;;----------------------------------------------------------------------------- ;; Name: IMAGEPDS ;; ;; Purpose: To read a PDS IMAGE object into IDL array ;; ;; Calling Sequence: ;; result = imagepds (filename, label, index [, /SILENT, /NOSCALE]) ;; ;; Input: ;; filename - scalar string containing the name of the PDS file to read ;; label - string array containing the image header information ;; index - an integer giving the index of label array where the ;; start of the IMAGE object ;; ;; Output: ;; result - an image array constructed from designated record ;; ;; Optional input: ;; SILENT - suppresses any messages from the procedure ;; NOSCALE - does not perform scaling and offset of values, default ;; is to scale and offset. ;; ;; Examples: ;; To read an image file IMAGE.LBL into an array, img: ;; IDL> label = headpds ("IMAGE.LBL", /SILENT) ;; IDL> img = imagepds ("IMAGE.LBL", label, /SILENT) ;; To read an image file IMAGEWIN.LBL with a window object into img: ;; IDL> label = headpds ("IMAGEWIN.LBL", /SILENT) ;; IDL> img = imagepds ("IMAGEWIN.LBL", /SILENT) ;; ;; External routines: Verify_label, Get_index, Pointpds, Extract_keyword, ;; Clean, Remove, Apply_bitmask, Get_idl_type ;; ;; Modification history: ;; Adapted by John D. Koch from READFITS by Wayne Landsman, ;; December, 1994 ;; ;; Re-written by: Puneet Khetarpal [June 30, 2005] ;; For a complete list of modifications, see changelog.txt file. ;; ;;----------------------------------------------------------------------------- ;- level 2 ------------------------------------------------------------------- ; precondition: the index and endindex are start and end indices of current ; image element and label is a viable pds label ; postcondition: the windows subobjects for current image are returned function get_subwindows, index, endindex, label ; first extract all window subobjects from label all_win = objpds(label, 'WINDOW') if (all_win.count eq 0) then return, all_win ; if none found, then return ; else continue extracting sub objects pos = where (all_win.index gt index and all_win.index lt endindex, cnt) if (cnt eq 0) then return, all_win ; if no subwindows found, then return ; else extract values and return struct = {array:all_win.array[pos], index:all_win.index[pos], count:cnt} return, struct end ; precondition: element is either a wubwindow array or the image array; ; structure passed contains ldd and sdd values ; postcondition: the element array is rotated depending upon the ; values of line and sample display direction keyword values function process_display_direction, element, keywds ; local variables ldd = keywds.ldd sdd = keywds.sdd saveelement = element ; process display direction if (sdd eq "RIGHT") then begin ; if sdd is "RIGHT" element = (ldd eq "UP") ? rotate(element, 0) : $ (ldd eq "DOWN") ? rotate(element, 7) : -1 endif else if (sdd eq "LEFT") then begin ; if sdd is "LEFT" element = (ldd eq "UP") ? rotate(element, 5) : $ (ldd eq "DOWN") ? rotate(element, 2) : -1 endif else if (sdd eq "UP") then begin ; if sdd is "UP" element = (ldd eq "LEFT") ? rotate(element, 3) : $ (ldd eq "RIGHT") ? rotate(element, 4): -1 endif else if (sdd eq "DOWN") then begin ; if sdd is "DOWN" element = (ldd eq "LEFT") ? rotate(element, 6) : $ (ldd eq "RIGHT") ? rotate(element, 1) : -1 endif ; check whether element was rotated properly stat = size(element, /dimensions) ; if invalid combination supplied if (stat[0] eq 0) then begin ; then dimension of element is 0 print, "Error: invalid LINE_DISPLAY_DIRECTION " + ldd + $ " and SAMPLE_DISPLAY_DIRECTION " + sdd + " combination" return, saveelement endif return, element end ;- level 1 ------------------------------------------------------------------- ; precondition: the label has been verified and index is a viable ; index for IMAGE object ; postcondition: the required keywords are extracted and returned as a struct function obtain_image_required, label, index, endindex ; extract lines keyword lines = extract_keyword(label, 'LINES', index, endindex, 1, 1) ; extract line samples keyword line_samples = extract_keyword(label,'LINE_SAMPLES', index, endindex, 1, 1) ; extract sample bits keyword sample_bits = extract_keyword(label, 'SAMPLE_BITS', index, endindex, 1) ; extract sample type keyword sample_type = extract_keyword(label, 'SAMPLE_TYPE', index, endindex, 1) sample_type = remove(sample_type, '"') ; store values in a structure struct = {lines:long(lines), line_samples:long(line_samples), $ sample_bits:long(sample_bits), sample_type:sample_type} return, struct end ; precondition: all required keywords have been extracted ; postcondition: the optional keyword values are extracted function obtain_image_optional, label, index, endindex ; extract line prefix bytes keyword line_prefix = extract_keyword(label, 'LINE_PREFIX_BYTES', index,endindex,0) line_prefix = (line_prefix eq '###~') ? 0 : long(line_prefix) ; extract line suffix bytes keyword line_suffix = extract_keyword(label, 'LINE_SUFFIX_BYTES', index,endindex,0) line_suffix = (line_suffix eq '###~') ? 0 : long(line_suffix) ; extract offset keyword offset = extract_keyword(label, 'OFFSET', index, endindex, 0) offset = (offset eq '###~') ? 0.0 : float(offset) ; extract scaling factor keyword scaling_factor = extract_keyword(label, 'SCALING_FACTOR', index,endindex,0) scaling_factor = (scaling_factor eq '###~') ? 1.0 : float(scaling_factor) ; extract bit mask keyword bit_mask = extract_keyword(label, 'BIT_MASK', index, endindex, 0) bit_mask = (bit_mask eq '###~') ? '0' : bit_mask ; extract line display direction keyword ldd = extract_keyword(label, 'LINE_DISPLAY_DIRECTION', index, endindex, 0) ldd = (ldd eq '###~') ? 'DOWN' : remove(ldd, '"') ; extract sample display direction keyword sdd = extract_keyword(label, 'SAMPLE_DISPLAY_DIRECTION',index, endindex, 0) sdd = (sdd eq '###~') ? 'RIGHT' : remove(sdd, '"') ; place in structure struct = {line_prefix:line_prefix, line_suffix:line_suffix, offset:offset,$ scaling_factor:scaling_factor, bit_mask:bit_mask,ldd:ldd,sdd:sdd} return, struct end ; precondition: all required and optional keywords have been extracted ; from label ; postcondition: the image structure is compiled and returned function obtain_image_structure, required, optional ; local variables bits = required.sample_bits type = required.sample_type prefix = optional.line_prefix suffix = optional.line_suffix bytes = bits / 8 ; store number of bytes for each sample ; get the line sample vector for image by identifying IDL type idl_type = get_idl_type(type, bytes, 'BINARY') ; declare the vector variable vector = make_array(required.line_samples, type = idl_type) ; compile prefix bytes component of structure struct = (prefix gt 0) ? {pre:bytarr(prefix),samp:vector} : {samp:vector} ; compile suffix bytes component of structure if (suffix gt 0) then begin struct = create_struct(struct, "suffix", bytarr(suffix)) endif ; replicate structure struct = replicate(struct, required.lines) return, struct end ; precondition: the pointer information is obtained, structure has ; been compiled to be read, the architecture of the data is known ; postcondition: pointer information is used to read the data, the ; data architecture is converted to the appropriate type for reading function read_image_data, pointer, struct, arch ; error checking on_ioerror, signal ; initialize variable and declare flag data_read = {flag:1} ; 0: error, 1: no error ; open the file to be read and apply swap endian if needed if (arch eq 'MSB') then begin openr, unit, pointer.datafile, /get_lun, /swap_if_little_endian endif else begin openr, unit, pointer.datafile, /get_lun, /swap_if_big_endian endelse ; set the file pointer to current object to be read point_lun, unit, pointer.skip ; read the image object into the structure readu, unit, struct ; close the unit and free it close, unit free_lun, unit ; add to structure data_read = create_struct(data_read, 'struct', struct) ; return return, data_read signal: on_ioerror, null print, "Error: file either corrupted or invalid parameters specified" data_read.flag = 0 return, data_read end ; precondition: the data has been read, and the required and optional keywords ; are present, along with the noscale keyword ; postcondition: the data conversion is performed if needed. function convert_image_data, current, required, optional, noscale ; extract image from the read data element = current[*].samp ; convert data elements for signed bytarr bojects ; (IDL only supports unsigned byte values of 0 - 255) if ((required.sample_bits eq 8) && (~ stregex(required.sample_type, $ 'UNSIGNED', /boolean))) then begin element = fix(element) ; set to integer fixitlist = where(element gt 127, count) ; check where gt 127 if (count gt 0) then begin ; if > 127 found, then element[fixitlist] -= 256 ; subtract 256 endif endif ; if bit mask available then apply it if (optional.bit_mask ne '0') then begin element = apply_bitmask(element, optional.bit_mask) ; external routine endif ; process scaling factor and offset if (~ noscale) then begin element *= optional.scaling_factor ; apply scaling factor element += optional.offset ; apply offset endif return, element end ; precondition: the image data has been read from file and appropriate ; conversions to the data have been performed; the tempstruct is a ; structure containing the label, index, endindex, required and ; optional keywords structures, and the value of silent keyword ; postcondition: the windows subobjects (if any) are extracted from image ; and returned in a structure function process_windows, struct ;; first extract any windows sub objects names, indices and total number winobjects = get_subwindows(struct.index, struct.endindex, struct.label) ;; if no window sub objects found, then return windows = {flag:0} if (winobjects.count eq 0) then return, windows win_index = winobjects.index ; store indices win_count = winobjects.count ; store count label = struct.label ; store label variable windows.flag++ ; increment windows flag ; initialize windows data array wdata = {windows:win_count} ; loop through each window object and process it for j = 0, win_count - 1 do begin win_end = get_index(struct.label, win_index[j]) ; get endindex ; get required keywords LINES, LINE_SAMPLES, FIRST_LINE/_SAMPLE lines = extract_keyword(label, 'LINES', win_index[j], win_end,1) line_samples = extract_keyword(label, 'LINE_SAMPLES', win_index[j], $ win_end, 1) first_line = extract_keyword(label, 'FIRST_LINE', win_index[j], $ win_end, 1) first_lnsmp = extract_keyword(label, 'FIRST_LINE_SAMPLE', $ win_index[j], win_end, 1) ; if not silent then notify user of status if (~ struct.silent) then begin print, " Now processing " + line_samples + " by " +lines+" window" endif ;; define start and end vector indices for window in element x1 = long(first_lnsmp) - 1 ; x: top left corner of window y1 = long(first_line) - 1 ; y: top left corner of window x2 = x1 + long(line_samples) - 1 ; x: bottom right corner y2 = y1 + long(lines) - 1 ; y: bottom right corner ; extract window from element win_element = struct.element[x1:x2, y1:y2] ; process display direction win_element = process_display_direction(win_element, struct.optional) ; store window element into windows data structure name = winobjects.array[j] + clean(string(j+1), /space) wdata = create_struct(wdata, name, win_element) endfor ; add entire image to window structure struct.element = process_display_direction(struct.element, struct.optional) wdata = create_struct(wdata, 'image', struct.element) windows = create_struct(windows, 'wdata', wdata) return, windows end ;- level 0 ------------------------------------------------------------------- function imagepds, filename, label, index, SILENT = silent, NOSCALE = noscale ; error check on_error, 1 ; check for the number of parameters in function call if (n_params() lt 3) then begin message, "Syntax Error: img = IMAGEPDS(filename, label [,/SILENT, "+$ "/NOSCALE])" endif silent = keyword_set(silent) noscale = keyword_set(noscale) ; verify label res = verify_label(label, filename) ; check current image object index if (~ stregex(label[index], 'IMAGE', /boolean)) then begin print, "Error: Invalid index specified for IMAGE object "+string(index) return, 0 endif ; get endindex value for current image object endindex = get_index(label, index) ; obtain all required image keywords required = obtain_image_required(label, index, endindex) ; obtain all optional image keywords optional = obtain_image_optional(label, index, endindex) ; obtain image architecture arch = (stregex(required.sample_type, '(LSB)|(VAX)|(PC)', /boolean)) ? $ 'LSB' : 'MSB' ; obtain image structure to be read from file struct = obtain_image_structure(required, optional) ; obtain object name from current index name = stregex(label[index], '= +([0-9A-Z_]+)', /extract, /subexpr) ; obtain pointer information pointer = pointpds(label, filename, name[1]) ; if not silent then inform user if (~ silent) then begin print, "Now reading " + clean(string(required.line_samples), /space) +$ " by " + clean(string(required.lines), /space) + " image" endif ; read data from file data_read = read_image_data(pointer, struct, arch) if (~ data_read.flag) then return, 0 ; perform data conversion if necessary element = convert_image_data(data_read.struct, required, optional, noscale) ; process window sub objects if any tempstruct = {label:label, index:index, endindex:endindex,element:element,$ required:required, optional:optional, silent:silent} windows = process_windows(tempstruct) ; save image and windows structure if (windows.flag) then begin ; if windows present data = windows.wdata ; then store windows data endif else begin ; else process display direction data = process_display_direction(element, optional) endelse return, data end