source: trunk/SRC/Picture/image_viewer.pro @ 134

Last change on this file since 134 was 134, checked in by navarro, 18 years ago

change *.pro file properties (del eof-style, del executable, set keywords Id

  • Property svn:keywords set to Id
File size: 48.3 KB
Line 
1;+
2;
3; @file_comments
4; The purpose of this program is to provide an interactive tool that can be used
5; to view JPEG, BMP, GIF, PNG, and TIFF picture files.  Images are loaded into
6; memory, so the initial file access may take a while, but once each picture has
7; been opened they can all be viewed in a very rapid fashion.
8;
9; @categories Visualization, Widgets
10;
11; @param event {in}{required}
12;
13; @restrictions While this program is running in an IDL session it will change the current
14;       working directory, enables/disables color decomposition, and sets !QUIET=1,
15;       !ORDER=0, & !P.BACKGROUND=0.  These settings are returned to their initial
16;       settings before the program was initiated once it is terminated.
17;
18; @restrictions This program is supported in IDL version 5.5 and newer.  In order to open
19;       GIF files or TIFF files with LZW compression the copy of IDL being used must
20;       be licensed with these features.  IDL only supports BMP files in the standard
21;       Windows format and does not support OS2 bitmaps.
22;
23; @history Written by: AEB, 1/02.
24;
25; @version $Id$
26;*********************************************************************************************
27;_
28
29PRO IMAGE_VIEWER_OPEN_FILES,event
30;THIS PROCEDURE IS CALLED WHEN A USER SELECTS "File > Open Picture Files" FROM THE MAIN MENU
31;error handling:
32;
33  compile_opt idl2, strictarrsubs
34;
35!ERROR_STATE.CODE=0
36CATCH,error
37if error NE 0 then begin
38  HELP,/LAST_MESSAGE,OUTPUT=traceback
39  messageStr=['Error Caught :','',traceback]
40  dummy=DIALOG_MESSAGE(messageStr,/ERROR)
41  ;if status report dialog is still active, destroy it:
42  if SIZE(tlb,/TYPE) NE 0 then WIDGET_CONTROL,tlb,/DESTROY
43  RETURN
44endif
45;obtain state structure for top-level-base from its UVALUE:
46WIDGET_CONTROL,event.top,GET_UVALUE=pState
47;prompt user to select files with native file selection dialog:
48if (*pState).gifFlag EQ 1 then filter=['*.JPG','*.jpg','*.JPEG','*.jpeg','*.JPE','*.jpe',$
49  '*.JFIF','*.jfif','*.GIF','*.gif','*.BMP','*.bmp','*.TIF','*.tif','*.TIFF','*.tiff',$
50  '*.PNG','*.png'] else $
51  filter=['*.JPG','*.jpg','*.JPEG','*.jpeg','*.JPE','*.jpe','*.JFIF','*.jfif','*.BMP','*.bmp',$
52  '*.TIF','*.tif','*.TIFF','*.tiff','*.PNG','*.png']
53files=DIALOG_PICKFILE(TITLE='Select picture files to open',/MULTIPLE_FILES,$
54                      FILTER=filter,GET_PATH=path)
55;if user hit "Cancel" then return to previous program level:
56if (files[0] EQ '') then RETURN
57;change current working directory to location of selected files:
58CD,path
59nFiles=N_ELEMENTS(files)
60(*pState).nFiles=nFiles
61(*pState).increment=100./nFiles
62files=files[SORT(files)]
63;create status report dialog:
64xCenter=(*pState).screenSize[0]/2
65yCenter=(*pState).screenSize[1]/2
66tlb2=WIDGET_BASE(TITLE='Status Report',/COLUMN,/ALIGN_CENTER,TLB_FRAME_ATTR=19,/MODAL,$
67                 GROUP_LEADER=(*pState).tlb)
68  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
69  label1=WIDGET_LABEL(tlb2,VALUE='LOADING SELECTED IMAGE FILES INTO MEMORY')
70  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
71  label2=WIDGET_LABEL(tlb2,VALUE='*** PLEASE WAIT ***')
72  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
73  statusBase=WIDGET_BASE(tlb2,/ROW,/FRAME,/BASE_ALIGN_CENTER,/ALIGN_CENTER,EVENT_PRO='image_viewer_timer')
74    cancelBut=WIDGET_BUTTON(statusBase,VALUE='Cancel',EVENT_PRO='image_viewer_cancel')
75    progressLabel=WIDGET_LABEL(statusBase,Value=' Progress :  0 ')
76    statusSlider=WIDGET_SLIDER(statusBase,SENSITIVE=0,TITLE=' ',XSIZE=200)
77    percentLabel=WIDGET_LABEL(statusBase,VALUE=' 100 %')
78geom=WIDGET_INFO(tlb2,/GEOMETRY)
79xHalfSize=geom.Scr_XSize/2
80yHalfSize=geom.Scr_YSize/2
81WIDGET_CONTROL,tlb2,XOFFSET=xCenter-xHalfSize,YOFFSET=yCenter-yHalfSize
82WIDGET_CONTROL,tlb2,/REALIZE
83(*pState).statusBase=statusBase
84(*pState).statusSlider=statusSlider
85WIDGET_CONTROL,tlb2,SET_UVALUE=pState
86;reset settings of GUI:
87WIDGET_CONTROL,(*pState).fileText,SET_VALUE=''
88WIDGET_CONTROL,(*pState).imageDraw,GET_VALUE=drawID
89WSET,drawID
90TVLCT,0,0,0,0
91ERASE
92;re-create thumbnails base with appropriate size for number of images selected:
93nRows = CEIL (nFiles / 3.0)
94WIDGET_CONTROL,(*pState).thumbBase,/DESTROY
95(*pState).thumbBase=WIDGET_BASE((*pState).controlsBase,/COLUMN,/ALIGN_TOP,/FRAME,XSIZE=260,$
96                                YSIZE=(nRows*89),/SCROLL,X_SCROLL_SIZE=260,Y_SCROLL_SIZE=650)
97;initialize pointer array to reference image data:
98numImages=N_ELEMENTS(*(*pState).images)
99if numImages NE 0 then PTR_FREE,*(*pState).images
100*(*pState).images=PTRARR(nFiles,/ALLOCATE_HEAP)
101*(*pState).files=files
102;loop through each file:
103(*pState).timer=1B
104WIDGET_CONTROL,statusBase,TIMER=0.01
105END
106;*********************************************************************************************
107
108
109;*********************************************************************************************
110;+
111; @param event {in}{required}
112;-
113PRO IMAGE_VIEWER_OPEN_FOLDER,event
114;THIS PROCEDURE IS CALLED WHEN A USER SELECTS "File > Open All In Folder" FROM THE MAIN MENU
115;error handling:
116;
117  compile_opt idl2, strictarrsubs
118;
119!ERROR_STATE.CODE=0
120CATCH,error
121if error NE 0 then begin
122  HELP,/LAST_MESSAGE,OUTPUT=traceback
123  messageStr=['Error Caught :','',traceback]
124  dummy=DIALOG_MESSAGE(messageStr,/ERROR)
125  ;if status report dialog is still active, destroy it:
126  if SIZE(tlb,/TYPE) NE 0 then WIDGET_CONTROL,tlb,/DESTROY
127  RETURN
128endif
129;obtain state structure for top-level-base from its UVALUE:
130WIDGET_CONTROL,event.top,GET_UVALUE=pState
131;prompt user to select files with native file selection dialog:
132folder=DIALOG_PICKFILE(TITLE='Select folder that contains picture files',/DIRECTORY)
133;if user hit "Cancel" then return to previous program level:
134if folder EQ '' then RETURN
135;change current working directory to location of selected files:
136CD,folder
137if (*pState).gifFlag EQ 1 then filter=['*.JPG','*.JPEG','*.JPE','*.JFIF','*.GIF','*.BMP',$
138  '*.TIF','*.TIFF','*.PNG'] else $
139  filter=['*.JPG','*.JPEG','*.JPE','*.JFIF','*.BMP','*.TIF','*.TIFF','*.PNG']
140files=FILE_SEARCH(filter,COUNT=nFiles,/FOLD_CASE,/FULLY_QUALIFY_PATH,/NOSORT)
141if nFiles EQ 0 then begin
142  dummy=DIALOG_MESSAGE('No valid picture files were found in the selected folder !',/INFO)
143  RETURN
144endif
145(*pState).nFiles=nFiles
146(*pState).increment=100./nFiles
147files=files[SORT(files)]
148;create status report dialog:
149xCenter=(*pState).screenSize[0]/2
150yCenter=(*pState).screenSize[1]/2
151tlb2=WIDGET_BASE(TITLE='Status Report',/COLUMN,/ALIGN_CENTER,TLB_FRAME_ATTR=19,/MODAL,$
152                 GROUP_LEADER=(*pState).tlb)
153  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
154  label1=WIDGET_LABEL(tlb2,VALUE='LOADING SELECTED IMAGE FILES INTO MEMORY')
155  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
156  label2=WIDGET_LABEL(tlb2,VALUE='*** PLEASE WAIT ***')
157  spacer=WIDGET_LABEL(tlb2,VALUE=' ')
158  statusBase=WIDGET_BASE(tlb2,/ROW,/FRAME,/BASE_ALIGN_CENTER,/ALIGN_CENTER,EVENT_PRO='image_viewer_timer')
159    cancelBut=WIDGET_BUTTON(statusBase,VALUE='Cancel',EVENT_PRO='image_viewer_cancel')
160    progressLabel=WIDGET_LABEL(statusBase,Value=' Progress :  0 ')
161    statusSlider=WIDGET_SLIDER(statusBase,SENSITIVE=0,TITLE=' ',XSIZE=200)
162    percentLabel=WIDGET_LABEL(statusBase,VALUE=' 100 %')
163geom=WIDGET_INFO(tlb2,/GEOMETRY)
164xHalfSize=geom.Scr_XSize/2
165yHalfSize=geom.Scr_YSize/2
166WIDGET_CONTROL,tlb2,XOFFSET=xCenter-xHalfSize,YOFFSET=yCenter-yHalfSize
167WIDGET_CONTROL,tlb2,/REALIZE
168(*pState).statusBase=statusBase
169(*pState).statusSlider=statusSlider
170WIDGET_CONTROL,tlb2,SET_UVALUE=pState
171;reset settings of GUI:
172WIDGET_CONTROL,(*pState).fileText,SET_VALUE=''
173WIDGET_CONTROL,(*pState).imageDraw,GET_VALUE=drawID
174WSET,drawID
175TVLCT,0,0,0,0
176ERASE
177;re-create thumbnails base with appropriate size for number of images selected:
178nRows = CEIL (nFiles / 3.0)
179WIDGET_CONTROL,(*pState).thumbBase,/DESTROY
180(*pState).thumbBase=WIDGET_BASE((*pState).controlsBase,/COLUMN,/ALIGN_TOP,/FRAME,XSIZE=260,$
181                                YSIZE=(nRows*89),/SCROLL,X_SCROLL_SIZE=260,Y_SCROLL_SIZE=650)
182;initialize pointer array to reference image data:
183numImages=N_ELEMENTS(*(*pState).images)
184if numImages NE 0 then PTR_FREE,*(*pState).images
185*(*pState).images=PTRARR(nFiles,/ALLOCATE_HEAP)
186*(*pState).files=files
187;loop through each file:
188(*pState).timer=1B
189WIDGET_CONTROL,statusBase,TIMER=0.01
190END
191;*********************************************************************************************
192
193
194;*********************************************************************************************
195;+
196; @param event {in}{required}
197;-
198PRO IMAGE_VIEWER_CANCEL,event
199;obtain state structure for top-level-base from its UVALUE:
200;
201  compile_opt idl2, strictarrsubs
202;
203WIDGET_CONTROL,event.top,GET_UVALUE=pState
204;shut-off timer:
205(*pState).timer=0B
206END
207;*********************************************************************************************
208
209
210;*********************************************************************************************
211;+
212; @param event {in}{required}
213;-
214PRO IMAGE_VIEWER_TIMER,event
215;obtain state structure for top-level-base from its UVALUE:
216;
217  compile_opt idl2, strictarrsubs
218;
219WIDGET_CONTROL,event.top,GET_UVALUE=pState
220if (*pState).timer EQ 1 then begin ;continue processing files:
221  if (*pState).currFile LE (*pState).nFiles-1 then begin
222    i=(*pState).currFile
223    extension=STRUPCASE(STRMID((*(*pState).files)[i],STRPOS((*(*pState).files)[i],'.',/REVERSE_SEARCH)+1))
224    if extension EQ 'JPG' or extension EQ 'JPEG' or extension EQ 'JPE' or extension EQ 'JFIF' then begin
225      result=QUERY_JPEG((*(*pState).files)[i],info)
226      if result NE 1 then begin
227        dummy=DIALOG_MESSAGE(['Selected file:','',(*(*pState).files)[i],'',$
228                              'does not appear to be a valid JPEG file !'],/ERROR)
229        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
230        if (*pState).currFile EQ (*pState).nFiles-1 then begin
231          ;last file ... terminate timer:
232          (*pState).timer=0B
233          (*pState).currFile=0L
234          WIDGET_CONTROL,event.top,/DESTROY
235        endif else begin
236          ;increment file number and update progress slider:
237          (*pState).currFile=(*pState).currFile+1
238          progressValue = ROUND((i+1)*(*pState).increment) < 100
239          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
240          ;fire off timer again:
241          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
242        endelse
243        RETURN
244      endif
245      if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
246      TVLCT,0,0,0,0
247      thumbDraw=WIDGET_DRAW((*pState).rowBase,/BUTTON_EVENTS,RETAIN=2,XSIZE=80,YSIZE=80,$
248                            EVENT_PRO='image_viewer_thumbs',UVALUE=(i+1),UNAME=STRTRIM(i+1,2))
249      WAIT,0.01
250      WIDGET_CONTROL,thumbDraw,GET_VALUE=drawID
251      WSET,drawID
252      if info.channels EQ 3 then begin
253        READ_JPEG,(*(*pState).files)[i],image,TRUE=1
254        if (*pState).colorMode EQ 'PSEUDO' then begin
255          image=COLOR_QUAN(TEMPORARY(image),1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
256          red=[[0],TEMPORARY(red)]
257          green=[[0],TEMPORARY(green)]
258          blue=[[0],TEMPORARY(blue)]
259          image=TEMPORARY(image)+1B
260          imageColorMode='PSEUDO'
261          TVLCT,red,green,blue
262        endif else begin
263          imageColorMode='TRUE'
264          red=0B
265          green=0B
266          blue=0B
267          DEVICE,DECOMPOSED=1
268        endelse
269      endif
270      if info.channels EQ 1 then begin
271        READ_JPEG,(*(*pState).files)[i],image
272        if (*pState).colorMode EQ 'PSEUDO' then image=BYTSCL(TEMPORARY(image),TOP=!D.TABLE_SIZE-1)
273        red=BINDGEN(!D.TABLE_SIZE)
274        green=BINDGEN(!D.TABLE_SIZE)
275        blue=BINDGEN(!D.TABLE_SIZE)
276        imageColorMode='PSEUDO'
277        if (*pState).colorMode EQ 'TRUE' then DEVICE,DECOMPOSED=0
278        TVLCT,red,green,blue
279      endif
280      ratio=FLOAT(info.dimensions[0])/info.dimensions[1]
281      ;resize image if necessary:
282      if info.dimensions[0] GT 710 or info.dimensions[1] GT 650 then begin
283        if ratio GE 1.09231 then begin
284          factor=(710./info.dimensions[0])
285          xSize=710
286          ySize=ROUND(info.dimensions[1]*factor)
287          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,710,ySize)
288          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,710,ySize)
289        endif else begin
290          factor=(650./info.dimensions[1])
291          xSize=ROUND(info.dimensions[0]*factor)
292          ySize=650
293          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,xSize,650)
294          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,xSize,650)
295        endelse
296      endif else begin
297        xSize=info.dimensions[0]
298        ySize=info.dimensions[1]
299      endelse
300      ;create thumbnail:
301      if xSize GT 80 or ySize GT 80 then begin
302        if ratio GE 1.09231 then begin
303          factor=(80./info.dimensions[0])
304          thumbxSize=80
305          thumbySize=ROUND(info.dimensions[1]*factor)
306          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,80,thumbySize)
307          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,80,thumbySize)
308        endif else begin
309          factor=(80./info.dimensions[1])
310          thumbxSize=ROUND(info.dimensions[0]*factor)
311          thumbySize=80
312          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,thumbxSize,80)
313          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,thumbxSize,80)
314        endelse
315        xOffset=ROUND((80-thumbxSize)/2.)
316        yOffset=ROUND((80-thumbySize)/2.)
317      endif else begin
318        bottom=FLOOR((80-ySize)/2.)
319        top=bottom+ySize-1
320        left=FLOOR((80-xSize)/2.)
321        right=left+xSize-1
322        if imageColorMode EQ 'PSEUDO' then begin
323          thumb=BYTARR(80,80)
324          thumb[left:right,bottom:top]=image
325        endif else begin ;imageColorMode EQ 'TRUE':
326          thumb=BYTARR(3,80,80)
327          thumb[*,left:right,bottom:top]=image
328        endelse
329        xOffset=0
330        yOffset=0
331      endelse
332      if imageColorMode EQ 'PSEUDO' then TV,TEMPORARY(thumb),xOffset,yOffset
333      if imageColorMode EQ 'TRUE' then TV,TEMPORARY(thumb),xOffset,yOffset,TRUE=1
334      imageStruct={image:TEMPORARY(image),xSize:xSize,ySize:ySize,imageColorMode:imageColorMode,$
335                   red:TEMPORARY(red),green:TEMPORARY(green),blue:TEMPORARY(blue)}
336      *(*(*pState).images)[i]=TEMPORARY(imageStruct)
337    endif
338    ;
339    if extension EQ 'GIF' and (*pState).gifFlag EQ 1 then begin
340      result=QUERY_GIF((*(*pState).files)[i],info)
341      if result NE 1 then begin
342        dummy=DIALOG_MESSAGE(['An error has occurred.  This is due to one of the following reasons :','',$
343                              '1) This installation of IDL is not licensed for GIF technology patented',$
344                              'by the Unisys Corporation.','',$
345                              '2) Selected file:','',(*(*pState).files)[i],'',$
346                              'is not a valid GIF file.'],/ERROR)
347        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
348        if (*pState).currFile EQ (*pState).nFiles-1 then begin
349          ;last file ... terminate timer:
350          (*pState).timer=0B
351          (*pState).currFile=0L
352          WIDGET_CONTROL,event.top,/DESTROY
353        endif else begin
354          ;increment file number and update progress slider:
355          (*pState).currFile=(*pState).currFile+1
356          progressValue = ROUND((i+1)*(*pState).increment) < 100
357          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
358          ;fire off timer again:
359          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
360        endelse
361        RETURN
362      endif
363      if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
364      TVLCT,0,0,0,0
365      thumbDraw=WIDGET_DRAW((*pState).rowBase,/BUTTON_EVENTS,RETAIN=2,XSIZE=80,YSIZE=80,$
366                            EVENT_PRO='image_viewer_thumbs',UVALUE=(i+1),UNAME=STRTRIM(i+1,2))
367      WAIT,0.01
368      WIDGET_CONTROL,thumbDraw,GET_VALUE=drawID
369      WSET,drawID
370      if info.has_palette EQ 1 then begin
371        READ_GIF,(*(*pState).files)[i],image,red,green,blue
372        trueColorImage=BYTARR(3,info.dimensions[0],info.dimensions[1])
373        trueColorImage[0,*,*]=red[image]
374        trueColorImage[1,*,*]=green[image]
375        trueColorImage[2,*,*]=blue[image]
376        image=COLOR_QUAN(TEMPORARY(trueColorImage),1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
377        red=[[0],TEMPORARY(red)]
378        green=[[0],TEMPORARY(green)]
379        blue=[[0],TEMPORARY(blue)]
380        image=TEMPORARY(image)+1B
381      endif
382      if info.has_palette EQ 0 then begin
383        READ_GIF,(*(*pState).files)[i],image
384        if (*pState).colorMode EQ 'PSEUDO' then image=BYTSCL(TEMPORARY(image),TOP=!D.TABLE_SIZE-1)
385        red=BINDGEN(!D.TABLE_SIZE)
386        green=BINDGEN(!D.TABLE_SIZE)
387        blue=BINDGEN(!D.TABLE_SIZE)
388      endif
389      if (*pState).colorMode EQ 'TRUE' then DEVICE,DECOMPOSED=0
390      TVLCT,red,green,blue
391      imageColorMode='PSEUDO'
392      ratio=FLOAT(info.dimensions[0])/info.dimensions[1]
393      ;resize image if necessary:
394      if info.dimensions[0] GT 710 or info.dimensions[1] GT 650 then begin
395        if ratio GE 1.09231 then begin
396          factor=(710./info.dimensions[0])
397          xSize=710
398          ySize=ROUND(info.dimensions[1]*factor)
399          image=CONGRID(image,710,ySize)
400        endif else begin
401          factor=(650./info.dimensions[1])
402          xSize=ROUND(info.dimensions[0]*factor)
403          ySize=650
404          image=CONGRID(image,xSize,650)
405        endelse
406      endif else begin
407        xSize=info.dimensions[0]
408        ySize=info.dimensions[1]
409      endelse
410      ;create thumbnail:
411      if xSize GT 80 or ySize GT 80 then begin
412        if ratio GE 1.09231 then begin
413          factor=(80./info.dimensions[0])
414          thumbxSize=80
415          thumbySize=ROUND(info.dimensions[1]*factor)
416          thumb=CONGRID(image,80,thumbySize)
417        endif else begin
418          factor=(80./info.dimensions[1])
419          thumbxSize=ROUND(info.dimensions[0]*factor)
420          thumbySize=80
421          thumb=CONGRID(image,thumbxSize,80)
422        endelse
423        xOffset=ROUND((80-thumbxSize)/2.)
424        yOffset=ROUND((80-thumbySize)/2.)
425      endif else begin
426        bottom=FLOOR((80-ySize)/2.)
427        top=bottom+ySize-1
428        left=FLOOR((80-xSize)/2.)
429        right=left+xSize-1
430        thumb=BYTARR(80,80)
431        thumb[left:right,bottom:top]=image
432        xOffset=0
433        yOffset=0
434      endelse
435      TV,TEMPORARY(thumb),xOffset,yOffset
436      imageStruct={image:TEMPORARY(image),xSize:xSize,ySize:ySize,imageColorMode:imageColorMode,$
437                   red:TEMPORARY(red),green:TEMPORARY(green),blue:TEMPORARY(blue)}
438      *(*(*pState).images)[i]=TEMPORARY(imageStruct)
439    endif
440    ;
441    if extension EQ 'BMP' then begin
442      result=QUERY_BMP((*(*pState).files)[i],info)
443      if result NE 1 then begin
444        dummy=DIALOG_MESSAGE(['An error has occurred.  This is due to one of the following reasons :','',$
445                              '1) The selected BMP file is an "OS2" format file, which is not supported',$
446                              'by IMAGE_VIEWER.','',$
447                              '2) Selected file:','',(*(*pState).files)[i],'',$
448                              'is not a valid BMP file.'],/ERROR)
449        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
450        if (*pState).currFile EQ (*pState).nFiles-1 then begin
451          ;last file ... terminate timer:
452          (*pState).timer=0B
453          (*pState).currFile=0L
454          WIDGET_CONTROL,event.top,/DESTROY
455        endif else begin
456          ;increment file number and update progress slider:
457          (*pState).currFile=(*pState).currFile+1
458          progressValue = ROUND((i+1)*(*pState).increment) < 100
459          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
460          ;fire off timer again:
461          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
462        endelse
463        RETURN
464      endif
465      if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
466      TVLCT,0,0,0,0
467      thumbDraw=WIDGET_DRAW((*pState).rowBase,/BUTTON_EVENTS,RETAIN=2,XSIZE=80,YSIZE=80,$
468                            EVENT_PRO='image_viewer_thumbs',UVALUE=(i+1),UNAME=STRTRIM(i+1,2))
469      WAIT,0.01
470      WIDGET_CONTROL,thumbDraw,GET_VALUE=drawID
471      WSET,drawID
472      if info.channels EQ 3 then begin
473        image=READ_BMP((*(*pState).files)[i],/RGB)
474        if (*pState).colorMode EQ 'PSEUDO' then begin
475          image=COLOR_QUAN(image,1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
476          red=[[0],TEMPORARY(red)]
477          green=[[0],TEMPORARY(green)]
478          blue=[[0],TEMPORARY(blue)]
479          image=TEMPORARY(image)+1B
480          imageColorMode='PSEUDO'
481          TVLCT,red,green,blue
482        endif else begin
483          imageColorMode='TRUE'
484          red=0B
485          green=0B
486          blue=0B
487          DEVICE,DECOMPOSED=1
488        endelse
489      endif
490      if info.channels EQ 1 then begin
491        image=READ_BMP((*(*pState).files)[i],red,green,blue)
492        if info.has_palette EQ 0 then begin
493          if (*pState).colorMode EQ 'PSEUDO' then image=BYTSCL(TEMPORARY(image),TOP=!D.TABLE_SIZE-1)
494          red=BINDGEN(!D.TABLE_SIZE)
495          green=BINDGEN(!D.TABLE_SIZE)
496          blue=BINDGEN(!D.TABLE_SIZE)
497        endif else begin
498          trueColorImage=BYTARR(3,info.dimensions[0],info.dimensions[1])
499          trueColorImage[0,*,*]=red[image]
500          trueColorImage[1,*,*]=green[image]
501          trueColorImage[2,*,*]=blue[image]
502          image=COLOR_QUAN(TEMPORARY(trueColorImage),1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
503          red=[[0],TEMPORARY(red)]
504          green=[[0],TEMPORARY(green)]
505          blue=[[0],TEMPORARY(blue)]
506          image=TEMPORARY(image)+1B
507        endelse
508        imageColorMode='PSEUDO'
509        if (*pState).colorMode EQ 'TRUE' then DEVICE,DECOMPOSED=0
510        TVLCT,red,green,blue
511      endif
512      ratio=FLOAT(info.dimensions[0])/info.dimensions[1]
513      ;resize image if necessary:
514      if info.dimensions[0] GT 710 or info.dimensions[1] GT 650 then begin
515        if ratio GE 1.09231 then begin
516          factor=(710./info.dimensions[0])
517          xSize=710
518          ySize=ROUND(info.dimensions[1]*factor)
519          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,710,ySize)
520          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,710,ySize)
521        endif else begin
522          factor=(650./info.dimensions[1])
523          xSize=ROUND(info.dimensions[0]*factor)
524          ySize=650
525          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,xSize,650)
526          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,xSize,650)
527        endelse
528      endif else begin
529        xSize=info.dimensions[0]
530        ySize=info.dimensions[1]
531      endelse
532      ;create thumbnail:
533      if xSize GT 80 or ySize GT 80 then begin
534        if ratio GE 1.09231 then begin
535          factor=(80./info.dimensions[0])
536          thumbxSize=80
537          thumbySize=ROUND(info.dimensions[1]*factor)
538          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,80,thumbySize)
539          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,80,thumbySize)
540        endif else begin
541          factor=(80./info.dimensions[1])
542          thumbxSize=ROUND(info.dimensions[0]*factor)
543          thumbySize=80
544          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,thumbxSize,80)
545          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,thumbxSize,80)
546        endelse
547        xOffset=ROUND((80-thumbxSize)/2.)
548        yOffset=ROUND((80-thumbySize)/2.)
549      endif else begin
550        bottom=FLOOR((80-ySize)/2.)
551        top=bottom+ySize-1
552        left=FLOOR((80-xSize)/2.)
553        right=left+xSize-1
554        if imageColorMode EQ 'PSEUDO' then begin
555          thumb=BYTARR(80,80)
556          thumb[left:right,bottom:top]=image
557        endif else begin ;imageColorMode EQ 'TRUE':
558          thumb=BYTARR(3,80,80)
559          thumb[*,left:right,bottom:top]=image
560        endelse
561        xOffset=0
562        yOffset=0
563      endelse
564      if imageColorMode EQ 'PSEUDO' then TV,TEMPORARY(thumb),xOffset,yOffset
565      if imageColorMode EQ 'TRUE' then TV,TEMPORARY(thumb),xOffset,yOffset,TRUE=1
566      imageStruct={image:TEMPORARY(image),xSize:xSize,ySize:ySize,imageColorMode:imageColorMode,$
567                   red:TEMPORARY(red),green:TEMPORARY(green),blue:TEMPORARY(blue)}
568      *(*(*pState).images)[i]=TEMPORARY(imageStruct)
569    endif
570    ;
571    if extension EQ 'TIF' or extension EQ 'TIFF' then begin
572      result=QUERY_TIFF((*(*pState).files)[i],info)
573      if result NE 1 then begin
574        dummy=DIALOG_MESSAGE(['An error has occurred.  This is due to one of the following reasons :','',$
575              '1) The selected TIFF file has LZW (Lempel-Zif-Welch) compression and this installation',$
576              'of IDL is not licensed for TIFF LZW technology patented by the Unisys Corporation.','',$
577              '2) Selected file:','',(*(*pState).files)[i],'',$
578              'is not a valid TIFF file.'],/ERROR)
579        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
580        if (*pState).currFile EQ (*pState).nFiles-1 then begin
581          ;last file ... terminate timer:
582          (*pState).timer=0B
583          (*pState).currFile=0L
584          WIDGET_CONTROL,event.top,/DESTROY
585        endif else begin
586          ;increment file number and update progress slider:
587          (*pState).currFile=(*pState).currFile+1
588          progressValue = ROUND((i+1)*(*pState).increment) < 100
589          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
590          ;fire off timer again:
591          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
592        endelse
593        RETURN
594      endif
595      if info.orientation NE 0 and info.orientation NE 1 and info.orientation NE 4 then begin
596        dummy=DIALOG_MESSAGE('IMAGE_VIEWER only works with standard orientation TIFF files !',/ERROR)
597        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
598        if (*pState).currFile EQ (*pState).nFiles-1 then begin
599          ;last file ... terminate timer:
600          (*pState).timer=0B
601          (*pState).currFile=0L
602          WIDGET_CONTROL,event.top,/DESTROY
603        endif else begin
604          ;increment file number and update progress slider:
605          (*pState).currFile=(*pState).currFile+1
606          progressValue = ROUND((i+1)*(*pState).increment) < 100
607          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
608          ;fire off timer again:
609          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
610        endelse
611        RETURN
612      endif
613      if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
614      TVLCT,0,0,0,0
615      thumbDraw=WIDGET_DRAW((*pState).rowBase,/BUTTON_EVENTS,RETAIN=2,XSIZE=80,YSIZE=80,$
616                            EVENT_PRO='image_viewer_thumbs',UVALUE=(i+1),UNAME=STRTRIM(i+1,2))
617      WAIT,0.01
618      WIDGET_CONTROL,thumbDraw,GET_VALUE=drawID
619      WSET,drawID
620      if info.channels EQ 3 then begin
621        image=READ_TIFF((*(*pState).files)[i],INTERLEAVE=0,ORDER=order,IMAGE_INDEX=0)
622        if info.pixel_type NE 1 then image=BYTSCL(TEMPORARY(image))
623        if order EQ 1 then begin
624          ;flip image:
625          rImage=REFORM(image[0,*,*])
626          rImage=ROTATE(rImage,7)
627          gImage=REFORM(image[1,*,*])
628          gImage=ROTATE(gImage,7)
629          bImage=REFORM(image[2,*,*])
630          bImage=ROTATE(bImage,7)
631          image=BYTARR(3,info.dimensions[0],info.dimensions[1])
632          image[0,*,*]=TEMPORARY(rImage)
633          image[1,*,*]=TEMPORARY(gImage)
634          image[2,*,*]=TEMPORARY(bImage)
635        endif
636        if (*pState).colorMode EQ 'PSEUDO' then begin
637          image=COLOR_QUAN(image,1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
638          red=[[0],TEMPORARY(red)]
639          green=[[0],TEMPORARY(green)]
640          blue=[[0],TEMPORARY(blue)]
641          image=TEMPORARY(image)+1B
642          imageColorMode='PSEUDO'
643          TVLCT,red,green,blue
644        endif else begin
645          imageColorMode='TRUE'
646          red=0B
647          green=0B
648          blue=0B
649          DEVICE,DECOMPOSED=1
650        endelse
651      endif
652      if info.channels EQ 1 then begin
653        image=READ_TIFF((*(*pState).files)[i],red,green,blue,ORDER=order,IMAGE_INDEX=0)
654        if info.pixel_type NE 1 then image=BYTSCL(TEMPORARY(image))
655        if order EQ 1 then begin
656          ;flip image:
657          image=ROTATE(TEMPORARY(image),7)
658        endif
659        if info.has_palette EQ 0 then begin
660          if (*pState).colorMode EQ 'PSEUDO' then image=BYTSCL(TEMPORARY(image),TOP=!D.TABLE_SIZE-1)
661          red=BINDGEN(!D.TABLE_SIZE)
662          green=BINDGEN(!D.TABLE_SIZE)
663          blue=BINDGEN(!D.TABLE_SIZE)
664        endif else begin
665          trueColorImage=BYTARR(3,info.dimensions[0],info.dimensions[1])
666          trueColorImage[0,*,*]=red[image]
667          trueColorImage[1,*,*]=green[image]
668          trueColorImage[2,*,*]=blue[image]
669          image=COLOR_QUAN(TEMPORARY(trueColorImage),1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
670          red=[[0],TEMPORARY(red)]
671          green=[[0],TEMPORARY(green)]
672          blue=[[0],TEMPORARY(blue)]
673          image=TEMPORARY(image)+1B
674        endelse
675        imageColorMode='PSEUDO'
676        if (*pState).colorMode EQ 'TRUE' then DEVICE,DECOMPOSED=0
677        TVLCT,red,green,blue
678      endif
679      ratio=FLOAT(info.dimensions[0])/info.dimensions[1]
680      ;resize image if necessary:
681      if info.dimensions[0] GT 710 or info.dimensions[1] GT 650 then begin
682        if ratio GE 1.09231 then begin
683          factor=(710./info.dimensions[0])
684          xSize=710
685          ySize=ROUND(info.dimensions[1]*factor)
686          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,710,ySize)
687          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,710,ySize)
688        endif else begin
689          factor=(650./info.dimensions[1])
690          xSize=ROUND(info.dimensions[0]*factor)
691          ySize=650
692          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,xSize,650)
693          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,xSize,650)
694        endelse
695      endif else begin
696        xSize=info.dimensions[0]
697        ySize=info.dimensions[1]
698      endelse
699      ;create thumbnail:
700      if xSize GT 80 or ySize GT 80 then begin
701        if ratio GE 1.09231 then begin
702          factor=(80./info.dimensions[0])
703          thumbxSize=80
704          thumbySize=ROUND(info.dimensions[1]*factor)
705          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,80,thumbySize)
706          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,80,thumbySize)
707        endif else begin
708          factor=(80./info.dimensions[1])
709          thumbxSize=ROUND(info.dimensions[0]*factor)
710          thumbySize=80
711          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,thumbxSize,80)
712          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,thumbxSize,80)
713        endelse
714        xOffset=ROUND((80-thumbxSize)/2.)
715        yOffset=ROUND((80-thumbySize)/2.)
716      endif else begin
717        bottom=FLOOR((80-ySize)/2.)
718        top=bottom+ySize-1
719        left=FLOOR((80-xSize)/2.)
720        right=left+xSize-1
721        if imageColorMode EQ 'PSEUDO' then begin
722          thumb=BYTARR(80,80)
723          thumb[left:right,bottom:top]=image
724        endif else begin ;imageColorMode EQ 'TRUE':
725          thumb=BYTARR(3,80,80)
726          thumb[*,left:right,bottom:top]=image
727        endelse
728        xOffset=0
729        yOffset=0
730      endelse
731      if imageColorMode EQ 'PSEUDO' then TV,TEMPORARY(thumb),xOffset,yOffset
732      if imageColorMode EQ 'TRUE' then TV,TEMPORARY(thumb),xOffset,yOffset,TRUE=1
733      imageStruct={image:TEMPORARY(image),xSize:xSize,ySize:ySize,imageColorMode:imageColorMode,$
734                   red:TEMPORARY(red),green:TEMPORARY(green),blue:TEMPORARY(blue)}
735      *(*(*pState).images)[i]=TEMPORARY(imageStruct)
736    endif
737    ;
738    if extension EQ 'PNG' then begin
739      result=QUERY_PNG((*(*pState).files)[i],info)
740      if result NE 1 then begin
741        dummy=DIALOG_MESSAGE(['Selected file:','',(*(*pState).files)[i],'',$
742                              'does not appear to be a valid PNG file !'],/ERROR)
743        if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
744        if (*pState).currFile EQ (*pState).nFiles-1 then begin
745          ;last file ... terminate timer:
746          (*pState).timer=0B
747          (*pState).currFile=0L
748          WIDGET_CONTROL,event.top,/DESTROY
749        endif else begin
750          ;increment file number and update progress slider:
751          (*pState).currFile=(*pState).currFile+1
752          progressValue = ROUND((i+1)*(*pState).increment) < 100
753          WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
754          ;fire off timer again:
755          WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
756        endelse
757        RETURN
758      endif
759      if (i MOD 3) EQ 0 then (*pState).rowBase=WIDGET_BASE((*pState).thumbBase,/ROW,/ALIGN_LEFT)
760      TVLCT,0,0,0,0
761      thumbDraw=WIDGET_DRAW((*pState).rowBase,/BUTTON_EVENTS,RETAIN=2,XSIZE=80,YSIZE=80,$
762                            EVENT_PRO='image_viewer_thumbs',UVALUE=(i+1),UNAME=STRTRIM(i+1,2))
763      WAIT,0.01
764      WIDGET_CONTROL,thumbDraw,GET_VALUE=drawID
765      WSET,drawID
766      if info.channels EQ 3 then begin
767        image=READ_PNG((*(*pState).files)[i])
768        if info.pixel_type NE 1 then image=BYTSCL(TEMPORARY(image))
769        if (*pState).colorMode EQ 'PSEUDO' then begin
770          image=COLOR_QUAN(image,1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
771          red=[[0],TEMPORARY(red)]
772          green=[[0],TEMPORARY(green)]
773          blue=[[0],TEMPORARY(blue)]
774          image=TEMPORARY(image)+1B
775          imageColorMode='PSEUDO'
776          TVLCT,red,green,blue
777        endif else begin
778          imageColorMode='TRUE'
779          red=0B
780          green=0B
781          blue=0B
782          DEVICE,DECOMPOSED=1
783        endelse
784      endif
785      if info.channels EQ 1 then begin
786        image=READ_PNG((*(*pState).files)[i],red,green,blue)
787        if info.pixel_type NE 1 then image=BYTSCL(TEMPORARY(image))
788        if info.has_palette EQ 0 then begin
789          if (*pState).colorMode EQ 'PSEUDO' then image=BYTSCL(TEMPORARY(image),TOP=!D.TABLE_SIZE-1)
790          red=BINDGEN(!D.TABLE_SIZE)
791          green=BINDGEN(!D.TABLE_SIZE)
792          blue=BINDGEN(!D.TABLE_SIZE)
793        endif else begin
794          trueColorImage=BYTARR(3,info.dimensions[0],info.dimensions[1])
795          trueColorImage[0,*,*]=red[image]
796          trueColorImage[1,*,*]=green[image]
797          trueColorImage[2,*,*]=blue[image]
798          image=COLOR_QUAN(TEMPORARY(trueColorImage),1,red,green,blue,COLORS=!D.TABLE_SIZE-1)
799          red=[[0],TEMPORARY(red)]
800          green=[[0],TEMPORARY(green)]
801          blue=[[0],TEMPORARY(blue)]
802          image=TEMPORARY(image)+1B
803        endelse
804        imageColorMode='PSEUDO'
805        if (*pState).colorMode EQ 'TRUE' then DEVICE,DECOMPOSED=0
806        TVLCT,red,green,blue
807      endif
808      ratio=FLOAT(info.dimensions[0])/info.dimensions[1]
809      ;resize image if necessary:
810      if info.dimensions[0] GT 710 or info.dimensions[1] GT 650 then begin
811        if ratio GE 1.09231 then begin
812          factor=(710./info.dimensions[0])
813          xSize=710
814          ySize=ROUND(info.dimensions[1]*factor)
815          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,710,ySize)
816          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,710,ySize)
817        endif else begin
818          factor=(650./info.dimensions[1])
819          xSize=ROUND(info.dimensions[0]*factor)
820          ySize=650
821          if imageColorMode EQ 'PSEUDO' then image=CONGRID(image,xSize,650)
822          if imageColorMode EQ 'TRUE' then image=CONGRID(image,3,xSize,650)
823        endelse
824      endif else begin
825        xSize=info.dimensions[0]
826        ySize=info.dimensions[1]
827      endelse
828      ;create thumbnail:
829      if xSize GT 80 or ySize GT 80 then begin
830        if ratio GE 1.09231 then begin
831          factor=(80./info.dimensions[0])
832          thumbxSize=80
833          thumbySize=ROUND(info.dimensions[1]*factor)
834          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,80,thumbySize)
835          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,80,thumbySize)
836        endif else begin
837          factor=(80./info.dimensions[1])
838          thumbxSize=ROUND(info.dimensions[0]*factor)
839          thumbySize=80
840          if imageColorMode EQ 'PSEUDO' then thumb=CONGRID(image,thumbxSize,80)
841          if imageColorMode EQ 'TRUE' then thumb=CONGRID(image,3,thumbxSize,80)
842        endelse
843        xOffset=ROUND((80-thumbxSize)/2.)
844        yOffset=ROUND((80-thumbySize)/2.)
845      endif else begin
846        bottom=FLOOR((80-ySize)/2.)
847        top=bottom+ySize-1
848        left=FLOOR((80-xSize)/2.)
849        right=left+xSize-1
850        if imageColorMode EQ 'PSEUDO' then begin
851          thumb=BYTARR(80,80)
852          thumb[left:right,bottom:top]=image
853        endif else begin ;imageColorMode EQ 'TRUE':
854          thumb=BYTARR(3,80,80)
855          thumb[*,left:right,bottom:top]=image
856        endelse
857        xOffset=0
858        yOffset=0
859      endelse
860      if imageColorMode EQ 'PSEUDO' then TV,TEMPORARY(thumb),xOffset,yOffset
861      if imageColorMode EQ 'TRUE' then TV,TEMPORARY(thumb),xOffset,yOffset,TRUE=1
862      imageStruct={image:TEMPORARY(image),xSize:xSize,ySize:ySize,imageColorMode:imageColorMode,$
863                   red:TEMPORARY(red),green:TEMPORARY(green),blue:TEMPORARY(blue)}
864      *(*(*pState).images)[i]=TEMPORARY(imageStruct)
865    endif
866    ;increment file number and update progress slider:
867    (*pState).currFile=(*pState).currFile+1
868    progressValue = ROUND((i+1)*(*pState).increment) < 100
869    WIDGET_CONTROL,(*pState).statusSlider,SET_VALUE=progressValue
870    ;fire off timer again:
871    WIDGET_CONTROL,(*pState).statusBase,TIMER=0.01
872  endif else begin ;all files have already been read-in:
873    (*pState).timer=0B
874    (*pState).currFile=0L
875    WIDGET_CONTROL,event.top,/DESTROY
876  endelse
877endif else begin ;user hit "Cancel":
878  (*pState).currFile=0L
879  WIDGET_CONTROL,event.top,/DESTROY
880endelse
881END
882;*********************************************************************************************
883
884
885;*********************************************************************************************
886;+
887; @param event {in}{required}
888;-
889PRO IMAGE_VIEWER_EXIT,event
890;THIS PROCEDURE IS CALLED WHEN A USER SELECTS "File > Exit" FROM THE MAIN MENU
891;terminate the program by destroying the top-level-base (widgetID always stored in event.top):
892;
893  compile_opt idl2, strictarrsubs
894;
895WIDGET_CONTROL,event.top,/DESTROY
896END
897;*********************************************************************************************
898
899
900;*********************************************************************************************
901;+
902; @param event {in}{required}
903;-
904PRO IMAGE_VIEWER_HELP,event
905;THIS PROCEDURE IS CALLED WHEN A USER SELECTS "Help > Help on IMAGE_VIEWER"
906;FROM THE MAIN MENU
907;display a simple message:
908;
909  compile_opt idl2, strictarrsubs
910;
911messageStr=['IMAGE_VIEWER written by AEB, 2002.','',$
912            'The purpose of this program is to provide an interactive tool that can be used',$
913            'to view JPEG, BMP, GIF, PNG, and TIFF picture files.  In order to provide rapid',$
914            'viewing capabilities the images are loaded into memory, which can cause the',$
915            'initial file access to take a bit of time while the pictures are opened and',$
916            'thumbnails are created.']
917dummy=DIALOG_MESSAGE(messageStr,/info)
918END
919;*********************************************************************************************
920
921
922;*********************************************************************************************
923;+
924; @param event {in}{required}
925;-
926PRO IMAGE_VIEWER_THUMBS,event
927;THIS PROCEDURE IS CALLED WHEN A USER CLICKS ON ONE OF THE THUMBNAIL PICTURES
928;error handling:
929;
930  compile_opt idl2, strictarrsubs
931;
932!ERROR_STATE.CODE=0
933CATCH,error
934if error NE 0 then begin
935  HELP,/LAST_MESSAGE,OUTPUT=traceback
936  messageStr=['Error Caught :','',traceback]
937  dummy=DIALOG_MESSAGE(messageStr,/ERROR)
938  RETURN
939endif
940if event.press EQ 1 then begin
941  WIDGET_CONTROL,/HOURGLASS
942  ;obtain state structure for top-level-base from its UVALUE:
943  WIDGET_CONTROL,event.top,GET_UVALUE=pState
944  WIDGET_CONTROL,(*pState).imageDraw,GET_VALUE=drawID
945  WSET,drawID
946  TVLCT,0,0,0,0
947  ERASE
948  ;obtain current image data:
949  WIDGET_CONTROL,event.id,GET_UVALUE=fileID
950  imageStruct=*(*(*pState).images)[fileID-1]
951  xOffset=ROUND((710-imageStruct.xSize)/2.)
952  yOffset=ROUND((650-imageStruct.ySize)/2.)
953  if (*pState).colorMode EQ 'PSEUDO' then begin
954    TVLCT,imageStruct.red,imageStruct.green,imageStruct.blue
955    TV,TEMPORARY(imageStruct.image),xOffset,yOffset
956  endif else begin ;(*pState).colorMode EQ 'TRUE':
957    if imageStruct.imageColorMode EQ 'PSEUDO' then begin
958      DEVICE,DECOMPOSED=0
959      TVLCT,imageStruct.red,imageStruct.green,imageStruct.blue
960      TV,TEMPORARY(imageStruct.image),xOffset,yOffset
961    endif else begin ;imageStruct.imageColorMode EQ 'TRUE':
962      DEVICE,DECOMPOSED=1
963      TV,TEMPORARY(imageStruct.image),xOffset,yOffset,TRUE=1
964    endelse
965  endelse
966  WIDGET_CONTROL,(*pState).fileText,SET_VALUE=(*(*pState).files)[fileID-1]
967endif
968END
969;*********************************************************************************************
970
971
972;*********************************************************************************************
973;+
974; @param widjetID {in}{required}
975;-
976PRO IMAGE_VIEWER_CLEANUP,widgetID
977;THIS PROCEDURE IS CALLED WHEN THE PROGRAM IS TERMINATED AND XMANAGER REGISTERS A CLEANUP:
978;obtain state structure for top-level-base from its uvalue:
979;
980  compile_opt idl2, strictarrsubs
981;
982WIDGET_CONTROL,widgetID,GET_UVALUE=pState
983;test for validity of state structure pointer:
984if PTR_VALID(pState) then begin
985  ;reset original settings:
986  !QUIET=(*pState).quietInit
987  !ORDER=(*pState).orderInit
988  !P.BACKGROUND=(*pState).backInit
989  CD,(*pState).currentDir
990  DEVICE,DECOMPOSED=(*pState).dc
991  TVLCT,(*pState).r,(*pState).g,(*pState).b
992  ;cleanup heap memory:
993  PTR_FREE,TEMPORARY((*pState).files)
994  numImages=N_ELEMENTS(*(*pState).images)
995  if numImages NE 0 then PTR_FREE,*(*pState).images
996  PTR_FREE,TEMPORARY((*pState).images)
997  PTR_FREE,TEMPORARY(pState)
998endif
999END
1000;*********************************************************************************************
1001
1002
1003;*********************************************************************************************
1004;+
1005; @param event {in}{required}
1006;-
1007PRO IMAGE_VIEWER_EVENT,event
1008;THIS PROCEDURE IS CALLED WHEN A USER RESIZES THE TOP-LEVEL BASE
1009;error handling:
1010;
1011  compile_opt idl2, strictarrsubs
1012;
1013!ERROR_STATE.CODE=0
1014CATCH,error
1015if error NE 0 then begin
1016  HELP,/LAST_MESSAGE,OUTPUT=traceback
1017  messageStr=['Error Caught :','',traceback]
1018  dummy=DIALOG_MESSAGE(messageStr,/ERROR)
1019  RETURN
1020endif
1021;obtain state structure for top-level-base from its UVALUE:
1022WIDGET_CONTROL,event.top,GET_UVALUE=pState
1023;reset widget size:
1024WIDGET_CONTROL,event.top,XSIZE=(*pState).tlbWidth,YSIZE=(*pState).tlbHeight,XOFFSET=0,YOFFSET=0
1025END
1026;*********************************************************************************************
1027
1028
1029;*********************************************************************************************
1030PRO IMAGE_VIEWER
1031;error handling:
1032;
1033  compile_opt idl2, strictarrsubs
1034;
1035!ERROR_STATE.CODE=0
1036CATCH,error
1037if error NE 0 then begin
1038  HELP,/LAST_MESSAGE,OUTPUT=traceback
1039  messageStr=['Error Caught :','',traceback]
1040  dummy=DIALOG_MESSAGE(messageStr,/ERROR)
1041  !QUIET=quietInit
1042  !ORDER=orderInit
1043  !P.BACKGROUND=backInit
1044  CD,currentDir
1045  RETURN
1046endif
1047;ignore beta and development build versions of IDL because string to float conversion will fail:
1048betaTest=STRPOS(STRLOWCASE(!VERSION.RELEASE),'beta')
1049buildTest=STRPOS(STRLOWCASE(!VERSION.RELEASE),'build')
1050;check to make sure the version of IDL running is 5.5 or newer:
1051if betaTest EQ -1 and buildTest EQ -1 then begin
1052  if FLOAT(!VERSION.RELEASE) LT 5.5 then begin
1053    dummy=dialog_message('IMAGE_VIEWER is only supported in IDL version 5.5 or newer.',/ERROR)
1054    RETURN
1055  endif
1056endif
1057;check to make sure there is adequate real estate:
1058DEVICE,GET_SCREEN_SIZE=screenSize
1059if (LONG(screenSize[0])*screenSize[1]) LT 786432 then begin
1060  messageStr=['IMAGE_VIEWER requires the computer monitor (Display) to be',$
1061              'configured in (1024 x 768) mode or better.']
1062  dummy=DIALOG_MESSAGE(messageStr)
1063  RETURN
1064endif
1065;check in auxiliary license:
1066result=LMGR("idl_tifflzw",VERSION='1.0')
1067result=LMGR("idl_gif",VERSION='1.0')
1068gifFlag=1B
1069if result NE 1 then begin
1070  messageStr=['The ability to read GIF (and TIFF LZW compressed) images requires',$
1071              'an auxiliary license in order to conform with the patent rights of the',$
1072              'Unisys Corporation.  IMAGE_VIEWER was unable to find the required',$
1073              'license in this installation.  Consequently, the ability to read GIF files',$
1074              'will be disabled.']
1075  dummy=DIALOG_MESSAGE(messageStr)
1076  gifFlag=0B
1077endif
1078;warn users of color flashing if monitor in PseudoColor mode:
1079if !D.N_COLORS LE 256 then begin
1080  messageStr=['The computer monitor (Display) is currently configured in 8-bit (256 Colors)',$
1081              'PseudoColor mode.  Due to the dynamic (read+write) nature of the colormap',$
1082              'system for this visual, when a colortable is loaded for an image it affects',$
1083              'all visible graphics windows, including the thumbnails of other images.  This',$
1084              'can lead to a phenomenon known as "color flashing".','',$
1085              'If possible, it is recommended that you exit this program, reconfigure your',$
1086              'monitor in 24-bit (TrueColor) mode or better, and restart IMAGE_VIEWER.']
1087  dummy=DIALOG_MESSAGE(messageStr)
1088endif
1089;obtain the current working directory:
1090CD,CURRENT=currentDir
1091if STRUPCASE(!VERSION.OS_FAMILY) EQ 'WINDOWS' then begin
1092  executeStr='cd "%USERPROFILE%\My Documents\My Pictures" & cd'
1093  SPAWN,executeStr,pathInit,/HIDE
1094  pathInit=pathInit[0]
1095  result=FILE_TEST(pathInit,/READ)
1096  if result EQ 1 then begin
1097    CD,pathInit
1098  endif else begin
1099    result=FILE_TEST('C:\My Documents\My Pictures',/READ)
1100    if result EQ 1 then begin
1101      CD,'C:\My Documents\My Pictures'
1102    endif else begin
1103      result=FILE_TEST('C:\',/READ)
1104      if result EQ 1 then CD,'C:\'
1105    endelse
1106  endelse
1107endif
1108;suppress informational messaging:
1109quietInit=!QUIET
1110!QUIET=1
1111;make sure color decomposition is disabled:
1112DEVICE,GET_DECOMPOSED=dc
1113if !D.N_COLORS GT 256 then colorMode='TRUE' else colorMode='PSEUDO'
1114;obtain the current color table:
1115TVLCT,r,g,b,/GET
1116LOADCT,0,/SILENT
1117;force !ORDER=0:
1118orderInit=!ORDER
1119!ORDER=0
1120;force !P.BACKGROUND=0:
1121backInit=!P.BACKGROUND
1122!P.BACKGROUND=0
1123;create GUI:
1124tlb=WIDGET_BASE(TITLE='Image Viewer',/ROW,MBAR=menuBar,/TLB_SIZE_EVENTS,XOFFSET=0,YOFFSET=0)
1125  fileMenu=WIDGET_BUTTON(menuBar,VALUE='File',/MENU)
1126    fileBttn1=WIDGET_BUTTON(fileMenu,VALUE='Open Picture Files',EVENT_PRO='image_viewer_open_files')
1127    fileBttn2=WIDGET_BUTTON(fileMenu,VALUE='Open All In Folder',EVENT_PRO='image_viewer_open_folder')
1128    fileBttn3=WIDGET_BUTTON(fileMenu,VALUE='Exit',EVENT_PRO='image_viewer_exit')
1129  helpMenu=WIDGET_BUTTON(menuBar,VALUE='Help',/MENU)
1130    helpBttn1=WIDGET_BUTTON(helpMenu,VALUE='Help on IMAGE_VIEWER',EVENT_PRO='image_viewer_help')
1131  controlsBase=WIDGET_BASE(tlb,/COLUMN,/FRAME,/ALIGN_TOP)
1132    labelBase=WIDGET_BASE(controlsBase,/COLUMN,SCR_XSIZE=280)
1133      thumbLabel=WIDGET_LABEL(labelBase,/ALIGN_CENTER,VALUE='CLICK ON THUMBNAIL TO VIEW IMAGE')
1134    thumbBase=WIDGET_BASE(controlsBase,/COLUMN,/ALIGN_TOP,/FRAME,XSIZE=260,YSIZE=700,$
1135                          /SCROLL,X_SCROLL_SIZE=260,Y_SCROLL_SIZE=650)
1136  imageBase=WIDGET_BASE(tlb,/COLUMN,/FRAME,/ALIGN_TOP)
1137    fileBase=WIDGET_BASE(imageBase,/ROW,/ALIGN_CENTER)
1138      fileLabel=WIDGET_LABEL(fileBase,VALUE='Current Image File = ')
1139      fileText=WIDGET_TEXT(fileBase,XSIZE=75,YSIZE=1)
1140    imageDraw=WIDGET_DRAW(imageBase,XSIZE=710,YSIZE=650,RETAIN=2)
1141;display the GUI on the computer monitor:
1142WIDGET_CONTROL,tlb,/REALIZE
1143;obtain the top-level base geometry:
1144tlbGeom=WIDGET_INFO(tlb,/GEOMETRY)
1145tlbWidth=tlbGeom.xsize
1146tlbHeight=tlbGeom.ysize
1147if tlbWidth EQ 0 or tlbHeight EQ 0 then begin
1148  WIDGET_CONTROL,tlb,TLB_GET_SIZE=tlbSize
1149  tlbWidth=tlbSize[0]
1150  tlbHeight=tlbSize[1]
1151endif
1152;create state structure to store information needed by the other event handling procedures:
1153pState=PTR_NEW({files:PTR_NEW(/ALLOCATE_HEAP),$
1154                images:PTR_NEW(/ALLOCATE_HEAP),$
1155                screenSize:screenSize,quietInit:quietInit,orderInit:orderInit,tlb:tlb,statusBase:0L,$
1156                controlsBase:controlsBase,thumbBase:thumbBase,fileText:fileText,timer:0B,nFiles:0L,$
1157                currentDir:currentDir,imageDraw:imageDraw,dc:dc,r:r,g:g,b:b,gifFlag:gifFlag,statusSlider:0L,$
1158                backInit:backInit,colorMode:colorMode,tlbWidth:tlbWidth,tlbHeight:tlbHeight,currFile:0L,$
1159                rowBase:0L,increment:0.0})
1160;store this state structure in the uvalue of the top-level-base
1161;so it can be obtained by other program units:
1162WIDGET_CONTROL,tlb,SET_UVALUE=pState
1163;register the GUI with the XMANAGER event handler routine:
1164XMANAGER,'image_viewer',tlb,CLEANUP='image_viewer_cleanup'
1165END
1166;*********************************************************************************************
Note: See TracBrowser for help on using the repository browser.