;+ ; NAME: ; IMAGESELECT ; ; PURPOSE: ; ; The purpose of this program is to allow the user to select a formatted ; image file for reading. The image data is returned as the result of the ; function. The program allows the user to see a thumbnail version of the ; image, along with information about the image, before selection. The ; program uses the file extention to determine what kind of image is to ; be read. The following image types are supported: ; ; TYPE FILE EXTENSION ; BMP *.bmp ; DICOM *.dcm ; FITS *.fits, *.fts (requires NASA ASTRO library on IDL Path) ; GIF *.gif (IDL 6.2 and higher) ; JPEG *.jpg, *.jpeg, *.jpe ; JPEG2000 *.jpf, *.jpx, *.jp2, *.j2c, *.j2k ; PICT *.pict ; PNG *.png ; TIFF *.tif, *tiff ; ; AUTHOR: ; ; FANNING SOFTWARE CONSULTING ; David Fanning, Ph.D. ; 1645 Sheely Drive ; Fort Collins, CO 80526 USA ; Phone: 970-221-0438 ; E-mail: david@idlcoyote.com ; Coyote's Guide to IDL Programming: http://www.idlcoyote.com/ ; ; CATEGORY: ; ; General programming. ; ; CALLING SEQUENCE: ; ; image = ImageSelect() ; ; INPUT PARAMETERS: ; ; None. All input is via keywords. ; ; INPUT KEYWORDS: ; ; BMP -- Set this keyword to select BMP files. ; ; DEMO -- If this keyword is set, the program changes directory to !DIR/examples/data. ; ; DICOM -- Set this keyword to select DICOM files. ; ; DIRECTORY -- The initial input directory name. The current directory by default. ; ; EXCLUDE -- A list of filenames that should excluded from the file selection list. ; ; FILENAME -- The initial filename. If the initial directory has image files of the ; correct type, the default is to display the first of these files. Otherwise, blank. ; ; FILTER -- A string, representing the file filter. For example, '*.jpg'. ; ; FITS -- Set the keyword to select FITS files. (Must have NASA Astro Library on path.) ; ; FLIPIMAGE -- Set this keyword if you wish to flip the image from its current orientation. Setting ; this keyword reverses the Y dimension of the image. ; ; GIF -- Set this keyword to select GIF files. (IDL versions before 5.4 and after 6.0, only.) ; ; GROUP_LEADER -- Set this keyword to a widget identifier group leader. This keyword MUST be ; set when calling this program from another widget program to guarantee modal operation. ; ; J2000 -- Set this keyword to select JPEG2000 files. (May also be set as J2K.) (IDL 6.1 or above.) ; ; J2K -- Set this keyword to select JPEG2000 files. (May also be set as J2000.) (IDL 6.1 or above.) ; ; JPEG -- Set this keyword to select JPEG files. ; ; LISTXSIZE -- Set this keyword to the XSIZE of the list widget. Default is 30 or MAX(StrLen(filenames)), whichever is larger. ; ; OFFSETS -- A two-element array containing the X and Y offsets of the program, from the upper left ; corner of the display. On dismissal of the program, if this is a named variable (passed into ; the program by reference), then it will contain the last offsets of the program. This is ; useful if you want to call ImageSelect again and have it positioned in exactly the same ; location it was before. ; ; ONLY2D -- Set this keyword if you only want the user to be able to select 2D images. Note ; that the user will be able to browse all images, but the Accept button will only ; be sensitive for 2D images. ; ; ONLY3D -- Set this keyword if you only want the user to be able to select 3D or true-color images. ; Note that the user will be able to browse all images, but the Accept button will only ; be sensitive for 3D or true-color images. ; ; PICT -- Set this keyword to select PICT files. ; ; PGM -- Set this keyword to select PGM files. ; ; PPM -- Set this keyword to select PPM files. ; ; PNG -- Set this keyword to select PNG files. ; ; PREVIEWSIZE -- Set this keyword to the maximum size (in pixels) of the preview window. Default is 150. ; ; SILENT -- Set this keyword to turn off Group_Leader educational message. Use only if you ; are sure you know what you are doing. :-) ; ; TIFF -- Set this keyword to select TIFF files. (This is the default filter selection.) ; ; TITLE -- Set this keyword to the text to display as the title of the main image selection window. ; ; NOTE: Any extra keywords passed into the program will collected and passed along to the READ_XXX routines ; that actually do the image file reading. Using this keyword inheritance mechanism makes it impossible ; to trap misspelled or misused keywords. Please take care when using ANY keyword for this routine! ; ; OUTPUT KEYWORDS: ; ; CANCEL -- This keyword is set to 1 if the user exits the program in any way except hitting the ACCEPT button. ; The ACCEPT button will set this keyword to 0. ; ; FHEADER -- Set this keyword to a named variable that will return the FITS header information for a FITS file. ; ; FILEINFO -- This keyword returns information about the selected file. Obtained from the QUERY_**** functions. ; ; GEOTIFF -- If the file is a GeoTIFF file, this keyword will return the GeoTIFF structure containing ; the files GeoTags. ; ; OUTDIRECTORY -- The directory where the selected file is found. ; ; OUTFILENAME -- The short filename of the selected file. ; ; PALETTE -- The current color table palette returned as a 256-by-3 byte array. ; ; COMMON BLOCKS: ; ; None. ; ; RESTRICTIONS: ; ; Requires other programs from the Coyote Library. ; ; Note: Keyword inheritance to collect undefined keywords that may be passed into the ; program for use in READ_XXX routines, make it impossible to trap keyword useage errors. ; Please take care when using keywords. ; ; EXAMPLE: ; ; To read JPEG files from the directory: ; ; IDL> image = ImageSelect(/JPEG) ; ; MODIFICATION HISTORY: ; ; Written by: David W. Fanning, 18 Jan 2001. ; Added modification to read both 8-bit and 24-bit BMP files. 27 Jan 2001. DWF. ; Fixed a problem with calculating the new size of the draw widget. 5 April 2002. DWF. ; Fixed a problem with List Widgets not sizing correctly on UNIX machines. 10 Aug 2002. DWF. ; Fixed a problem with the initial file not being selected correctly when you changed ; the file type. 10 Aug 2002. DWF. ; Added a FLIPIMAGE keyword 10 Aug 2002. DWF. ; When user chooses to Flip Image, I now reverse the Y dimension of the image, ; rather than set the !Order system variable. 10 Aug 2002. DWF. ; Added OUTDIRECTORY and OUTFILENAME keywords. 18 Aug 2002. DWF. ; Fairly extensive changes in the way this program works and selects images. ; A new version of FSC_FileSelect is also required. Because of interactions ; with the operating system with image filters, the program has probably ; become more Windows-centric. The default is now to display all image ; files the program is capable of reading. 31 October 2002. DWF. ; Added ONLY2D keyword to allow the acceptance of 2D images only. 3 Nov 2002. DWF. ; Added ability to center itself on the display. 8 Nov 2002. DWF. ; Fixed a problem caused by reading old images with short color table vectors. 26 Nov 2002. DWF. ; Fixed a problem with specifying a fully-qualified filename. 26 Nov 2002. DWF. ; Now highlights the selected file in the directory. 26 Nov 2002. DWF. ; Improved error handling. 9 Dec 2002. DWF. ; Added PALETTE keyword and improved color operation on 8-bit displays. If the image file ; contains a color palette, that palette is now loaded when the image is read from the file. ; The current color palette can be obtained with the PALETTE keyword. 4 April 2003. DWF. ; Added ONLY3D keyword. 19 April 2003. DWF. ; Added ability to read PPM and PGM files. 24 November 2003. DWF. ; Added TITLE keyword. 1 December 2003. DWF. ; Added EXAMPLES keyword. 22 December 2005. DWF. ; Added GIF and JPEG2000 file types. Rearranged and cleaned up code. 3 January 2006. DWF. ; Added LISTXSIZE keyword. 3 January 2006. DWF. ; Added file type checkmark buttons. Program now compatible with IDL 5.6 and higher. 3 January 2006. DWF. ; Improved error handling with invalid file types. 5 January 2006. DWF. ; Added OFFSETS and EXCLUDE keywords. 3 March 2006 DWF. ; Modified the program to check for FITS unsigned integer data. 3 March 2006. DWF. ; Added ability to double-click image name in list to Accept. 10 March 2006. DWF. ; Added FHEADER keyword to return FITS header information. 3 April 2006. DWF. ; Fixed a problem in which the file type was not set if the user cancelled. 10 July 2006. DWF. ; Added a "fit" file extension for FITS images. 1 April 2008. DWF. ; Added a FILTER keyword. 1 April 2008. DWF. ; Updated for reading transparent images. 13 May 2009. DWF. ; Provided check for PNG images with more than 8 bits per channel. 5 August 2009. DWF. ; Fixed a problem in which the starting directory was changed on exit. 20 Nov 2010. DWF. ; Change EXAMPLES to more easily remembered DEMO keyword. 29 Nov 2010. DWF. ; Removed NOINTERPOLATION keywords in going from TVIMAGE to cgImage. 22 Feb 2011. DWF. ; Fixed a problem reading 2D Tiff files. 20 Sept 2012. DWF. ; ;- ; ;******************************************************************************************; ; Copyright (c) 2008-2012, by Fanning Software Consulting, Inc. ; ; All rights reserved. ; ; ; ; Redistribution and use in source and binary forms, with or without ; ; modification, are permitted provided that the following conditions are met: ; ; ; ; * Redistributions of source code must retain the above copyright ; ; notice, this list of conditions and the following disclaimer. ; ; * Redistributions in binary form must reproduce the above copyright ; ; notice, this list of conditions and the following disclaimer in the ; ; documentation and/or other materials provided with the distribution. ; ; * Neither the name of Fanning Software Consulting, Inc. nor the names of its ; ; contributors may be used to endorse or promote products derived from this ; ; software without specific prior written permission. ; ; ; ; THIS SOFTWARE IS PROVIDED BY FANNING SOFTWARE CONSULTING, INC. ''AS IS'' AND ANY ; ; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ; ; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT ; ; SHALL FANNING SOFTWARE CONSULTING, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, ; ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED ; ; TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; ; ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ; ; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ; ; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ; ; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ; ;******************************************************************************************; FUNCTION ImageSelect_WindowSize, image, XSIZE=xsize, YSIZE=ysize ; This function determines the correct window size for an image that keeps ; its aspect ratio. Returns two element array: [xsize, ysize]. Assumes the ; current graphics window is where the image is to be displayed. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel void = cgErrorMsg() RETURN, Size(image, /Dimensions) ENDIF ; Need X and Y size of image. dims = Image_Dimensions(image, XSize=imgXSize, YSize=imgYSize) ; Fill the window. position=[0.0, 0.0, 1.0, 1.0] ; Find aspect ratio of image. ratio = FLOAT(imgYsize) / imgXSize ; Find the proposed size of the image in pixels without aspect ; considerations. xpixSize = (position(2) - position(0)) * xsize ypixSize = (position(3) - position(1)) * ysize ; Try to fit the image width. If you can't maintain ; the aspect ratio, fit the image height. trialX = xpixSize trialY = trialX * ratio IF trialY GT ypixSize THEN BEGIN trialY = ypixSize trialX = trialY / ratio ENDIF ; Recalculate the position of the image in the window. position(0) = (((xpixSize - trialX) / 2.0) / xsize) + position(0) position(2) = position(0) + (trialX/FLOAT(xsize)) position(1) = (((ypixSize - trialY) / 2.0) / ysize) + position(1) position(3) = position(1) + (trialY/FLOAT(ysize)) ; Return the X and Y sizes. RETURN, Round([(position[2]-position[0])*xsize, (position[3]-position[1])*ysize]) END ; ---------------------------------------------------------------------------------------- PRO ImageSelect_Action, event ; This event handler responds to CANCEL and ACCEPT buttons. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel ok = cgErrorMsg() IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF IF event.select NE 1 THEN RETURN Widget_Control, event.top, Get_UValue=info, /No_Copy ; Get the button value. Widget_Control, event.id, Get_Value=buttonValue ; Set the cancel flag appropriately. IF buttonValue EQ 'Accept' THEN (*info.storagePtr).cancel = 0 ; Get the name and directory you selected and set them into output fields. info.filenameObj->GetProperty, Directory=outdirectory, Filename=outfilename (*info.storagePtr).outdirectory = outdirectory (*info.storagePtr).outfilename = outfilename ; Is this a GEOTIFF file? isTiff = Query_Tiff(Filepath(ROOT_DIR=outdirectory, outfilename), GEOTIFF=geotiff) IF isTiff THEN BEGIN IF Size(geotiff, /TNAME) EQ 'STRUCT' THEN (*info.storagePtr).geotiff = Ptr_New(geotiff) ENDIF ; Get the current offsets. Widget_Control, event.top, TLB_GET_OFFSET=offsets (*info.storagePtr).offsets = offsets Widget_Control, event.top, Set_UValue=info, /No_Copy Widget_Control, event.top, /Destroy END ;--------------------------------------------------------------------------------- FUNCTION ImageSelect_BSort, Array, Asort, INFO=info, REVERSE = rev ; ; NAME: ; ImageSelect_BSort ; PURPOSE: ; Function to sort data into ascending order, like a simple bubble sort. ; EXPLANATION: ; Original subscript order is maintained when values are equal (FIFO). ; (This differs from the IDL SORT routine alone, which may rearrange ; order for equal values) ; ; CALLING SEQUENCE: ; result = ImageSelect_BSort( array, [ asort, /INFO, /REVERSE ] ) ; ; INPUT: ; Array - array to be sorted ; ; OUTPUT: ; result - sort subscripts are returned as function value ; ; OPTIONAL OUTPUT: ; Asort - sorted array ; ; OPTIONAL KEYWORD INPUTS: ; /REVERSE - if this keyword is set, and non-zero, then data is sorted ; in descending order instead of ascending order. ; /INFO = optional keyword to cause brief message about # equal values. ; ; HISTORY ; written by F. Varosi Oct.90: ; uses WHERE to find equal clumps, instead of looping with IF ( EQ ). ; compatible with string arrays, test for degenerate array ; 20-MAY-1991 JKF/ACC via T AKE- return indexes if the array to ; be sorted has all equal values. ; Aug - 91 Added REVERSE keyword W. Landsman ; Always return type LONG W. Landsman August 1994 ; Converted to IDL V5.0 W. Landsman September 1997 ; N = N_elements( Array ) if N lt 1 then begin print,'Input to ImageSelect_BSort must be an array' return, [0L] endif if N lt 2 then begin asort = array ;MDM added 24-Sep-91 return,[0L] ;Only 1 element end ; ; sort array (in descending order if REVERSE keyword specified ) ; subs = sort( Array ) if keyword_set( REV ) then subs = rotate(subs,5) Asort = Array[subs] ; ; now sort subscripts into ascending order ; when more than one Asort has same value ; weq = where( (shift( Asort, -1 ) eq Asort) , Neq ) if keyword_set( info ) then $ message, strtrim( Neq, 2 ) + " equal values Located",/CON,/INF if (Neq EQ n) then return,lindgen(n) ;Array is degenerate equal values if (Neq GT 0) then begin if (Neq GT 1) then begin ;find clumps of equality wclump = where( (shift( weq, -1 ) - weq) GT 1, Nclump ) Nclump = Nclump + 1 endif else Nclump = 1 if (Nclump LE 1) then begin Clump_Beg = 0 Clump_End = Neq-1 endif else begin Clump_Beg = [0,wclump+1] Clump_End = [wclump,Neq-1] endelse weq_Beg = weq[ Clump_Beg ] ;subscript ranges weq_End = weq[ Clump_End ] + 1 ; of Asort equalities. if keyword_set( info ) then message, strtrim( Nclump, 2 ) + $ " clumps of equal values Located",/CON,/INF for ic = 0L, Nclump-1 do begin ;sort each clump. subic = subs[ weq_Beg[ic] : weq_End[ic] ] subs[ weq_Beg[ic] ] = subic[ sort( subic ) ] endfor if N_params() GE 2 then Asort = Array[subs] ;resort array. endif return, subs END ; ---------------------------------------------------------------------------------------- PRO ImageSelect_Cleanup, tlb ; Program pointers are cleaned up here. Widget_Control, tlb, Get_UValue=info, /No_Copy IF N_Elements(info) EQ 0 THEN RETURN Ptr_Free, info.theFiles Ptr_Free, info.filter Ptr_Free, info.excludeFiles END ; ---------------------------------------------------------------------------------------- FUNCTION ImageSelect_FileExtension, filename ; This function finds the file extension of the filename by ; searching for the last ".". parts = StrSplit(filename, ".", /Extract) IF N_Elements(parts) EQ 1 THEN extension = "*" ELSE $ extension = parts[N_Elements(parts)-1] RETURN, StrUpCase(extension) END ; ---------------------------------------------------------------------------------------- PRO ImageSelect_FilenameEvents, event ; This event handler responds to events from the filename compound widget. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel ok = cgErrorMsg() IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF Widget_Control, event.top, Get_UValue=info, /No_Copy ; Get the name of the file. filename = event.basename CD, event.directory, Current=thisDirectory ; Locate appropriate files. Ptr_Free, info.theFiles info.theFiles = Ptr_New(/Allocate_Heap) ; Sort the files. FOR j=0, N_Elements(*info.filter)-1 DO BEGIN specificFiles = File_Search((*info.filter)[j], Count=fileCount) IF fileCount GT 0 THEN IF N_Elements(*(info.theFiles)) EQ 0 THEN $ *info.theFiles = specificFiles[ImageSelect_BSort(specificFiles)] ELSE $ *info.theFiles = [*info.theFiles, specificFiles[ImageSelect_BSort(specificFiles)]] ENDFOR fileCount = N_Elements(*info.theFiles) IF fileCount EQ 0 THEN *info.theFiles = "" ELSE BEGIN IF Ptr_Valid(info.excludeFiles) THEN BEGIN FOR k=0,N_Elements(*info.excludeFiles)-1 DO BEGIN index = Where(StrUpCase(*info.theFiles) EQ StrUpCase((*info.excludeFiles)[k]), count, COMPLEMENT=ok) IF count GT 0 THEN *info.theFiles = (*info.theFiles)[ok] ENDFOR ENDIF IF filename EQ "" THEN filename = (*info.theFiles)[0] ENDELSE info.dataDirectory = event.directory ; Is the filename amoung the list of files? If not, ; chose another filename. index = Where(StrLowCase(*info.theFiles) EQ StrLowCase(filename), count) IF count EQ 0 THEN BEGIN filename = (*info.theFiles)[0] Widget_Control, info.filenameID, Set_Value=filename ENDIF ; Set the file list. Widget_Control, info.fileListID, Set_Value=*info.theFiles ; Can you find the filename in the list of files? If so, ; highlight it in the list. i = Where(StrUpCase(*info.theFiles) EQ StrUpCase(filename), count) IF count GT 0 THEN Widget_Control, info.filelistID, Set_List_Select=i ; Set the file extension. thisExtension = ImageSelect_FileExtension(filename) ; Try to read the image ImageSelect_ReadFiles, thisExtension, filename, info, fileinfo, $ image, ok, type, _Extra=*((*info.storagePtr).extra) ; If you are only displaying 2D images, set sensitive buttons. IF info.only2d THEN IF fileinfo.channels NE 1 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 ; If you are only displaying 3D images, set sensitive buttons. IF info.only3d THEN IF fileinfo.channels NE 3 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 ; What kind of image is this? CASE fileinfo.channels OF 3: imageType = 'True-Color ' + type + ' Image' 0: imageType = 'No Image' -1: imageType = 'Invalid Image File' ELSE: imageType = '2D ' + type + ' Image' ENDCASE ; Get the file sizes. Dicom images can report incorrect sizes, ; which is what we are trying to fix in the ysize line. xsize = fileInfo.dimensions[0] ysize = fileInfo.dimensions[1] > Fix(xsize * 0.5) ; Get the file sizes. dimensions = Image_Dimensions(image, XSize=xsize, YSize=ysize, YIndex=yindex) ; Flip the image if required. IF info.flipimage THEN image = Reverse(image, yindex+1) ; Calculate a window size for the image preview. aspect = Float(xsize) / ysize IF aspect GT 1 THEN BEGIN wxsize = Fix(info.previewSize) wysize = Fix(info.previewSize / aspect) < info.previewSize ENDIF ELSE BEGIN wysize = Fix(info.previewSize) wxsize = Fix(info.previewSize / aspect) < info.previewSize ENDELSE ; If you don't have an image, then get sensible numbers for the labels. IF imageType EQ 'No Image' OR imageType EQ 'Invalid Image File' THEN BEGIN xsize = 0 ysize = 0 minval = 0 maxval = 0 ENDIF ; Update the display with what you have. IF imageType EQ 'No Image' THEN imageDataType = 'NONE' ELSE imageDataType = Size(image, /TNAME) IF imageType EQ 'Invalid Image File' THEN imageDataType = 'INVALID' Widget_Control, info.labelTypeID, Set_Value=imageType Widget_Control, info.labelXSizeID, Set_Value="X Size: " + StrTrim(xsize, 2) Widget_Control, info.labelYSizeID, Set_Value="Y Size: " + StrTrim(ysize, 2) Widget_Control, info.labelDataTypeID, Set_Value="Type: " + imageDataType Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ; Draw the preview image. WSet, info.previewWID sizes = ImageSelect_WindowSize(image, XSIZE=info.previewSize, YSIZE=info.previewSize) Widget_Control, info.previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] TVLCT, info.r, info.g, info.b IF (Min(image) LT 0) OR (Max(image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, image, /Keep_Aspect IF imageDataType EQ 'NONE' THEN image = 0 ; Store the image data for later retrieval. *(*(info.storagePtr)).image = image *(*(info.storagePtr)).fileInfo = fileInfo (*info.storagePtr).r = info.r (*info.storagePtr).g = info.g (*info.storagePtr).b = info.b ; Clean up. CD, thisDirectory Widget_Control, event.top, Set_UValue=info, /No_Copy END ;--------------------------------------------------------------------------------- PRO ImageSelect_FlipImage, event ; This event handler reverses the Y dimension of the image and re-displays it. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel ok = cgErrorMsg() IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF Widget_Control, event.top, Get_UValue=info, /No_Copy ; Reverse the Y dimensions. dims = Image_Dimensions(*(*(info.storagePtr)).image, YIndex=yindex) *(*(info.storagePtr)).image = Reverse(*(*(info.storagePtr)).image, yindex + 1) ; Display it again. WSet, info.previewWID sizes = ImageSelect_WindowSize(*(*(info.storagePtr)).image, XSIZE=info.previewSize, YSIZE=info.previewSize) Widget_Control, info.previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] TVLCT, info.r, info.g, info.b IF (Min(*(*(info.storagePtr)).image) LT 0) OR (Max(*(*(info.storagePtr)).image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(*(*(info.storagePtr)).image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, *(*(info.storagePtr)).image, /Keep_Aspect Widget_Control, event.top, Set_UValue=info, /No_Copy END ; ---------------------------------------------------------------------------------------- PRO ImageSelect_ListEvents, event ; Handles events from the list widget of file names. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel ok = cgErrorMsg() IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF ; Handle double click events here. IF event.clicks NE 1 THEN BEGIN Widget_Control, event.top, Get_UValue=info, /No_Copy ; Get the name of the file. filename = (*info.theFiles)[event.index] CD, info.dataDirectory, Current=thisDirectory ; Set it in the Filename widget. Widget_Control, info.filenameID, Set_Value=filename ; Try to read the image thisExtension = ImageSelect_FileExtension(filename) ImageSelect_ReadFiles, thisExtension, filename, info, fileinfo, $ image, ok, type, _Extra=*((*info.storagePtr).extra) ; If this is an image you can accept, the read it and exit. ; If not treat as a single click. canRead = 1 IF info.only2d AND (fileinfo.channels NE 1) THEN canRead = 0 IF info.only3d AND (fileinfo.channels NE 3) THEN canRead = 0 IF canRead THEN BEGIN ; Set the cancel flag appropriately. (*info.storagePtr).cancel = 0 ; Get the name and directory you selected and set them into output fields. info.filenameObj->GetProperty, Directory=outdirectory, Filename=outfilename (*info.storagePtr).outdirectory = outdirectory (*info.storagePtr).outfilename = outfilename ; Get the current offsets. Widget_Control, event.top, TLB_GET_OFFSET=offsets (*info.storagePtr).offsets = offsets ; Store the image data for later retrieval. *(*(info.storagePtr)).image = image *(*(info.storagePtr)).fileInfo = fileInfo (*info.storagePtr).r = info.r (*info.storagePtr).g = info.g (*info.storagePtr).b = info.b TVLCT, info.r, info.g, info.b Widget_Control, event.top, Set_UValue=info, /No_Copy Widget_Control, event.top, /Destroy ENDIF ELSE BEGIN ; Set sensive buttons on for both 2D and 3D images. IF info.only2d THEN IF fileinfo.channels NE 1 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 IF info.only3d THEN IF fileinfo.channels NE 3 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 ; What kind of image is this? CASE fileinfo.channels OF 3: imageType = 'True-Color ' + type + ' Image' 0: imageType = 'No Image' -1: imageType = 'Invalid Image File' ELSE: imageType = '2D ' + type + ' Image' ENDCASE ; Get the file sizes. Dicom images can report incorrect sizes, ; which is what we are trying to fix in the ysize line. xsize = fileInfo.dimensions[0] ysize = fileInfo.dimensions[1] > Fix(xsize * 0.5) ; Get the file sizes. dimensions = Image_Dimensions(image, XSize=xsize, YSize=ysize, YIndex=yindex) ; Flip the image if required. IF info.flipimage THEN image = Reverse(image, yindex+1) ; Calculate a window size for the image preview. aspect = Float(xsize) / ysize IF aspect GT 1 THEN BEGIN wxsize = Fix(info.previewSize) wysize = Fix(info.previewSize / aspect) < info.previewSize ENDIF ELSE BEGIN wysize = Fix(info.previewSize) wxsize = Fix(info.previewSize / aspect) < info.previewSize ENDELSE ; If you don't have an image, then get sensible numbers for the labels. IF imageType EQ 'No Image' OR imageType EQ 'Invalid Image File' THEN BEGIN xsize = 0 ysize = 0 minval = 0 maxval = 0 ENDIF ; Update the display with what you have. IF imageType EQ 'No Image' THEN imageDataType = 'NONE' ELSE imageDataType = Size(image, /TNAME) IF imageType EQ 'Invalid Image File' THEN imageDataType = 'INVALID' Widget_Control, info.labelTypeID, Set_Value=imageType Widget_Control, info.labelXSizeID, Set_Value="X Size: " + StrTrim(xsize, 2) Widget_Control, info.labelYSizeID, Set_Value="Y Size: " + StrTrim(ysize, 2) Widget_Control, info.labelDataTypeID, Set_Value="Type: " + imageDataType IF imageDataType NE 'FLOAT' THEN BEGIN Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ENDIF ELSE BEGIN Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ENDELSE ; Draw the preview image. WSet, info.previewWID sizes = ImageSelect_WindowSize(image, XSIZE=info.previewSize, YSIZE=info.previewSize) Widget_Control, info.previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] TVLCT, info.r, info.g, info.b IF (Min(image) LT 0) OR (Max(image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, image, /Keep_Aspect IF imageDataType EQ 'NONE' THEN image = 0 ; Store the image data for later retrieval. *(*(info.storagePtr)).image = image *(*(info.storagePtr)).fileInfo = fileInfo (*info.storagePtr).r = info.r (*info.storagePtr).g = info.g (*info.storagePtr).b = info.b ; Clean up. CD, thisDirectory Widget_Control, event.top, Set_UValue=info, /No_Copy ENDELSE ENDIF ; Handle single click events here. IF event.clicks EQ 1 THEN BEGIN Widget_Control, event.top, Get_UValue=info, /No_Copy ; Get the name of the file. filename = (*info.theFiles)[event.index] CD, info.dataDirectory, Current=thisDirectory ; Set it in the Filename widget. Widget_Control, info.filenameID, Set_Value=filename ; Try to read the image thisExtension = ImageSelect_FileExtension(filename) ImageSelect_ReadFiles, thisExtension, filename, info, fileinfo, $ image, ok, type, _Extra=*((*info.storagePtr).extra) ; Set sensive buttons on for both 2D and 3D images. IF info.only2d THEN IF fileinfo.channels NE 1 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 IF info.only3d THEN IF fileinfo.channels NE 3 THEN $ Widget_Control, info.acceptID, Sensitive=0 ELSE $ Widget_Control, info.acceptID, Sensitive=1 ; What kind of image is this? CASE fileinfo.channels OF 3: imageType = 'True-Color ' + type + ' Image' 0: imageType = 'No Image' -1: imageType = 'Invalid Image File' ELSE: imageType = '2D ' + type + ' Image' ENDCASE ; Get the file sizes. Dicom images can report incorrect sizes, ; which is what we are trying to fix in the ysize line. xsize = fileInfo.dimensions[0] ysize = fileInfo.dimensions[1] > Fix(xsize * 0.5) ; Get the file sizes. dimensions = Image_Dimensions(image, XSize=xsize, YSize=ysize, YIndex=yindex) ; Flip the image if required. IF info.flipimage THEN image = Reverse(image, yindex+1) ; Calculate a window size for the image preview. aspect = Float(xsize) / ysize IF aspect GT 1 THEN BEGIN wxsize = Fix(info.previewSize) wysize = Fix(info.previewSize / aspect) < info.previewSize ENDIF ELSE BEGIN wysize = Fix(info.previewSize) wxsize = Fix(info.previewSize / aspect) < info.previewSize ENDELSE ; If you don't have an image, then get sensible numbers for the labels. IF imageType EQ 'No Image' OR imageType EQ 'Invalid Image File' THEN BEGIN xsize = 0 ysize = 0 minval = 0 maxval = 0 ENDIF ; Update the display with what you have. IF imageType EQ 'No Image' THEN imageDataType = 'NONE' ELSE imageDataType = Size(image, /TNAME) IF imageType EQ 'Invalid Image File' THEN imageDataType = 'INVALID' Widget_Control, info.labelTypeID, Set_Value=imageType Widget_Control, info.labelXSizeID, Set_Value="X Size: " + StrTrim(xsize, 2) Widget_Control, info.labelYSizeID, Set_Value="Y Size: " + StrTrim(ysize, 2) Widget_Control, info.labelDataTypeID, Set_Value="Type: " + imageDataType IF imageDataType NE 'FLOAT' THEN BEGIN Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ENDIF ELSE BEGIN Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ENDELSE ; Draw the preview image. WSet, info.previewWID sizes = ImageSelect_WindowSize(image, XSIZE=info.previewSize, YSIZE=info.previewSize) Widget_Control, info.previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] TVLCT, info.r, info.g, info.b IF (Min(image) LT 0) OR (Max(image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, image, /Keep_Aspect IF imageDataType EQ 'NONE' THEN image = 0 ; Store the image data for later retrieval. *(*(info.storagePtr)).image = image *(*(info.storagePtr)).fileInfo = fileInfo (*info.storagePtr).r = info.r (*info.storagePtr).g = info.g (*info.storagePtr).b = info.b ; Clean up. CD, thisDirectory Widget_Control, event.top, Set_UValue=info, /No_Copy ENDIF END ;--------------------------------------------------------------------------------- PRO ImageSelect_ReadFiles, extension, filename, info, fileinfo, image, ok, type, _Extra=extra ; Utility routine to read the data file. Returns the image and file information. ; First three parameters are required INPUT, last three are optional OUTPUT. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel void = cgErrorMsg() ok = 0 RETURN ENDIF ; We need three required parameters. IF N_Params() LT 3 THEN Message, 'Called with incorrect number of required parameters.' ; Initialize output variables. image = BytArr(info.previewsize, info.previewsize) fileInfo = {channels:0, dimensions:[info.previewsize, info.previewsize], type:""} ok = 0 ; Must have non-null filename to continue. IF filename EQ "" THEN RETURN ; Read the image for display. CASE extension OF "BMP": BEGIN ok = Query_BMP(filename, fileInfo) IF ok THEN BEGIN IF fileInfo.channels EQ 3 THEN image = Read_BMP(filename, /RGB, _EXTRA=extra) ELSE $ image = Read_BMP(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'BMP' ENDCASE "DCM": BEGIN IF StrUpCase(!Version.OS_Family) EQ 'WINDOWS' THEN BEGIN thisRelease = Float(!Version.Release) IF (thisRelease GT 6.4) AND (thisRelease LT 8) THEN BEGIN IF !Version.Memory_Bits EQ 64 THEN Message, 'This version of IDL does not support reading DICOM files.' ENDIF ENDIF ok = Query_DICOM(filename, fileInfo) IF ok THEN BEGIN image = Read_Dicom(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'DICOM' ENDCASE "GIF": BEGIN ok = Query_GIF(filename, fileInfo) IF ok THEN BEGIN IF fileInfo.channels EQ 0 THEN fileInfo.channels = 1 ; Bug? Read_GIF, filename, image, r, g, b, _EXTRA=extra IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'GIF' ENDCASE "FITS": BEGIN header = Call_Function('HeadFits', filename, /Silent, ERRMSG=ok) IF ok EQ "" THEN BEGIN ok = 1 ; Check for unsigned integer offset = Call_Function('SXPar', header, 'BZERO', Count=count) IF count GT 0 THEN BEGIN IF offset EQ '32768' THEN BEGIN image = Call_Function("MRDFITS", filename, /Unsigned, _EXTRA=extra, /Silent) ENDIF ELSE BEGIN image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ENDELSE ENDIF ELSE image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ; Construct a fileInfo structure for this image. dims = Image_Dimensions(image, XSize=xsize, YSize=ysize, TrueIndex=trueindex) fileinfo = {has_palette:0, channels:1, dimensions:dims, image_index:0L, $ num_images:1L, pixel_type:Size(image, /Type), type:"FITS", header:header} IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'FITS' ENDCASE "FIT": BEGIN header = Call_Function('HeadFits', filename, /Silent, ERRMSG=ok) IF ok EQ "" THEN BEGIN ok = 1 ; Check for unsigned integer offset = Call_Function('SXPar', header, 'BZERO', Count=count) IF count GT 0 THEN BEGIN IF offset EQ '32768' THEN BEGIN image = Call_Function("MRDFITS", filename, /Unsigned, _EXTRA=extra, /Silent) ENDIF ELSE BEGIN image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ENDELSE ENDIF ELSE image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ; Construct a fileInfo structure for this image. dims = Image_Dimensions(image, XSize=xsize, YSize=ysize, TrueIndex=trueindex) fileinfo = {has_palette:0, channels:1, dimensions:dims, image_index:0L, $ num_images:1L, pixel_type:Size(image, /Type), type:"FITS", header:header} IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'FITS' ENDCASE "FTS": BEGIN header = Call_Function('HeadFits', filename, /Silent, ERRMSG=ok) IF ok EQ "" THEN BEGIN ok = 1 ; Check for unsigned integer offset = Call_Function('SXPar', header, 'BZERO', Count=count) IF count GT 0 THEN BEGIN IF offset EQ '32768' THEN BEGIN image = Call_Function("MRDFITS", filename, /Unsigned, _EXTRA=extra, /Silent) ENDIF ELSE BEGIN image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ENDELSE ENDIF ELSE image = Call_Function("MRDFITS", filename, _EXTRA=extra, /Silent, /FScale) ; Construct a fileInfo structure for this image. dims = Image_Dimensions(image, XSize=xsize, YSize=ysize, TrueIndex=trueindex) fileinfo = {has_palette:0, channels:1, dimensions:dims, image_index:0L, $ num_images:1L, pixel_type:Size(image, /Type), type:"FITS", header:header} IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'FITS' ENDCASE "JPEG": BEGIN ok = Query_JPEG(filename, fileInfo) IF ok THEN $ BEGIN Device, Get_Visual_Depth = theDepth IF theDepth GT 8 THEN BEGIN Read_JPEG, filename, image, True=1, _EXTRA=extra ENDIF ELSE BEGIN Read_JPEG, filename, image, colortable, Dither=1, Colors=!D.Table_Size, _EXTRA=extra r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDELSE IF fileInfo.has_palette EQ 1 THEN $ BEGIN r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDIF ENDIF type = 'JPEG' ENDCASE "JPG": BEGIN ok = Query_JPEG(filename, fileInfo) IF ok THEN $ BEGIN Device, Get_Visual_Depth = theDepth IF theDepth GT 8 THEN BEGIN Read_JPEG, filename, image, True=1, _EXTRA=extra ENDIF ELSE BEGIN Read_JPEG, filename, image, colortable, Dither=1, Colors=!D.Table_Size, _EXTRA=extra r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDELSE IF fileInfo.has_palette EQ 1 THEN $ BEGIN r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDIF ENDIF type = 'JPEG' ENDCASE "JPE": BEGIN ok = Query_JPEG(filename, fileInfo) IF ok THEN $ BEGIN Device, Get_Visual_Depth = theDepth IF theDepth GT 8 THEN BEGIN Read_JPEG, filename, image, True=1, _EXTRA=extra ENDIF ELSE BEGIN Read_JPEG, filename, image, colortable, Dither=1, Colors=!D.Table_Size, _EXTRA=extra r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDELSE IF fileInfo.has_palette EQ 1 THEN $ BEGIN r = colortable[*,0] g = colortable[*,1] b = colortable[*,2] TVLCT, r, g, b ENDIF ENDIF type = 'JPEG' ENDCASE "JPF": BEGIN ok = Query_JPEG2000(filename, fileInfo) IF ok THEN BEGIN image = Read_JPEG2000(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'JPEG2000' ENDCASE "JPX": BEGIN ok = Query_JPEG2000(filename, fileInfo) IF ok THEN BEGIN image = Read_JPEG2000(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'JPEG2000' ENDCASE "JP2": BEGIN ok = Query_JPEG2000(filename, fileInfo) IF ok THEN BEGIN image = Read_JPEG2000(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'JPEG2000' ENDCASE "J2C": BEGIN ok = Query_JPEG2000(filename, fileInfo) IF ok THEN BEGIN image = Read_JPEG2000(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'JPEG2000' ENDCASE "J2K": BEGIN ok = Query_JPEG2000(filename, fileInfo) IF ok THEN BEGIN image = Read_JPEG2000(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'JPEG2000' ENDCASE "PICT": BEGIN ok = Query_PICT(filename, fileInfo) IF ok THEN BEGIN Read_PICT, filename, image, r, g, b, _EXTRA=extra IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'PICT' ENDCASE "PGM": BEGIN ok = Query_PPM(filename, fileInfo) IF ok THEN BEGIN Read_PPM, filename, image, _EXTRA=extra TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'PGM' ENDCASE "PPM": BEGIN ok = Query_PPM(filename, fileInfo) IF ok THEN BEGIN Read_PPM, filename, image, _EXTRA=extra TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ENDIF type = 'PPM' ENDCASE "PNG": BEGIN ok = Query_PNG(filename, fileInfo) IF ok THEN BEGIN image = Read_PNG(filename, r, g, b, _EXTRA=extra) IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) ; Some PNG files (from ImageMagick, for example) are created with 16-bits per channel. ; Convert this to 8-bits per channel, and also remove any alpha channel for this application. IF Size(image, /TNAME) NE 'BYTE' THEN image = BytScl(image) IF Size(image, /N_DIMENSIONS) GT 3 THEN BEGIN dims = Image_Dimensions(image, TRUEINDEX=trueindex) CASE trueIndex OF 0: image = image[0:2, *, *] 1: image = image[*, 0:2, *] 2: image = image[*, *, 0:2] ENDCASE ENDIF ENDIF type = 'PNG' ENDCASE "TIF": BEGIN ok = Query_TIFF(filename, fileInfo, GEOTIFF=geotiff) IF ok THEN BEGIN CASE fileInfo.channels OF 3: image = Read_TIFF(filename, _EXTRA=extra, ORIENTATION=orientation) ELSE: image = Read_TIFF(filename, r, g, b, _EXTRA=extra, ORIENTATION=orientation) ENDCASE IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) IF Size(geotiff, /TNAME) EQ 'STRUCT' THEN BEGIN ; Save the geotiff variable at the IDL main level. (Scope_VarFetch('geotiff', LEVEL=1, /ENTER)) = geotiff ENDIF ENDIF ELSE orientation = 1 IF orientation EQ 1 THEN BEGIN dims = Image_Dimensions(image, YINDEX=yindex) image = Reverse(Temporary(image), yindex+1) ENDIF IF Size(geotiff, /TNAME) EQ 'STRUCT' THEN type = 'GEOTIFF' ELSE type = 'TIFF' ENDCASE "TIFF": BEGIN ok = Query_TIFF(filename, fileInfo, GEOTIFF=geotiff) IF ok THEN BEGIN CASE fileInfo.channels OF 3: image = Read_TIFF(filename, _EXTRA=extra, ORIENTATION=orientation) ELSE: image = Read_TIFF(filename, r, g, b, _EXTRA=extra, ORIENTATION=orientation) ENDCASE IF fileInfo.has_palette EQ 1 THEN TVLCT, r, g, b ELSE TVLCT, Bindgen(256), Bindgen(256), Bindgen(256) IF Size(geotiff, /TNAME) EQ 'STRUCT' THEN BEGIN ; Save the geotiff variable at the IDL main level. (Scope_VarFetch('geotiff', LEVEL=1, /ENTER)) = geotiff ENDIF ENDIF ELSE orientation = 1 IF orientation EQ 1 THEN BEGIN dims = Image_Dimensions(image, YINDEX=yindex) image = Reverse(Temporary(image), yindex+1) ENDIF IF Size(geotiff, /TNAME) EQ 'STRUCT' THEN type = 'GEOTIFF' ELSE type = 'TIFF' ENDCASE ELSE: ok = 0 ENDCASE ; If there was a problem, report it and indicate an invalid file. IF ~ok THEN BEGIN void = Dialog_Message('Selected file is not a valid ' + extension + ' type. Returning.') fileInfo.channels = -1 RETURN ENDIF ; Store RGB vectors if they got set. IF N_Elements(r) NE 0 THEN info.r = r ELSE info.r = Bindgen(!D.Table_Size) IF N_Elements(g) NE 0 THEN info.g = g ELSE info.g = Bindgen(!D.Table_Size) IF N_Elements(b) NE 0 THEN info.b = b ELSE info.b = Bindgen(!D.Table_Size) END ; ------------------------------------------------------------------------------------ PRO ImageSelect_SetFilter, event ; This event handler responds to events on the Filter button. ; Error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel ok = cgErrorMsg() IF N_Elements(info) NE 0 THEN Widget_Control, event.top, Set_UValue=info, /No_Copy RETURN ENDIF ; This event handler sets the filter for image data files. Widget_Control, event.top, Get_UValue=info, /No_Copy ; The filter is in the User Value of the button. Store it. Widget_Control, event.id, Get_UValue=theFilter *info.filter = theFilter ; Put a check mark next to this button. parent = Widget_Info(event.id, /Parent) child = Widget_Info(parent, /Child) WHILE child NE 0 DO BEGIN IF child NE event.id THEN Widget_Control, child, Set_Button=0 ELSE Widget_Control, child, Set_Button=1 child = Widget_Info(child, /Sibling) ENDWHILE ; Get the current filename. Widget_Control, info.filenameID, Get_Value=filename ; Set the new filter in the Filename compound widget. info.filenameObj->SetProperty, Filter=theFilter ; Look in the data directory for the files. CD, info.dataDirectory, Current=thisDirectory ; Locate appropriate files. FOR j=0, N_Elements(*info.filter)-1 DO BEGIN specificFiles = File_Search((*info.filter)[j], Count=fileCount) IF fileCount GT 0 THEN IF N_Elements(theFiles) EQ 0 THEN $ theFiles = specificFiles[ImageSelect_BSort(StrLowCase(specificFiles))] ELSE $ theFiles = [theFiles, specificFiles[ImageSelect_BSort(StrLowCase(specificFiles))]] ENDFOR fileCount = N_Elements(theFiles) IF fileCount EQ 0 THEN BEGIN theFiles = "" filename = "" ENDIF ELSE BEGIN IF Ptr_Valid(info.excludeFiles) THEN BEGIN FOR k=0,N_Elements(*info.excludeFiles)-1 DO BEGIN index = Where(StrUpCase(theFiles) EQ StrUpCase((*info.excludeFiles)[k]), count, COMPLEMENT=ok) IF count GT 0 THEN theFiles = theFiles[ok] ENDFOR ENDIF filename = theFiles[0] ENDELSE ; Update the widget interface according to what you found. Widget_Control, info.filenameID, Set_Value=filename Widget_Control, info.fileListID, Set_Value=theFiles IF fileCount GT 0 THEN Widget_Control, info.fileListID, Set_List_Select=0 *info.theFiles = theFiles ; Try to read the image thisExtension = ImageSelect_FileExtension(filename) ImageSelect_ReadFiles, thisExtension, filename, info, fileinfo, $ image, ok, type, _Extra=*((*info.storagePtr).extra) ; What kind of image is this? CASE fileinfo.channels OF 3: imageType = 'True-Color ' + type + ' Image' 0: imageType = 'No Image' -1: imageType = 'Invalid Image File' ELSE: imageType = '2D ' + type + ' Image' ENDCASE ; Get the file sizes. Dicom images can report incorrect sizes, ; which is what we are trying to fix in the ysize line. xsize = fileInfo.dimensions[0] ysize = fileInfo.dimensions[1] > Fix(xsize * 0.5) ; Get the file sizes. dimensions = Image_Dimensions(image, XSize=xsize, YSize=ysize, YIndex=yindex) ; Flip the image if required. IF info.flipimage THEN image = Reverse(image, yindex+1) ; Calculate a window size for the image preview. aspect = Float(xsize) / ysize IF aspect GT 1 THEN BEGIN wxsize = Fix(info.previewSize) wysize = Fix(info.previewSize / aspect) < info.previewSize ENDIF ELSE BEGIN wysize = Fix(info.previewSize) wxsize = Fix(info.previewSize / aspect) < info.previewSize ENDELSE ; If you don't have an image, then get sensible numbers for the labels. IF imageType EQ 'No Image' OR imageType EQ 'Invalid Image File' THEN BEGIN xsize = 0 ysize = 0 minval = 0 maxval = 0 ENDIF ; Update the display with what you have. IF imageType EQ 'No Image' THEN imageDataType = 'NONE' ELSE imageDataType = Size(image, /TNAME) IF imageType EQ 'Invalid Image File' THEN imageDataType = 'INVALID' Widget_Control, info.labelTypeID, Set_Value=imageType Widget_Control, info.labelXSizeID, Set_Value="X Size: " + StrTrim(xsize, 2) Widget_Control, info.labelYSizeID, Set_Value="Y Size: " + StrTrim(ysize, 2) Widget_Control, info.labelDataTypeID, Set_Value="Type: " + imageDataType Widget_Control, info.labelminvalID, Set_Value="Min Value: " + cgNumber_Formatter(Min(image)) Widget_Control, info.labelmaxvalID, Set_Value="Max Value: " + cgNumber_Formatter(Max(image)) ; Draw the preview image. WSet, info.previewWID sizes = ImageSelect_WindowSize(image, XSIZE=info.previewSize, YSIZE=info.previewSize) Widget_Control, info.previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] TVLCT, info.r, info.g, info.b IF (Min(image) LT 0) OR (Max(image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, image, /Keep_Aspect IF imageDataType EQ 'NONE' THEN image = 0 ; Save the image data for later retrieval. *(*(info.storagePtr)).image = image *(*(info.storagePtr)).fileInfo = fileInfo (*info.storagePtr).r = info.r (*info.storagePtr).g = info.g (*info.storagePtr).b = info.b ; Clean up. CD, thisDirectory Widget_Control, event.top, Set_UValue=info, /No_Copy END ; ---------------------------------------------------------------------------------------- FUNCTION ImageSelect, $ BMP=bmp, $ ; Set this keyword to select BMP files. Cancel=cancel, $ ; An output keyword. Returns 0 if the ACCEPT button is used, 1 otherwise. Demo=demo, $ ; If set, check the $IDL_DIR/examples/data directory first. Dicom=dicom, $ ; Set this keyword to select DICOM files Directory=directory, $ ; Initial directory to search for files. Examples=examples, $ ; If set, check the $IDL_DIR/examples/data directory first. Exclude=exclude, $ ; A list of files that should be excluded from the list of available files. _Extra=extra, $ ; This is used to pass keywords on to READ_XXX routines. FileInfo=fileInfo, $ ; An output keyword containing file information from the Query_*** routine. Filename=filename, $ ; Initial file name of image file. Filter = filter, $ FITS=fits, $ ; Set this keyword to select FITS files. (Must have NASA Astro Library on !PATH) Flipimage=flipimage, $ ; Set this keyword to flip the Y indices of the image. Set to 0 by default. GEOTIFF=geotiff, $ ; Returns the geotiff structure of GeoTIFF files. GIF=gif, $ ; Set this keyword to select GIF files. (IDL 6.2 and above, only) Group_Leader=group_leader, $ ; The group leader ID of this widget program. FHeader=fheader, $ ; Output keyword returns FITS header from FITS files. J2000=j2000, $ ; Set this keyword to select JPEG2000 files (IDL 6.1 and above, only.) J2K=j2k, $ ; Set this keyword to select JPEG2000 files (IDL 6.1 and above, only.) JPEG=jpeg, $ ; Set this keyword to select JPEG files LISTXSIZE=listxsize, $ ; Set this keyword to the XSIZE of the list widget. OFFSETS=offsets, $ ; The offsets of the program. ONLY2D=only2d, $ ; Set this keyword so that only 2D images can be accepted. ONLY3D=only3d, $ ; Set this keyword so that only 3D or true-color images can be accepted. OutDirectory=outdirectory, $ ; The directory name of the selected image file. OutFilename=outfilename, $ ; The short filename (without directory) of the selected image file. Palette=palette, $ ; The color palette associated with the file. PICT=pict, $ ; Set this keyword to select PICT files PGM=pgm, $ ; Set this keyword to read PGM files. PPM=ppm, $ ; Set this keyword to read PPM files. PNG=png, $ ; Set this keyword to select PNG files. SILENT=silent, $ ; Set this keyword to run off educational message. TIFF=tiff, $ ; Set this keyword to select TIFF files. TITLE=title, $ ; The title of the main image selection window. PreviewSize=previewsize ; The maximum size of the image preview window. 150 pixels by default. CD, Current=originalDir ; First thing we are going to do is check for the availability of FITS files. We are ; going to look for MRDFITS on the path. If we don't find it, we will generate an error ; condition and handle it silently. skip = 0 Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel skip = 1 haveFits = 0 ENDIF IF skip EQ 0 THEN BEGIN RESOLVE_ROUTINE, 'MRDFITS', /IS_FUNCTION, /NO_RECOMPILE haveFits = 1 ENDIF ; Normal error handling. Catch, theError IF theError NE 0 THEN BEGIN Catch, /Cancel Cancel = 1 ok = cgErrorMsg() RETURN, 0 ENDIF ; Set up the info structure. info = { storagePtr: Ptr_New(), $ ; The "outside the program" storage pointer. previewID: 0L, $ ; The ID of the preview draw widget. previewWID: 0L, $ ; The window index number of the preview draw widget. r:BytArr(256), $ ; The R color vector. g:BytArr(256), $ ; The G color vector. b:BytArr(256), $ ; The B color vector. theFiles: Ptr_New(), $ ; The current list of files in the directory. excludeFiles: Ptr_New(), $ ; The list of files to exclude from the file list. filenameID: 0L, $ ; The identifier of the FileSelect compound widget. fileListID: 0L, $ ; The identifier of the file list widget. flipimage:0L, $ ; A flag to flip the image Y order. previewSize: 0L, $ ; The default size of the preview window. acceptID: 0L, $ ; The idenfier of the Accept button widget. only2d: 0L, $ ; A flag that permits only the acceptance of 2D images. only3d: 0L, $ ; A flag that permits only the acceptance of true-color images. filter: Ptr_New(), $ ; The file filter. filenameObj: Obj_New(), $ ; The FileSelect compound widget object reference. originalDir: "", $ ; The starting or original directory. dataDirectory: "", $ ; The current data directory. display: 0B, $ ; Display the image after reading? labelmaxvalID: 0L, $ ; The ID of the Max Value label. labelminvalID: 0L, $ ; The ID of the Max Value label. labelTypeID: 0L, $ ; The ID of the Image Type label. labelXSizeID: 0L, $ ; The ID of the X Size label. labelYSizeID: 0L, $ ; The ID of the Y Size label. labelDataTypeID: 0L $ ; The ID of the Data Type label. } ; Check for availability of GIF and JPEG2000 files. thisVersion = Float(!Version.Release) IF ((thisVersion LT 5.3) OR (thisVersion GE 6.2)) THEN haveGif = 1 ELSE haveGIF = 0 IF thisVersion GE 6.1 THEN BEGIN haveJ2000 = 1 scopeOK = 1 ; Use ScopeLevel. ENDIF ELSE BEGIN haveJ2000 = 0 scopeOK = 0 ; Use Routine_Names. ENDELSE ; Set up the filter. IF Keyword_Set(bmp) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.bmp"] ELSE filter = [filter, "*.bmp"] IF Keyword_Set(dicom) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.dcm"] ELSE filter = [filter, "*.dcm"] flipimage = Keyword_Set(flipimage) IF Keyword_Set(examples) THEN demo = 1 demo = Keyword_Set(demo) IF N_Elements(exclude) NE 0 THEN info.excludeFiles = Ptr_New(exclude) IF Keyword_Set(gif) THEN BEGIN IF havegif THEN BEGIN IF N_Elements(filter) EQ 0 THEN filter = ["*.gif"] ELSE filter = [filter, "*.gif"] ENDIF ELSE ok = Dialog_Message('GIF files are not available in this version of IDL. Continuing.') ENDIF IF haveFits THEN BEGIN IF Keyword_Set(fits) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.fits", "*.fts", "*.fit"] ELSE $ filter = [filter, "*.fits", "*.fts", "*.fit"] ENDIF IF Keyword_Set(jpeg) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.jpg", "*.jpeg", "*.jpe"] ELSE $ filter = [filter, "*.jpg", "*.jpeg", "*.jpe"] IF Keyword_Set(j2000) OR Keyword_Set(j2k) THEN BEGIN IF haveJ2000 THEN BEGIN IF N_Elements(filter) EQ 0 THEN filter = ["*.jpf", "*.jpx", "*.jp2", "*.j2c", "*.j2k"] ELSE $ filter = [filter, "*.jpf", "*.jpx", "*.jp2", "*.j2c", "*.j2k"] ENDIF ELSE ok = Dialog_Message('JPEG2000 files are not available in this version of IDL. Continuing.') ENDIF IF Keyword_Set(pict) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.pict"] ELSE filter = [filter, "*.pict"] IF Keyword_Set(png) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.png"] ELSE filter = [filter, "*.png"] IF Keyword_Set(tiff) THEN IF N_Elements(filter) EQ 0 THEN filter = ["*.tif"] ELSE filter = [filter, "*.tif"] IF N_Elements(filter) EQ 0 THEN BEGIN filter = ['*.bmp', '*.dcm', '*.jpg', "*.jpeg", "*.jpe", '*.pict', '*.ppm', '*.pgm', '*.png', '*.tif'] IF haveGif THEN filter = [filter, "*.gif"] IF havej2000 THEN filter = [filter, "*.jpf", "*.jpx", "*.jp2", "*.j2c", "*.j2k"] IF haveFits THEN filter = [filter, "*.fits", "*.fts", "*.fit"] allextensions = 1 ENDIF ELSE allextensions = 0 only2D = Keyword_Set(only2d) only3D = Keyword_Set(only3d) IF N_Elements(title) EQ 0 THEN title = 'Select Image File' ; Get the current directory. Some processing involved. IF Keyword_Set(demo) THEN BEGIN path = Filepath(SubDir=['examples', 'data'], 'junk.pro') directory = File_Dirname(path) ENDIF CD, Current=startDirectory IF N_Elements(directory) EQ 0 THEN directory = startDirectory ELSE BEGIN IF StrMid(directory, 0, 2) EQ ".." THEN BEGIN CASE StrUpCase(!Version.OS_Family) OF 'MACOS': BEGIN CD, '..' CD, Current=basename directory = basename + StrMid(directory, 3) END 'VMS': BEGIN CD, '..' CD, Current=basename directory = basename + StrMid(directory, 3) END ELSE: BEGIN CD, '..' CD, Current=basename directory = basename + StrMid(directory, 2) END ENDCASE ENDIF IF StrMid(directory, 0, 1) EQ "." THEN BEGIN CASE StrUpCase(!Version.OS_Family) OF 'MACOS': BEGIN CD, Current=basename directory = basename + StrMid(directory, 2) END 'VMS': BEGIN CD, Current=basename directory = basename + StrMid(directory, 2) END ELSE: BEGIN CD, Current=basename directory = basename + StrMid(directory, 1) END ENDCASE ENDIF ENDELSE CD, directory ; Check other keyword values. IF N_Elements(filename) EQ 0 THEN file = "" ELSE BEGIN dir=StrMid(filename, 0, StrPos(filename, Path_Sep(), /REVERSE_SEARCH)) IF dir NE "" THEN BEGIN directory = dir CD, directory file = StrMid(filename, StrLen(directory)+1) ENDIF ELSE file = filename ENDELSE IF N_Elements(previewSize) EQ 0 THEN previewSize = 150 info.previewSize = previewSize ; Locate appropriate files. FOR j=0, N_Elements(filter)-1 DO BEGIN specificFiles = File_Search(filter[j], Count=fileCount) IF fileCount GT 0 THEN IF N_Elements(theFiles) EQ 0 THEN $ theFiles = specificFiles[ImageSelect_BSort(StrLowCase(specificFiles))] ELSE $ theFiles = [theFiles, specificFiles[ImageSelect_BSort(StrLowCase(specificFiles))]] ENDFOR fileCount = N_Elements(theFiles) IF fileCount EQ 0 THEN theFiles = "" ELSE BEGIN theFiles = theFiles[ImageSelect_BSort(theFiles)] IF Ptr_Valid(info.excludeFiles) THEN BEGIN FOR k=0,N_Elements(*info.excludeFiles)-1 DO BEGIN index = Where(StrUpCase(theFiles) EQ StrUpCase((*info.excludeFiles)[k]), count, COMPLEMENT=ok) IF count GT 0 THEN theFiles = theFiles[ok] ENDFOR ENDIF IF file EQ "" THEN file = theFiles[0] ENDELSE ; Try to read the file. extension = ImageSelect_FileExtension(file) ImageSelect_ReadFiles, extension, file, info, fileinfo, image, ok, type, _Extra=extra ; Get the file sizes. dimensions = Image_Dimensions(image, XSize=xsize, YSize=ysize, YIndex=yindex) ; Flip the image if required. IF flipimage THEN image = Reverse(image, yindex+1) ; Do you have a group leader? Here is my attempt to educate ; people to its use. I'll create a group leader if I have ; to, but it's ugly and I don't want to. I rule it out for ; RUNTIME and VM use. You should know better. :-) IF scopeOK THEN scopeLevel = Scope_Level() ELSE scopeLevel = Routine_Names(/Level) IF scopeLevel GT 2 THEN BEGIN IF N_Elements(group_leader) EQ 0 THEN BEGIN IF ~Keyword_Set(silent) THEN BEGIN CASE 1 OF LMGR(/VM): Message, 'In a VM application, a GROUP_LEADER is required for MODAL operation.' LMGR(/RUNTIME): Message, 'In a RUNTIME application, a GROUP_LEADER is required for MODAL operation.' ELSE: ENDCASE ENDIF group_leader = Widget_Base(Map=0) Widget_Control, group_leader, /Realize destroy_groupleader = 1 ENDIF ELSE destroy_groupleader = 0 ENDIF ELSE destroy_groupleader = 0 ; Create the widgets. IF N_Elements(group_leader) NE 0 THEN BEGIN tlb = Widget_Base(Title=title, Column=1, /Base_Align_Center, $ /Modal, Group_Leader=group_leader) ENDIF ELSE BEGIN tlb = Widget_Base(Title=title, Column=1, /Base_Align_Center) ENDELSE fileSelectBase = Widget_Base(tlb, Column=1, Frame=1) buttonBase = Widget_Base(tlb, Row=1) ; Define file selection widgets. filenameID = FSC_FileSelect(fileSelectBase, Filename=file, ObjectRef=filenameObj,$ Directory=directory, Event_Pro='ImageSelect_FilenameEvents', Filter=filter, _Extra=extra) fsrowbaseID = Widget_Base(fileSelectBase, Row=1, XPad=10) IF N_Elements(listxsize) EQ 0 THEN listxsize = Max(StrLen(theFiles)) + 0.1*Max(StrLen(theFiles)) > 30 filelistID = Widget_List(fsrowbaseID, Value=theFiles, YSize = 10, XSize=listxsize, $ Event_Pro='ImageSelect_ListEvents') spacer = Widget_Label(fsrowbaseID, Value=" ") previewID = Widget_Draw(fsrowbaseID, XSize=previewSize, YSize=previewSize) spacer = Widget_Label(fsrowbaseID, Value=" ") labelBaseID = Widget_Base(fsrowbaseID, Column=1, /Base_Align_Left) ; What kind of image is this? CASE fileinfo.channels OF 3: imageType = 'True-Color ' + type + ' Image' 0: imageType = 'No Image' -1: imageType = 'Invalid Image File' ELSE: imageType = '2D ' + type + ' Image' ENDCASE xsize = fileInfo.dimensions[0] ysize = fileInfo.dimensions[1] > Fix(xsize * 0.5) imageDataType = Size(image, /TNAME) IF imageType EQ 'Invalid Image File' THEN imageDataType = 'INVALID' IF imageType EQ 'No Image' THEN imageDataType = 'NONE' ; If you don't have an image, then get sensible numbers for the labels. IF imageType EQ 'No Image' OR imageType EQ 'Invalid Image File' THEN BEGIN xsize = 0 ysize = 0 minval = 0 maxval = 0 ENDIF labeltypeID = Widget_Label(labelBaseID, Value=imageType, /Dynamic_Resize) labelxsizeID = Widget_Label(labelBaseID, Value="X Size: " + StrTrim(xsize, 2), /Dynamic_Resize) labelysizeID = Widget_Label(labelBaseID, Value="Y Size: " + StrTrim(ysize, 2), /Dynamic_Resize) labeldataTypeID = Widget_Label(labelBaseID, Value="Type: " + imageDataType, /Dynamic_Resize) labelminvalID = Widget_Label(labelBaseID, Value="Min Value: " + cgNumber_Formatter(Min(image)), /Dynamic_Resize) labelmaxvalID = Widget_Label(labelBaseID, Value="Max Value: " + cgNumber_Formatter(Max(image)), /Dynamic_Resize) ; Size the draw widget appropriately. ; Calculate a window size for the image preview. IF xsize NE ysize THEN BEGIN aspect = Float(ysize) / xsize IF aspect LT 1 THEN BEGIN wxsize = previewSize wysize = (previewSize * aspect) < previewSize ENDIF ELSE BEGIN wysize = previewSize wxsize = (previewSize / aspect) < previewSize ENDELSE ENDIF ; Can you find the filename in the list of files? If so, ; highlight it in the list. index = Where(StrUpCase(theFiles) EQ StrUpCase(file), count) IF count GT 0 THEN Widget_Control, filelistID, Set_List_Select=index ; Define buttons widgets. button = Widget_Button(buttonBase, Value='Cancel', Event_Pro='ImageSelect_Action') filterID = Widget_Button(buttonBase, Value='Image Type...', /Menu, Event_Pro='ImageSelect_SetFilter') button = Widget_Button(filterID, Value='BMP Files', UValue=['*.bmp'], /Checked_Menu) IF Keyword_Set(bmp) THEN Widget_Control, button, Set_Button=1 button = Widget_Button(filterID, Value='DICOM Files', UValue=['*.dcm'], /Checked_Menu) IF Keyword_Set(dicom) THEN Widget_Control, button, Set_Button=1 IF haveFits THEN BEGIN button = Widget_Button(filterID, Value='FITS Files', UValue=['*.fits', '*.fts', '*.fit'], /Checked_Menu) IF Keyword_Set(fits) THEN Widget_Control, button, Set_Button=1 ENDIF IF havegif THEN BEGIN button = Widget_Button(filterID, Value='GIF Files', UValue=['*.gif'], /Checked_Menu) IF Keyword_Set(gif) THEN Widget_Control, button, Set_Button=1 ENDIF button = Widget_Button(filterID, Value='JPEG Files', UValue=['*.jpg', '*.jpeg', '*.jpe'], /Checked_Menu) IF Keyword_Set(jpeg) THEN Widget_Control, button, Set_Button=1 IF haveJ2000 THEN BEGIN button = Widget_Button(filterID, Value='JPEG2000 Files', UValue=['*.jpf', '*.jpx', '*.jp2', '*.j2c', '*.j2k'], /Checked_Menu) IF Keyword_Set(j2000) THEN Widget_Control, button, Set_Button=1 ENDIF button = Widget_Button(filterID, Value='PICT Files', UValue=['*.pict'], /Checked_Menu) IF Keyword_Set(pict) THEN Widget_Control, button, Set_Button=1 button = Widget_Button(filterID, Value='PNG Files', UValue=['*.png'], /Checked_Menu) IF Keyword_Set(png) THEN Widget_Control, button, Set_Button=1 button = Widget_Button(filterID, Value='PPM Files', UValue=['*.pgm', '*.ppm'], /Checked_Menu) IF Keyword_Set(ppm) THEN Widget_Control, button, Set_Button=1 button = Widget_Button(filterID, Value='PGM Files', UValue=['*.pgm', '*.ppm'], /Checked_Menu) IF Keyword_Set(pgm) THEN Widget_Control, button, Set_Button=1 button = Widget_Button(filterID, Value='TIFF Files', UValue=['*.tif', '*.tiff'], /Checked_Menu) IF Keyword_Set(tiff) THEN Widget_Control, button, Set_Button=1 IF haveFits THEN BEGIN button = Widget_Button(filterID, Value='All Types', $ UValue=['*.bmp', '*.dcm', '*.fits', '*.fts', '*.fit', '*.gif', '*.jpg', '*.jpeg', '*.jpe', '*.jpf', '*.jpx', $ '*.jp2', '*.j2c', '*.j2k', '*.pict', '*.png', '*.ppm', '*.pgm', '*.tif', '*.tiff'], /Checked_Menu) ENDIF ELSE BEGIN button = Widget_Button(filterID, Value='All Types', $ UValue=['*.bmp', '*.dcm', '*.gif', '*.jpg', '*.jpeg', '*.jpe', '*.jpf', '*.jpx', $ '*.jp2', '*.j2c', '*.j2k', '*.pict', '*.png', '*.ppm', '*.pgm', '*.tif', '*.tiff'], /Checked_Menu) ENDELSE IF allextensions THEN Widget_Control, button, Set_Button=1 button = Widget_Button(buttonBase, Value='Flip Image', Event_Pro='ImageSelect_FlipImage') acceptID = Widget_Button(buttonBase, Value='Accept', Event_Pro='ImageSelect_Action') IF only2d THEN BEGIN IF fileinfo.channels NE 1 THEN Widget_Control, acceptID, Sensitive=0 Widget_Control, tlb, TLB_Set_Title=title + ' (2D Images Only)' ENDIF IF only3d THEN BEGIN IF fileinfo.channels NE 3 THEN Widget_Control, acceptID, Sensitive=0 Widget_Control, tlb, TLB_Set_Title=title + ' (True-Color Images Only)' ENDIF ; Center the TLB or use offsets, if defined. IF N_Elements(offsets) NE 0 THEN BEGIN IF N_Elements(offsets) NE 2 THEN offsets = [offsets[0], offsets[0]] Widget_Control, tlb, XOffset=offsets[0], YOffset=offsets[1] ENDIF ELSE BEGIN cgCenterTLB, tlb offsets = LonArr(2) ENDELSE Widget_Control, tlb, /Realize ; Display the image. Widget_Control, previewID, Get_Value=previewWID WSet, previewWID sizes = ImageSelect_WindowSize(image, XSIZE=previewSize, YSIZE=previewSize) Widget_Control, previewID, Draw_XSize=sizes[0], Draw_YSize=sizes[1] IF (Min(image) LT 0) OR (Max(image) GT (!D.Table_Size-1)) THEN $ cgImage, BytScl(image, Top=!D.Table_Size-1), /Keep_Aspect ELSE $ cgImage, image, /Keep_Aspect ; Set up information to run the program. storagePtr = Ptr_New({cancel:1, image:Ptr_New(image), fileInfo:Ptr_New(fileInfo), offsets:offsets, $ outdirectory:"", outfilename:"", r:info.r, g:info.g, b:info.b, $ geotiff:Ptr_New(), extra:Ptr_New(extra), originalDir:originalDir}) ; Load the info structure. info.storagePtr = storagePtr info.previewID = previewID info.previewWID = previewWID info.theFiles = Ptr_New(theFiles) info.filenameID = filenameID info.fileListID = fileListID info.flipImage = flipImage info.previewSize = previewSize info.acceptID = acceptID info.only2d = only2d info.only3d = only3d info.filter = Ptr_New(filter) info.filenameObj = filenameObj info.dataDirectory = directory info.display = Keyword_Set(display) info.labelmaxvalID = labelmaxvalID info.labelminvalID = labelminvalID info.labelTypeID = labelTypeID info.labelXSizeID = labelXSizeID info.labelYSizeID = labelYSizeID info.labelDataTypeID = labelDataTypeID info.originalDir = originalDir Widget_Control, tlb, Set_UValue=info, /No_Copy ; Blocking or modal widget mode, depending upon presence of GROUP_LEADER. XManager, "imageselect", tlb, Cleanup='ImageSelect_Cleanup' ; Return collected information. cancel = (*storagePtr).cancel fileInfo = *(*storagePtr).fileInfo type = fileInfo.type IF Ptr_Valid((*storagePtr).geotiff) THEN geotiff = *(*storagePtr).geotiff ELSE Undefine, geotiff IF type EQ 'FITS' THEN fheader = fileInfo.header image = *((*storagePtr).image) outDirectory = (*storagePtr).outDirectory outFilename = (*storagePtr).outFilename originalDir = (*storagePtr).originalDir CD, originalDir offsets = (*storagePtr).offsets Ptr_Free, (*storagePtr).image Ptr_Free, (*storagePtr).fileInfo Ptr_Free, (*storagePtr).geotiff palette = BytArr(256,3) palette[*,0] = (*storagePtr).r palette[*,1] = (*storagePtr).g palette[*,2] = (*storagePtr).b IF Ptr_Valid((*storagePtr).extra) NE 0 THEN BEGIN IF N_Elements(*(*storagePtr).extra) NE 0 THEN extra = *(*storagePtr).extra ENDIF Ptr_Free, (*storagePtr).extra Ptr_Free, storagePtr ; Did you create your own group leader? IF destroy_groupleader THEN Widget_Control, group_leader, /Destroy ; Return the image. IF cancel EQ 1 THEN RETURN, 0 ELSE RETURN, image END ; ----------------------------------------------------------------------------------------