Viewing contents of file '../idllib/contrib/fanning/getimage.pro'
;+
; NAME:
; GETIMAGE
;
; PURPOSE:
; The purpose of this function is to allow the user to open either
; regular or XDR binary image files of two or three dimensions.
;
; CATEGORY:
; Widgets, File I/O.
;
; CALLING SEQUENCE:
; image = GETIMAGE(filename)
;
; INPUTS:
; filename: The name of the file to open for reading.
;
; KEYWORD PARAMETERS:
;
; CANCEL: An output variable that can be set to a named variable.
; The value of the return variable will be 1 if the user clicked
; the "Cancel" button or if there was a problem reading the file.
;
; DIRECTORY: The name of the directory the file is located in. By
; default the program looks in the "training" directory under the
; main IDL directory, if one exists. Otherwise, it defaults to the
; current directory.
;
; FRAMES: The 3rd dimension of a 3D data set. Defaults to 0.
;
; HEADER: The size of any header information in the file in BYTES.
; Default is 0.
;
; PARENT: The group leader for this widget program. The PARENT is
; required if GETIMAGE is called from another widget program.
;
; XDR: Set this keyword if the binary file is of XDR type.
;
; XOFFSET: This is the X offset of the program on the display. The
; program will be placed approximately in the middle of the display
; by default.
;
; XSIZE: The size of the 1st dimension of the data.
;
; YOFFSET: This is the Y offset of the program on the display. The
; program will be placed approximately in the middle of the display
; by default.
;
; YSIZE: The size of the 2nd dimension of the data.
;
; COMMON BLOCKS:
; None.
;
; SIDE EFFECTS:
; A "CANCEL" operation is indicated by a 0 return value.
; Any error in reading the file results in a 0 return value.
;
; RESTRICTIONS:
; None.
;
; EXAMPLE:
; To load the image "galaxy.dat" in the $IDL/examples/data
; directory, type:
;
; image = GETIMAGE('galaxy.dat', DIRECTORY=!DIR + '/examples/data', $
; XSIZE=256, YSIZE=256, Cancel=cancelled, Parent=event.top)
; IF NOT cancelled THEN TV, image
;
; MODIFICATION HISTORY:
; Written by: David Fanning, 3 February 96.
; Fixed bug that prevented reading INTEGER data. 19 Dec 96.
; Modifed program for IDL 5 MODAL operation. 19 Oct 97.
; Added CANCEL keyword. 27 Oct 97. DWF.
; Fixed CANCLE keyword spelling. Sigh... 29 JUN 98. DWF.
;-
PRO GETIMAGE_INTEGER_ONLY, event
; This event handler for text widgets only allows integers to be entered
; in the text widget. A maximum of four digits are allowed.
; Deal with simple one-character insertion events.
IF event.type EQ 0 THEN BEGIN
; Get the current text in the widget and find its length.
Widget_Control, event.id, Get_Value=text
text = text(0)
length = StrLen(text)
; Only react if the insertion character is a number and there
; are less than four characters already in the widget.
IF Byte(event.ch) GE 48B AND Byte(event.ch) LE 57B $
AND length LT 4 THEN BEGIN
; Get the current text selection.
selection = Widget_Info(event.id, /Text_Select)
; Insert the character at the proper location.
Widget_Control, event.id, /Use_Text_Select, Set_Value=String(event.ch)
; Update the current insertion point in the text widget.
Widget_Control, event.id, Set_Text_Select=event.offset + 1
ENDIF
ENDIF ; of insertion event
; Deal with deletion events.
IF event.type EQ 2 THEN BEGIN
; Get the current text in widget.
Widget_Control, event.id, Get_Value=text
text = text(0)
length = StrLen(text)
; Put it back with the deletion subtracted.
Widget_Control, event.id, Set_Value=StrMid(text, 0, length-event.length)
; Reset the text insertion point in the text widget.
Widget_Control, event.id, Set_Text_Select=event.offset
ENDIF
END ;-------------------------------------------------------------------------
PRO GETIMAGE_NULL_EVENTS, event
; The purpose of this event handler is to do nothing
;and ignore all events that come to it.
END ;-------------------------------------------------------------------------
FUNCTION GETIMAGE_FIND_COYOTE
; The purpose of this function is to find the "coyote"
; training directory and return its path. If no
; directory is found, the function returns a null string.
ON_ERROR, 1
; Check this directory first.
CD, Current=thisDir
IF STRPOS(STRUPCASE(thisDir), 'COYOTE') GT 0 THEN RETURN, thisDir
; Look in !Path directories.
pathDir = EXPAND_PATH(!Path, /Array)
s = SIZE(pathDir)
IF s(1) LT 1 THEN RETURN, ''
FOR j=0,s(1)-1 DO BEGIN
check = STRPOS(STRUPCASE(pathDir(j)), 'COYOTE')
IF check GT 0 THEN RETURN, pathDir(j)
ENDFOR
RETURN, ''
END ;-------------------------------------------------------------------------
PRO GETIMAGE_EVENT, event
; The only events that can come here are button events.
; Get the info structure out of the user value of the top-level base.
Widget_Control, event.top, Get_UValue=info
; There may be errors we can't anticipate. Catch them here, alert the
; user as to what the error was, and exit the event handler without
; doing any damage.
Catch, error
IF error NE 0 THEN BEGIN
ok = Widget_Message(!Err_String)
formdata = {cancel:1}
*info.ptrToFormData =formdata
Widget_Control, event.top, /Destroy
RETURN
ENDIF
; Which button caused this event?
Widget_Control, event.id, Get_Value=buttonValue
CASE buttonValue OF
'Pick Filename': BEGIN
; Start in the directory listed in the directory text widget.
; Convert the text value to a scalar.
Widget_Control, info.dirnameID, Get_Value=startDirectory
startDirectory = startDirectory(0)
; If this directory doesn't exist, use the current directory.
test = Findfile(startDirectory, Count=foundfile)
IF foundfile NE 1 THEN CD, Current=startDirectory
; Use PICKFILE to pick a name.
pick = Pickfile(Path=startDirectory, /NoConfirm, $
Get_Path=path, Filter='*.')
; Set the directory text widget with the name of the directory.
; Make sure the user didn't cancel out of PICKFILE.
IF pick NE '' THEN BEGIN
; Find the lengths of the PICK and the PATH.
pathLen = StrLen(path)
picklen = StrLen(pick)
; Shorten the PATH to take off last file separator.
path = StrMid(path,0,pathLen-1)
; Put the PATH in the directory location.
Widget_Control, info.dirnameID, Set_Value=path
; Set the filename text widget with the name of the file.
filename = StrMid(pick, pathlen, picklen-pathlen)
Widget_Control, info.filenameID, Set_Value=filename
ENDIF
END ; of the Pick Filename button case
'Cancel': BEGIN
; Have to exit here gracefully. Set the "CANCEL" flag.
formdata = {cancel:1}
*info.ptrToFormData =formdata
; Out of here!
Widget_Control, event.top, /Destroy
END ; of the Cancel button case
'Accept': BEGIN ; Gather the form information.
; Put the directory and filename together to make a path.
Widget_Control, info.dirnameID, Get_Value=directory
Widget_Control, info.filenameID, Get_Value=file
filename = Filepath(Root_Dir=directory(0),file(0))
; Get the size and header info. Remember these are STRINGS!
Widget_Control, info.headerID, Get_Value=header
Widget_Control, info.xsizeID, Get_Value=xsize
Widget_Control, info.ysizeID, Get_Value=ysize
Widget_Control, info.frameID, Get_Value=frames
header = Fix(header(0))
xsize = Fix(xsize(0))
ysize = Fix(ysize(0))
frames = Fix(frames(0))
; Get the data type from the droplist widget.
listIndex = Widget_Info(info.droplistID, /Droplist_Select)
datatype = info.datatypes(listIndex)
; Get the format index from the formatlist widget.
formatIndex = Widget_Info(info.formatlistID, /Droplist_Select)
; Create the formdata structure from the information you collected.
formdata = {header:header, xsize:xsize, ysize:ysize, frames:frames, $
filename:filename, datatype:datatype, formatIndex:formatIndex, cancel:0}
; Store the formdata in the pointer location.
*info.ptrToFormData = formdata
; Out of here!
Widget_Control, event.top, /Destroy
END ; of the Accept button case
ENDCASE
END ; of GETIMAGE_EVENT event handler ***************************************
FUNCTION GETIMAGE, filename, Directory=directory, XSize=xsize, YSize=ysize, $
Frames=frames, Header=header, Parent=parent, XDR=xdr, XOffSet=xoffset, $
YOffSet=yoffset, Cancel=canceled
; This is a function to specify the size, data type, and header information
; about an image that you would like to read. It reads the data and returns
; it as the result of the function. If an error occurs or the user CANCELS,
; the function returns a 0.
; Must have IDL 5 because of pointers and other functionality.
thisRelease = StrMid(!Version.Release, 0, 1)
IF thisRelease NE '5' THEN BEGIN
ok = Widget_Message('This program requires IDL 5 functionality. Sorry.')
RETURN, 0
ENDIF
; Check for parameters and keywords.
IF N_Params() EQ 0 THEN filename='ctscan.dat'
; If DIRECTORY keyword is not used, use the "coyote" directory.
; If that is not found, use the current directory.
IF N_Elements(directory) EQ 0 THEN BEGIN
startDirectory = GetImage_Find_Coyote()
IF startDirectory EQ '' THEN CD, Current=startDirectory
ENDIF ELSE startDirectory = directory
; If the default file is not in the directory, make the filename
; a null string.
thisFile = Filepath(Root_Dir=startDirectory, filename)
ok = Findfile(thisFile, Count=count)
IF count EQ 0 THEN filename = ''
; Check for size and header keywords. These probably come in as
; numbers and you need strings to put them into text widgets.
IF N_Elements(xsize) EQ 0 THEN xsize='256' ELSE xsize=StrTrim(xsize,2)
IF N_Elements(ysize) EQ 0 THEN ysize='256' ELSE ysize=StrTrim(ysize,2)
IF N_Elements(frames) EQ 0 THEN frames='0' ELSE frames=StrTrim(frames,2)
IF N_Elements(header) EQ 0 THEN header='0' ELSE header=StrTrim(header,2)
; Find the center of the display.
Device, Get_Screen_Size=screenSize
xCenter = Fix(screenSize(0) / 2.0)
yCenter = Fix(screenSize(1) / 2.0)
IF N_Elements(xoffset) EQ 0 THEN xoffset = xCenter - 275
IF N_Elements(yoffset) EQ 0 THEN yoffset = yCenter - 150
; Create a modal top-level base if PARENT is present.
IF N_Elements(parent) EQ 0 THEN $
tlb = Widget_Base(Column=1, Title='Read Image Data', XOffSet=xoffset, $
YOffSet=yoffset) ELSE $
tlb = Widget_Base(Column=1, Title='Read Image Data', XOffSet=xoffset, $
YOffSet=yoffset, Modal=1, Group_Leader=parent)
; Create the directory widgets.
dirnamebase = Widget_Base(tlb, Row=1)
dirnamelabel = Widget_Label(dirnamebase, Value='Directory:')
dirnameID = Widget_Text(dirnamebase, Value=startDirectory, /Editable, $
Event_Pro='GETIMAGE_NULL_EVENTS', XSize=Fix(2.0*StrLen(startDirectory) > 50))
; Create the filename widgets.
filenamebase = Widget_Base(tlb, Row=1)
filenamelabel = Widget_Label(filenamebase, Value='Filename:')
filenameID = Widget_Text(filenamebase, Value=filename, /Editable, $
Event_Pro='GETIMAGE_NULL_EVENTS', XSize=2*StrLen(filename) > 20)
; Create a button to allow user to pick a filename.
pickbutton = Widget_Button(filenamebase, Value='Pick Filename')
; Create a droplist widget to select file data types.
database = Widget_Base(tlb, Row=1)
datatypes = ['Byte', 'Integer', 'Long', 'Float']
droplistID = Widget_Droplist(database, Value=datatypes, $
Title='Data Type: ', Event_Pro='GETIMAGE_NULL_EVENTS')
; Create a droplist widget to select file formats.
formatlistID = Widget_Droplist(database, Value=['None', 'XDR'], $
Title='File Format: ', Event_Pro='GETIMAGE_NULL_EVENTS')
; Create a text widget to accept a header size.
headlabel = Widget_Label(database, Value='Header Size:')
headerID = Widget_Text(database, Value=header, All_Events=1, Editable=0, $
Event_Pro='GETIMAGE_INTEGER_ONLY', XSize=8)
; Create widgets to gather the required file sizes.
sizebase = Widget_Base(tlb, Row=1)
xlabel = Widget_Label(sizebase, Value='X Size:')
xsizeID = Widget_Text(sizebase, Value=xsize, All_Events=1, Editable=0, $
Event_Pro='GETIMAGE_INTEGER_ONLY', XSize=8)
ylabel = Widget_Label(sizebase, Value='Y Size:')
ysizeID = Widget_Text(sizebase, Value=ysize, All_Events=1, Editable=0, $
Event_Pro='GETIMAGE_INTEGER_ONLY', XSize=8)
zlabel = Widget_Label(sizebase, Value='Frames:')
frameID = Widget_Text(sizebase, Value=frames, All_Events=1, Editable=0, $
Event_Pro='GETIMAGE_INTEGER_ONLY', XSize=8)
; Create cancel and accept buttons.
cancelbase = Widget_Base(tlb, Column=2, Frame=1)
cancel = Widget_Button(cancelbase, Value='Cancel')
accept = Widget_Button(cancelbase, Value='Accept')
; Realize the program.
Widget_Control, tlb, /Realize
; Create a pointer to store the information collected from the form.
ptrToFormData = Ptr_New({cancel:1})
; Set the correct file format in the format droplist widget.
Widget_Control, formatlistID, Set_Droplist_Select=Keyword_Set(xdr)
; Set the text insertion point at the end of the filename text widget.
tip = [StrLen(filename),0]
Widget_Control, filenameID, Input_Focus=1
Widget_Control, filenameID, Set_Text_Select=tip
; Create an info structure with program information.
info = { filenameID:filenameID, $
dirnameID:dirnameID, $
xsizeID:xsizeID, $
ysizeID:ysizeID, $
frameID:frameID, $
headerID:headerID, $
droplistID:droplistID, $
formatlistID:formatlistID, $
datatypes:datatypes, $
ptrToFormData:ptrToFormData}
; Store the info structure in the user value of the top-level base.
Widget_Control, tlb, Set_UValue=info
; The form will be a MODAL or BLOCKING widget, depending upon the
; presence of the PARENT.
XManager, 'getimage', tlb, Event_Handler='GETIMAGE_EVENT'
; Get the form data that was collected by the form.
formdata = *ptrToFormData
; If there is nothing here. Free the pointer and return.
IF N_Elements(formdata) EQ 0 THEN BEGIN
Ptr_Free, ptrToFormData
canceled = 1
RETURN, 0
ENDIF
; Did the user cancel out of the form? If so, return a 0.
IF formdata.cancel EQ 1 THEN BEGIN
Ptr_Free, ptrToFormData
canceled = 1
RETURN, 0
ENDIF
; Make the proper sized image array. Check for success.
image = 0
IF STRUPCASE(formdata.datatype) EQ 'INTEGER' THEN formdata.datatype = 'INT'
IF formdata.frames EQ 0 THEN $
command = 'image = Make_Array(formdata.xsize, formdata.ysize, ' + $
formdata.datatype + '=1)' ELSE $
command = 'image = Make_Array(formdata.xsize, ' + $
'formdata.ysize, formdata.frames, ' + formdata.datatype + '=1)'
check = Execute(command)
IF check EQ 0 THEN BEGIN
ok = Widget_Message("Problem making image array. Returning 0.")
canceled = 1
RETURN, 0
ENDIF
; We can have all kinds of trouble reading data. Let's catch all
; input and output errors and alert user without crashing the program!
Catch, error
IF error NE 0 THEN BEGIN
; If we can't read the file for some reason, let the user know
; why, free the pointer and its information, check the logical
; unit number back in if it is checked out, and return a 0.
ok = Dialog_Message(!Err_String)
Ptr_Free, ptrToFormData
canceled = 1
IF N_ELements(lun) NE 0 THEN Free_Lun, lun
RETURN, 0
ENDIF
; Set the canceled flag.
canceled = formdata.cancel
; Read the data file.
IF formdata.header GT 0 THEN header = BytArr(formdata.header)
Get_Lun, lun
OpenR, lun, formdata.filename, XDR=formdata.formatIndex
IF formdata.header EQ 0 THEN ReadU, lun, image $
ELSE ReadU, lun, header, image
Free_Lun, lun
; Free the pointer.
Ptr_Free, ptrToFormData
RETURN, image
END ; of GETIMAGE program ***************************************************