;-----------------------------------------------------------------------------
; NAME: IMAGEPDS
; 
; PURPOSE: To read an image array into an array variable
;
; CALLING SEQUENCE: Result = IMAGEPDS (filename, label [,/SILENT, /NOSCALE]
; 
; INPUTS:
;     Filename: Scalar string containing the name of the PDS file to read
;     Label: String array containing the image header information
; OUTPUTS:
;     Result: 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)
;
; PROCEDURES USED:
;     Functions: APPLY_BITMASK, CLEAN, GET_INDEX, OBJPDS, PDSPAR,
;         POINTPDS, REMOVE_CHARS
; 
; MODIFICATION HISTORY:
;    Written by:     J. Koch       [Dec 01, 1994]
;                    Some sections adapted from READFITS.PRO by Wayne Landsman.
;    Re-written by:  P. Khetarpal  [Aug 01, 2004]
;    Last modified:  L. Nagdimunov [Jul 07, 2015]
;    
;    For a complete list of modifications, see changelog.txt file.
;
;-----------------------------------------------------------------------------

;- level 3 -------------------------------------------------------------------

;-----------------------------------------------------------------------------
; precondition: start and end index are viable indices for current
;     image; so is label; param is a PDS keyword name to be extracted
;     from label; required is a boolean describing whether the keyword
;     to be extracted is required for the image object or not.
; postcondition: the keyword for current image object is extracted and returned
  
function extract_image_keywords, start_ind, end_ind, label, param, required
    ; intialize variables:
    flag = 0      ; 1: found, 0: not found
    ; determine if param value is of type string or not:
    isstring = ((param eq "SAMPLE_TYPE") || $
               (strpos(param, "DISPLAY") gt -1)) ? 1 : 0  
    ; determine if param value if of type double or not:
    isfloat = ((param eq "OFFSET") || (param eq "SCALING_FACTOR")) ? 1 : 0

    ; first extract all param keywords value in the label:
    allvalues = pdspar(label, param, count=allcount, index=allindex)
    if (allcount gt 0) then begin
        ; extract all param value between start_ind and next object or
        ; end index:
        objects = pdspar(label, "OBJECT", count=objcount, index=objindex)
        pos = where (objindex gt start_ind, cnt)
        if (cnt gt 0) then begin
            greatind = objindex[pos[0]]
            ppos = where (allindex gt start_ind and allindex lt greatind, pcnt)
        endif else begin
            ppos = where(allindex gt start_ind and allindex lt end_ind, pcnt)
        endelse

        if (pcnt gt 0) then begin
            value = clean(allvalues[ppos[0]], /space)
            flag = 1
            
            ; convert into appropriate type:
            if (isstring) then begin
                par = ['"', "'", "(", ")", ","]
                value = remove_chars(value, par)
            endif else if (isfloat) then begin
                value = float(value)
            endif else begin
                value = long(value)
            endelse
        endif
    endif

    ; if not found then issue error:
    if (~flag) then begin
        if (required) then begin
            print, "Error: missing required " + param + " keyword from label"
        endif
        value = "-1"
    endif

    return, value
end

;-----------------------------------------------------------------------------
; precondition: value is an idl scalar obtained from the label for
;     current image object definition
; postcondition: the value is tested for whether it is of type string
;     or not

function is_string, value
    ; get size information of value:
    flag = (size(value, /type) eq 7) ? 1 : 0
    return, flag
end

;-----------------------------------------------------------------------------
; precondition: keywds contains all current image object definitions
; postcondition: all keyword values are tested for viability

function check_image_keywords, keywds, silent
    ; check line samples:
    if (keywds.line_samples eq 0) then begin
        print, "Error: LINE_SAMPLES keyword value is 0. No data in file."
        goto, endfunction
    endif else if (keywds.line_samples lt 0) then begin
        print, "Error: Invalid LINE_SAMPLES keyword value found: " + $
            clean(string(keywds.line_samples), /space)
        goto, endfunction
    endif  

    ; check lines:
    if (keywds.lines eq 0) then begin
        print, "Error: LINES keyword value is 0. No data in file."
        goto, endfunction
    endif else if (keywds.lines lt 0) then begin
        print, "Error: Invalid LINES keyword value found: " + $
            clean(string(keywds.lines), /space)
        goto, endfunction
    endif

    ; check sample bits:
    bitsrange = [8, 16, 32, 64]
    pos = where (keywds.bits eq bitsrange, cnt)
    if (cnt eq 0) then begin
        print, "Error: invalid SAMPLE_BITS keyword value found: " + $
            clean(string(keywds.bits), /space) 
        goto, endfunction
    endif

    ; check sample type:
    if (strlen(keywds.sample_type) eq 0) then begin
        print, "Error: null SAMPLE_TYPE keyword value found."
        goto, endfunction
    endif

    ; check sample display direction:
    if (keywds.sdd eq "-1") then begin
        if (~silent) then begin
          print, "Note: SAMPLE_DISPLAY_DIRECTION keyword not found..."
          print, "  assuming default value of RIGHT."
        endif
        keywds.sdd = "RIGHT"
    endif
    ddrange = ["UP", "DOWN", "LEFT", "RIGHT"]
    pos = where (keywds.sdd eq ddrange, cnt)
    if (cnt eq 0) then begin
        print, "Error: invalid SAMPLE_DISPLAY_DIRECTION keyword: " + keywds.sdd
        print, "  assuming default value of RIGHT."
        keywds.sdd = "RIGHT"
    endif

    ; check line display direction:
    if (keywds.ldd eq "-1") then begin
        if (~silent) then begin
          print, "Note: LINE_DISPLAY_DIRECTION keyword not found..."
          print, "  assuming default value of DOWN."
        endif
        keywds.ldd = "DOWN"
    endif
    pos = where (keywds.ldd eq ddrange, cnt)
    if (cnt eq 0) then begin
        print, "Error: invalid LINE_DISPLAY_DIRECTION keyword: " + keywds.ldd
        print, "  assuming default value of DOWN."
        keywds.ldd = "DOWN"
    endif

    return, keywds

    endfunction:
        keywds.flag = 0
        return, keywds
end

;-----------------------------------------------------------------------------
; precondition: start and end index are viable indices for current
;     image object, and wobjects contains all the window objects
;     in the label
; postcondition: all window subobjects for current image object are returned

function get_subwindows, start_ind, end_ind, wobjects
    ; initialize variable:
    struct = {flag: 0, count:0}
    windex = wobjects.index

    ; find whether there exist window subobjects for start index:
    pos = where (windex gt start_ind and windex lt end_ind, count)
    if (count gt 0) then begin
        struct.flag = 1
        struct.count = count
        array = wobjects.array[pos]
        index = wobjects.index[pos]
        struct = create_struct(struct, "array", array, "index", index)
    endif

    return, struct
end

;-----------------------------------------------------------------------------
; precondition: start and end index are viable indices for the current
;     subwindow object; so is label; element contains the current
;     image object array
; postcondition: the current window subobject parameters are obtained
;     from label and returned in a structure

function obtain_current_window_params, start_ind, end_ind, label, element
    ; initialize keyword structure variable:
    keywds = {flag: 1}
    
    ; get dimensions of element:
    dim = size(element, /dimensions)

    ; extract first line:
    first_line = extract_image_keywords(start_ind, end_ind, label, $
        "FIRST_LINE", 1)
    if (is_string(first_line)) then goto, endfunction

    ; check first line:
    if (first_line le 0 || first_line gt dim[1]) then begin
        print, "Error: FIRST_LINE keyword value exceeds image: " + $
            clean(string(first_line),/space)
        goto, endfunction
    endif

    ; extract first line sample:
    first_line_sample = extract_image_keywords(start_ind, end_ind, label, $
        "FIRST_LINE_SAMPLE", 1)
    if (is_string(first_line_sample)) then goto, endfunction

    ; check first line sample:
    if (first_line_sample le 0 || first_line_sample gt dim[0]) then begin
        print, "Error: FIRST_LINE_SAMPLE keyword value exceeds image: " + $
            clean(string(first_line), /space)
        goto, endfunction
    endif

    ; extract line samples:
    line_samples = extract_image_keywords(start_ind, end_ind, label, $ 
        "LINE_SAMPLES", 1)
    if (is_string(line_samples)) then goto, endfunction

    ; check line samples:
    if (line_samples eq 0) then begin
        print, "Error: LINE_SAMPLES keyword value is 0. No data in file."
        goto, endfunction
    endif else if (line_samples lt 0) then begin
        print, "Error: Invalid LINE_SAMPLES keyword value found: " + $
            clean(string(line_samples), /space)
        goto, endfunction
    endif  

    ; extract lines:
    lines = extract_image_keywords(start_ind, end_ind, label, "LINES", 1)
    if (is_string(lines)) then goto, endfunction

    ; check lines:
    if (lines eq 0) then begin
        print, "Error: LINES keyword value is 0. No data in file."
        goto, endfunction
    endif else if (lines lt 0) then begin
        print, "Error: Invalid LINES keyword value found: " + $
            clean(string(lines), /space)
        goto, endfunction
    endif

    keywds = create_struct(keywds, "first_line", first_line, $
        "first_line_sample", first_line_sample, "line_samples", line_samples, $
        "lines", lines)

    return, keywds
    endfunction:
        keywds.flag = 0
        return, keywds
end

;-----------------------------------------------------------------------------
; precondition: element is either a subwindow array or the image
;     array; keywds contains all current image object definitions.
; 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
        element = (ldd eq "UP") ? rotate(element, 0) : $
           (ldd eq "DOWN") ? rotate(element, 7) : -1 
    endif else if (sdd eq "LEFT") then begin
        element = (ldd eq "UP") ? rotate(element, 5) : $
           (ldd eq "DOWN") ? rotate(element, 2) : -1
    endif else if (sdd eq "UP") then begin
        element = (ldd eq "LEFT") ? rotate(element, 3) : $
           (ldd eq "RIGHT") ? rotate(elment, 4): -1
    endif else if (sdd eq "DOWN") then begin
        element = (ldd eq "LEFT") ? rotate(element, 6) : $
           (ldd eq "RIGHT") ? rotate(element, 1) : -1
    endif

    stat = size(element, /dimensions)
    if (stat[0] eq 0) then begin
        print, "Error: invalid LINE_DISPLAY_DIRECTION " + ldd + $
               " and SAMPLE_DISPLAY_DIRECTION " + sdd + " combination"
        return, saveelement
    endif

    return, element
end


;- level 2 -------------------------------------------------------------------

;-----------------------------------------------------------------------------
; precondition: start and end index are viable indices; so is label
; postcondition: all current image parameters are extracted from label

function obtain_current_image_params, start_ind, end_ind, label, silent
    ; initialize keyword structure variable:
    keywds = {flag:1}

    ; required keywords:
    ; line samples:
    line_samples = extract_image_keywords(start_ind, end_ind, label, $
        "LINE_SAMPLES", 1)
    if (is_string(line_samples)) then goto, endfunction

    ; lines:
    lines = extract_image_keywords(start_ind, end_ind, label, "LINES", 1)
    if (is_string(lines)) then goto, endfunction

    ; bits:
    bits = extract_image_keywords(start_ind, end_ind, label, "SAMPLE_BITS", 1)
    if (is_string(lines)) then goto, endfunction

    ; sample type:
    sample_type = extract_image_keywords(start_ind, end_ind, label, $ 
        "SAMPLE_TYPE", 1)

    if (sample_type eq "-1") then goto, endfunction

    ; optional keywords:
    ; sample display direction:
    samp_dis_dir = extract_image_keywords(start_ind, end_ind, label, $
        "SAMPLE_DISPLAY_DIRECTION", 0)
    
    ; line display direction:
    line_dis_dir = extract_image_keywords(start_ind, end_ind, label, $
        "LINE_DISPLAY_DIRECTION", 0)
     
    ; obtain line display direction and/or line display direction from main label if otherwise not found
    ; Added by L.Nagdimunov 07Jul2015   
    if (samp_dis_dir eq "-1") or (line_dis_dir eq "-1") then begin
      
      objects = get_all_objects(label)
      label_search = label
      
      for i=0, objects.count-1 do begin
        start_idx = objects.index[i]
        
        if (start_idx lt N_ELEMENTS(label_search)-1) then begin
          end_idx = get_index(label, start_idx)
          label_search[start_idx:end_idx] = ''
        endif
        
      endfor
      
      allvalues = pdspar(label_search, "SAMPLE_DISPLAY_DIRECTION", count=allcount)
      if (samp_dis_dir eq "-1") and (allcount eq 1) then begin
        samp_dis_dir = remove_chars(clean(allvalues[0], /space), '"')
        print, "Warning: SAMPLE_DISPLAY_DIRECTION keyword found outside of image object."
      endif
      
      allvalues = pdspar(label_search, "LINE_DISPLAY_DIRECTION", count=allcount)
      if (line_dis_dir eq "-1") and (allcount eq 1) then begin
        line_dis_dir = remove_chars(clean(allvalues[0], /space), '"')
        print, "Warning: LINE_DISPLAY_DIRECTION keyword found outside of image object."       
      endif
    endif

    ; offset:
    offset = extract_image_keywords(start_ind, end_ind, label, "OFFSET", 0)
    if (is_string(offset)) then offset = double(0.0)

    ; scaling factor:
    scaling_factor = extract_image_keywords(start_ind, end_ind, label, $
        "SCALING_FACTOR", 0)
    if (is_string(scaling_factor)) then scaling_factor = double(1.0)

    ; line prefix bytes:
    prefix_bytes = extract_image_keywords(start_ind, end_ind, label, $
        "LINE_PREFIX_BYTES", 0)
    if (is_string(prefix_bytes)) then prefix_bytes = long(0)

    ; line suffix bytes:
    suffix_bytes = extract_image_keywords(start_ind, end_ind, label, $
        "LINE_SUFFIX_BYTES", 0)
    if (is_string(suffix_bytes)) then suffix_bytes = long(0) 

    keywds = create_struct(keywds, "line_samples", line_samples, "lines", $
        lines, "bits", bits, "sample_type", sample_type, "sdd", samp_dis_dir, $
        "ldd", line_dis_dir, "offset", offset, "scaling_factor", $
        scaling_factor, "prefix_bytes", prefix_bytes, "suffix_bytes", $
        suffix_bytes)

    keywds = check_image_keywords(keywds,silent)

    return, keywds
    endfunction:
        keywds.flag = 0
        return, keywds
end

;-----------------------------------------------------------------------------
; precondition: sample type is a viable sample type keyword value for
;     current image object
; postcondition: the architecture for the data file is determined

function obtain_image_architecture, sample_type
    ; initialize architecture variable:
    arch = "MSB"

    ; obtain all types of keyword values from the label:
    if ((strpos(sample_type, "LSB") gt -1) || $
        (strpos(sample_type, "PC") gt -1) || $
        (strpos(sample_type, "VAX") gt -1)) then begin
        arch = "LSB"
    endif

    return, arch
end

;-----------------------------------------------------------------------------
; precondition: keywds is the idl structure definition for current
;     image object.
; postcondition: an idl structure is created to read the data from the
;     data file
 
function obtain_image_structure, keywds
    ; initialize structure:
    bits = keywds.bits   ; temporary store bits value
    type = keywds.sample_type ; temporary store sample_type value

    ; get the line sample vector for image:
    if (bits eq 8) then begin
        idl_type = 1
    endif else if (bits eq 16) then begin
        idl_type = (strpos(type, "UNSIGNED") gt -1) ? 12 : 2
    endif else if (bits eq 32) then begin
        if (strpos(type, "INTEGER") gt -1) then begin
            idl_type = (strpos(type, "UNSIGNED") gt -1) ? 13 : 3
        endif else begin
            idl_type = 4
        endelse
    endif else if (bits eq 64) then begin
        if (strpos(type, "INTEGER") gt -1) then begin
            idl_type = (strpos(type, "UNSIGNED") gt -1) ? 15 : 14
        endif else begin
            idl_type = 5
        endelse
    endif

    vector = make_array(keywds.line_samples, type = idl_type)

    ; construct the prefix byte structure:
    if (keywds.prefix_bytes gt 0) then begin
        struct = {prefix:bytarr(keywds.prefix_bytes), sample:vector}
    endif else begin
        struct = {sample:vector}
    endelse

    ; construct the suffix byte structure:
    if (keywds.suffix_bytes gt 0) then begin
        struct = create_struct(struct, "suffix", bytarr(keywds.suffix_bytes))
    endif

    ; now replicate the structure lines times:
    main = replicate(struct, keywds.lines)

    return, main
end

;-----------------------------------------------------------------------------
; precondition: pointer is an idl structure containing viable data
;     file name associated with current image object to be read, and
;     the number of bytes to skip if any; struct is the idl structure
;     to be read from the data file, and arch is the architecture of
;     the data file (LSB or MSB).
; postcondition: the data file is opened, the structure is read, and
;     returned

function read_image_data, pointer, struct, arch
    ; error protection:
    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 structure:
    readu, unit, struct

    ; close the unit and free the unit:
    close, unit
    free_lun, unit
    
    data_read = create_struct(data_read, "struct", struct)

    return, data_read

    signal:
        on_ioerror, null
        print, "Error: file either corrupted or invalid parameters specified"+$
               " in label."
        data_read.flag = 0
        close, unit
        free_lun, unit
        return, data_read
end

;-----------------------------------------------------------------------------
; precondition: current contains the raw image data for current image
;     object as read from the datafile; keywds contains all current
;     image object keyword values.
; postcondition: extracts the image array from the current structure,
;     converts the array values to signed integers if necessary, and
;     performs scaling and offset if noscale keyword is not supplied.

function convert_image_data, current, label, start_ind, end_ind,keywds, noscale
    ; extract image from the read data:
    element = current[*].sample

    ; convert data elements for signed bytarr objects
    ; (IDL only supports byte values of 0-255):
    pos = strpos(keywds.sample_type, "UNSIGNED")
    if ((keywds.bits eq 8) && (pos lt 0)) then begin
        element = fix(element)
        fixitlist = where (element gt 127, count)
        if (count gt 0) then begin
            element[fixitlist] = element[fixitlist] - 256
        endif
    endif  

    ; apply bit mask if applicable:
    element = apply_bitmask(label, start_ind, end_ind, element)

    ; process scaling factor and offset:
    if (~noscale) then begin
        if (keywds.scaling_factor ne 1.0) then begin
            element *= keywds.scaling_factor
        endif
        if (keywds.offset ne 0.0) then begin
            element += keywds.offset
        endif
    endif

    return, element
end

;-----------------------------------------------------------------------------
; precondition: start_ind and end_ind are viable start and end indices
;     of current image object; element contains the image array
;     information with the converted values, and bitmask applied;
;     wobjects and label are viable, and imgkeywds is an idl structure
;     containing current image object keyword values.
; postcondition: all window subobjects for the current image object,
;     if present, are processed and returned 

function process_windows, start_ind, end_ind, element, wobjects, label, $ 
  imgkeywds, silent
    ; initialize structure:
    windows_struct = {flag: 1}

    ; check existence of window subobjects and get their positions:
    subwindows = get_subwindows(start_ind, end_ind, wobjects)
    if (~subwindows.flag) then goto, endfunction
    count = subwindows.count
    array = subwindows.array
    index = subwindows.index

    ; intialize data structure for windows objects:
    if (count gt 1) then wdata = {windows: count}

    ; process each window subobject:
    for j = 0, count - 1 do begin
        ; set current and next window object pointer:
        cur_win = index[j]
        next_win = (j lt count - 1) ? index[j + 1] : end_ind

        ; obtain required keywords for current window object:
        keywds = obtain_current_window_params(cur_win, next_win, label,element)
        if (~keywds.flag) then goto, endfunction

        ; notify to user if not silent:
        if (~silent) then begin
            xtext = clean(string(keywds.line_samples), /space)
            ytext = clean(string(keywds.lines), /space)
            print, "  Now processing " + xtext + " by " + ytext + " window"
        endif

        ; extract the window vector from element:
        x1 = keywds.first_line_sample - 1     ; x - top left corner of window
        y1 = keywds.first_line - 1            ; y - top left corner of window
        x2 = x1 + keywds.line_samples - 1     ; x - bottom right corner
        y2 = y1 + keywds.lines - 1            ; y - bottom right corner 
        win_element = element(x1:x2, y1:y2)

        ; process display directions
        win_element = process_display_direction(win_element, imgkeywds)

        ; store the window vector into windows data structure:
        if (count gt 1) then begin
            name = array[j] + clean(string(j + 1), /space)
            wdata = create_struct(wdata, name, win_element)
        endif else begin
            wdata = create_struct("window", win_element)
        endelse
    endfor

    ; add entire image to window structure:
    element = process_display_direction(element, imgkeywds)
    wdata = create_struct(wdata, "image", element)
    windows_struct = create_struct(windows_struct, "wdata", wdata)

    return, windows_struct

    endfunction:
        windows_struct.flag = 0
        return, windows_struct
end 

;- level 1 -------------------------------------------------------------------

;-----------------------------------------------------------------------------
; precondition: filename and label are viable, and objects has at
;     least one image object structure, and wobjects definition is
;     obtained.
; spotcondition: all image objects are processed as defined in objects
;     and window structure.
 
function process_all_images, filename, label, objects, wobjects, silent,noscale
    ; initialize the image structure if more than one image:
    if (objects.count gt 1) then data = {images:objects.count}

    ; start the loop:
    for i = 0, objects.count - 1 do begin
        ; get current start and end index pointer:
        start_ind = objects.index[i]
        end_ind = get_index(label, start_ind)
        if (end_ind eq -1) then return, -1

        ; obtain current image object keyword values:
        keywds = obtain_current_image_params(start_ind, end_ind, label,silent)
        if (~keywds.flag) then return, -1  

        ; obtain file data architecture:
        arch = obtain_image_architecture(keywds.sample_type)

        ; obtain image structure:
        struct = obtain_image_structure(keywds)

        ; obtain pointer info:
        pointer = pointpds(label, filename, objects.array[i])
        if (pointer.flag eq "-1") then return, -1

        ; read data:
        if (~silent) then begin
            print, "Now reading " + clean(string(keywds.line_samples),/space) $
                + " by " + clean(string(keywds.lines),/space) + " image"
        endif
        data_read = read_image_data(pointer, struct, arch)        
        if (~data_read.flag) then return, -1
        current = data_read.struct

        ; perform data conversion if needed:
        element = convert_image_data(current, label, start_ind, end_ind, $
            keywds, noscale)

        ; process window sub objects:
        windows = process_windows(start_ind, end_ind, element, wobjects, $
             label, keywds, silent)

        ; save image and windows structure if applicable:
        if (windows.flag) then begin
            data = (objects.count gt 1) ? create_struct(data, $
                objects.array[i], windows.wdata) : windows.wdata
        endif else begin
            element = process_display_direction(element, keywds)
            data = (objects.count gt 1) ? create_struct(data, $
                objects.array[i], element) : element
        endelse

    endfor

    return, data
end

;- level 0 -------------------------------------------------------------------

;-----------------------------------------------------------------------------
; precondition: filename is a viable pds label file name, and label is
;     a viable pds label.
; postcondition: all image objects defined in label are read from
;     associated data file and returned.
 
function imagepds, filename, label, SILENT = silent, NOSCALE = noscale
    ; error protection:
    on_error, 2
    on_ioerror, signal

    ; check for the number of parameters in function call:
    if (n_params() lt 2) then begin
        print, "Syntax Error: result = IMAGEPDS (filename, label [, /SILENT" +$
               ", /NOSCALE])"
        return, -1
    endif
    silent = keyword_set(SILENT)
    noscale = keyword_set(NOSCALE)

    ; obtain all image and window objects from label:
    objects = objpds (label, "IMAGE")
    if (objects.flag eq -1) then begin
        print, "Error: no IMAGE object found in label"
        return, -1
    endif
    wobjects = objpds(label, "WINDOW")

    ; process all image and window objects:
    data = process_all_images(filename,label,objects,wobjects,silent,noscale)

    return, data

    signal:
        on_ioerror, null
        print, "Error reading file"
        return, -1
end