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

Last change on this file since 236 was 232, checked in by pinsard, 17 years ago

improvements/corrections of some *.pro headers

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