1 /* $Id$ */
2 
3 /*
4  * Copyright (c) 1988-1997 Sam Leffler
5  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
6  * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
7  *
8  * Permission to use, copy, modify, distribute, and sell this software and
9  * its documentation for any purpose is hereby granted without fee, provided
10  * that (i) the above copyright notices and this permission notice appear in
11  * all copies of the software and related documentation, and (ii) the names of
12  * Sam Leffler and Silicon Graphics may not be used in any advertising or
13  * publicity relating to the software without the specific, prior written
14  * permission of Sam Leffler and Silicon Graphics.
15  *
16  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
18  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
21  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
22  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
24  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
25  * OF THIS SOFTWARE.
26  */
27 
28 #include "tif_config.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #ifdef HAVE_OPENGL_GL_H
35 # include <OpenGL/gl.h>
36 #else
37 # include <GL/gl.h>
38 #endif
39 #ifdef HAVE_GLUT_GLUT_H
40 # include <GLUT/glut.h>
41 #else
42 # include <GL/glut.h>
43 #endif
44 
45 #include "tiffio.h"
46 #include "tiffiop.h"
47 
48 #ifndef HAVE_GETOPT
49 extern int getopt(int, char**, char*);
50 #endif
51 
52 static  uint32  width = 0, height = 0;          /* window width & height */
53 static  uint32* raster = NULL;                  /* displayable image */
54 static TIFFRGBAImage img;
55 static int      order0 = 0, order;
56 static uint16   photo0 = (uint16) -1, photo;
57 static int      stoponerr = 0;                  /* stop on read error */
58 static int      verbose = 0;
59 #define TITLE_LENGTH    1024
60 static char     title[TITLE_LENGTH];            /* window title line */
61 static uint32   xmax, ymax;
62 static char**   filelist = NULL;
63 static int      fileindex;
64 static int      filenum;
65 static TIFFErrorHandler oerror;
66 static TIFFErrorHandler owarning;
67 
68 static void	cleanup_and_exit(void);
69 static int	initImage(void);
70 static int	prevImage(void);
71 static int	nextImage(void);
72 static void	setWindowSize(void);
73 static void	usage(void);
74 static uint16	photoArg(const char*);
75 static void	raster_draw(void);
76 static void	raster_reshape(int, int);
77 static void	raster_keys(unsigned char, int, int);
78 static void	raster_special(int, int, int);
79 
80 #if !HAVE_DECL_OPTARG
81 extern  char* optarg;
82 extern  int optind;
83 #endif
84 
85 /* GLUT framework on MacOS X produces deprecation warnings */
86 # if defined(__GNUC__) && defined(__APPLE__)
87 #  pragma GCC diagnostic push
88 #  pragma GCC diagnostic ignored "-Wdeprecated-declarations"
89 # endif
90 
91 static TIFF* tif = NULL;
92 
93 int
main(int argc,char * argv[])94 main(int argc, char* argv[])
95 {
96         int c;
97         int dirnum = -1;
98         uint32 diroff = 0;
99 
100         oerror = TIFFSetErrorHandler(NULL);
101         owarning = TIFFSetWarningHandler(NULL);
102         while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
103             switch (c) {
104             case 'd':
105                 dirnum = atoi(optarg);
106                 break;
107             case 'e':
108                 oerror = TIFFSetErrorHandler(oerror);
109                 break;
110             case 'l':
111                 order0 = FILLORDER_LSB2MSB;
112                 break;
113             case 'm':
114                 order0 = FILLORDER_MSB2LSB;
115                 break;
116             case 'o':
117                 diroff = strtoul(optarg, NULL, 0);
118                 break;
119             case 'p':
120                 photo0 = photoArg(optarg);
121                 break;
122             case 's':
123                 stoponerr = 1;
124                 break;
125             case 'w':
126                 owarning = TIFFSetWarningHandler(owarning);
127                 break;
128             case 'v':
129                 verbose = 1;
130                 break;
131             case '?':
132                 usage();
133                 /*NOTREACHED*/
134             }
135         filenum = argc - optind;
136         if ( filenum < 1)
137                 usage();
138 
139         glutInit(&argc, argv);
140         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
141 
142         /*
143          * Get the screen size
144          */
145         xmax = glutGet(GLUT_SCREEN_WIDTH);
146         ymax = glutGet(GLUT_SCREEN_HEIGHT);
147 
148         /*
149          * Use 90% of the screen size
150          */
151         xmax = xmax - xmax / 10.0;
152         ymax = ymax - ymax / 10.0;
153 
154         filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
155         if (!filelist) {
156                 TIFFError(argv[0], "Can not allocate space for the file list.");
157                 return 1;
158         }
159         _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
160         fileindex = -1;
161         if (nextImage() < 0) {
162                 _TIFFfree(filelist);
163                 return 2;
164         }
165         /*
166          * Set initial directory if user-specified
167          * file was opened successfully.
168          */
169         if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
170             TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
171         if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
172             TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
173         order = order0;
174         photo = photo0;
175 	if (initImage() < 0){
176                 _TIFFfree(filelist);
177                 return 3;
178         }
179         /*
180          * Create a new window or reconfigure an existing
181          * one to suit the image to be displayed.
182          */
183         glutInitWindowSize(width, height);
184         snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
185                 (unsigned int) TIFFCurrentDirectory(tif));
186         glutCreateWindow(title);
187         glutDisplayFunc(raster_draw);
188         glutReshapeFunc(raster_reshape);
189         glutKeyboardFunc(raster_keys);
190         glutSpecialFunc(raster_special);
191         glutMainLoop();
192 
193         cleanup_and_exit();
194         return 0;
195 }
196 
197 static void
cleanup_and_exit(void)198 cleanup_and_exit(void)
199 {
200         TIFFRGBAImageEnd(&img);
201         if (filelist != NULL)
202                 _TIFFfree(filelist);
203         if (raster != NULL)
204                 _TIFFfree(raster);
205         if (tif != NULL)
206                 TIFFClose(tif);
207         exit(0);
208 }
209 
210 static int
initImage(void)211 initImage(void)
212 {
213         uint32 w, h;
214 
215         if (order)
216                 TIFFSetField(tif, TIFFTAG_FILLORDER, order);
217         if (photo != (uint16) -1)
218                 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo);
219         if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) {
220                 TIFFError(filelist[fileindex], "%s", title);
221                 TIFFClose(tif);
222                 tif = NULL;
223                 return -1;
224         }
225 
226         /*
227          * Setup the image raster as required.
228          */
229         h = img.height;
230         w = img.width;
231         if (h > ymax) {
232                 w = (int)(w * ((float)ymax / h));
233                 h = ymax;
234         }
235         if (w > xmax) {
236                 h = (int)(h * ((float)xmax / w));
237                 w = xmax;
238         }
239 
240 	if (w != width || h != height) {
241 		uint32 rastersize =
242 			_TIFFMultiply32(tif, img.width, img.height, "allocating raster buffer");
243 		if (raster != NULL)
244 			_TIFFfree(raster), raster = NULL;
245 		raster = (uint32*) _TIFFCheckMalloc(tif, rastersize, sizeof (uint32),
246 						    "allocating raster buffer");
247 		if (raster == NULL) {
248 			width = height = 0;
249 			TIFFError(filelist[fileindex], "No space for raster buffer");
250 			cleanup_and_exit();
251 		}
252 		width = w;
253 		height = h;
254 	}
255 	TIFFRGBAImageGet(&img, raster, img.width, img.height);
256 #if HOST_BIGENDIAN
257 	TIFFSwabArrayOfLong(raster,img.width*img.height);
258 #endif
259 	return 0;
260 }
261 
262 static int
prevImage(void)263 prevImage(void)
264 {
265         if (fileindex > 0)
266                 fileindex--;
267         else if (tif)
268                 return fileindex;
269         if (tif)
270                 TIFFClose(tif);
271         tif = TIFFOpen(filelist[fileindex], "r");
272         if (tif == NULL)
273                 return -1;
274         return fileindex;
275 }
276 
277 static int
nextImage(void)278 nextImage(void)
279 {
280         if (fileindex < filenum - 1)
281                 fileindex++;
282         else if (tif)
283                 return fileindex;
284         if (tif)
285                 TIFFClose(tif);
286         tif = TIFFOpen(filelist[fileindex], "r");
287         if (tif == NULL)
288                 return -1;
289         return fileindex;
290 }
291 
292 static void
setWindowSize(void)293 setWindowSize(void)
294 {
295         glutReshapeWindow(width, height);
296 }
297 
298 static void
raster_draw(void)299 raster_draw(void)
300 {
301   glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
302   glFlush();
303 }
304 
305 static void
raster_reshape(int win_w,int win_h)306 raster_reshape(int win_w, int win_h)
307 {
308         GLfloat xratio = (GLfloat)win_w/img.width;
309         GLfloat yratio = (GLfloat)win_h/img.height;
310         int     ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
311 
312         glPixelZoom(xratio, yratio);
313         glViewport(0, 0, win_w, win_h);
314         snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
315                 (unsigned int) TIFFCurrentDirectory(tif), ratio);
316         glutSetWindowTitle(title);
317 }
318 
319 static void
raster_keys(unsigned char key,int x,int y)320 raster_keys(unsigned char key, int x, int y)
321 {
322         (void) x;
323         (void) y;
324         switch (key) {
325                 case 'b':                       /* photometric MinIsBlack */
326                     photo = PHOTOMETRIC_MINISBLACK;
327                     initImage();
328                     break;
329                 case 'l':                       /* lsb-to-msb FillOrder */
330                     order = FILLORDER_LSB2MSB;
331                     initImage();
332                     break;
333                 case 'm':                       /* msb-to-lsb FillOrder */
334                     order = FILLORDER_MSB2LSB;
335                     initImage();
336                     break;
337                 case 'w':                       /* photometric MinIsWhite */
338                     photo = PHOTOMETRIC_MINISWHITE;
339                     initImage();
340                     break;
341                 case 'W':                       /* toggle warnings */
342                     owarning = TIFFSetWarningHandler(owarning);
343                     initImage();
344                     break;
345                 case 'E':                       /* toggle errors */
346                     oerror = TIFFSetErrorHandler(oerror);
347                     initImage();
348                     break;
349                 case 'z':                       /* reset to defaults */
350                 case 'Z':
351                     order = order0;
352                     photo = photo0;
353                     if (owarning == NULL)
354                         owarning = TIFFSetWarningHandler(NULL);
355                     if (oerror == NULL)
356                         oerror = TIFFSetErrorHandler(NULL);
357                     initImage();
358                     break;
359                 case 'q':                       /* exit */
360                 case '\033':
361                     cleanup_and_exit();
362         }
363         glutPostRedisplay();
364 }
365 
366 static void
raster_special(int key,int x,int y)367 raster_special(int key, int x, int y)
368 {
369         (void) x;
370         (void) y;
371         switch (key) {
372                 case GLUT_KEY_PAGE_UP:          /* previous logical image */
373                     if (TIFFCurrentDirectory(tif) > 0) {
374                             if (TIFFSetDirectory(tif,
375                                                  TIFFCurrentDirectory(tif)-1)) {
376                                     initImage();
377                                     setWindowSize();
378                         }
379                     } else {
380                             TIFFRGBAImageEnd(&img);
381                             prevImage();
382                             initImage();
383                             setWindowSize();
384                     }
385                 break;
386                 case GLUT_KEY_PAGE_DOWN:        /* next logical image */
387                     if (!TIFFLastDirectory(tif)) {
388                             if (TIFFReadDirectory(tif)) {
389                                     initImage();
390                                     setWindowSize();
391                             }
392                     } else {
393                             TIFFRGBAImageEnd(&img);
394                             nextImage();
395                             initImage();
396                             setWindowSize();
397                     }
398                 break;
399                 case GLUT_KEY_HOME:             /* 1st image in current file */
400                         if (TIFFSetDirectory(tif, 0)) {
401                                 TIFFRGBAImageEnd(&img);
402                                 initImage();
403                                 setWindowSize();
404                         }
405                 break;
406                 case GLUT_KEY_END:              /* last image in current file */
407                         TIFFRGBAImageEnd(&img);
408                         while (!TIFFLastDirectory(tif))
409                                 TIFFReadDirectory(tif);
410                         initImage();
411                         setWindowSize();
412                 break;
413         }
414         glutPostRedisplay();
415 }
416 
417 /* GLUT framework on MacOS X produces deprecation warnings */
418 # if defined(__GNUC__) && defined(__APPLE__)
419 #  pragma GCC diagnostic pop
420 # endif
421 
422 char* stuff[] = {
423 "usage: tiffgt [options] file.tif",
424 "where options are:",
425 " -c            use colormap visual",
426 " -d dirnum     set initial directory (default is 0)",
427 " -e            enable display of TIFF error messages",
428 " -l            force lsb-to-msb FillOrder",
429 " -m            force msb-to-lsb FillOrder",
430 " -o offset     set initial directory offset",
431 " -p photo      override photometric interpretation",
432 " -r            use fullcolor visual",
433 " -s            stop decoding on first error (default is ignore errors)",
434 " -v            enable verbose mode",
435 " -w            enable display of TIFF warning messages",
436 NULL
437 };
438 
439 static void
usage(void)440 usage(void)
441 {
442         char buf[BUFSIZ];
443         int i;
444 
445         setbuf(stderr, buf);
446                 fprintf(stderr, "%s\n\n", TIFFGetVersion());
447         for (i = 0; stuff[i] != NULL; i++)
448                 fprintf(stderr, "%s\n", stuff[i]);
449         exit(-1);
450 }
451 
452 static uint16
photoArg(const char * arg)453 photoArg(const char* arg)
454 {
455         if (strcmp(arg, "miniswhite") == 0)
456             return (PHOTOMETRIC_MINISWHITE);
457         else if (strcmp(arg, "minisblack") == 0)
458             return (PHOTOMETRIC_MINISBLACK);
459         else if (strcmp(arg, "rgb") == 0)
460             return (PHOTOMETRIC_RGB);
461         else if (strcmp(arg, "palette") == 0)
462             return (PHOTOMETRIC_PALETTE);
463         else if (strcmp(arg, "mask") == 0)
464             return (PHOTOMETRIC_MASK);
465         else if (strcmp(arg, "separated") == 0)
466             return (PHOTOMETRIC_SEPARATED);
467         else if (strcmp(arg, "ycbcr") == 0)
468             return (PHOTOMETRIC_YCBCR);
469         else if (strcmp(arg, "cielab") == 0)
470             return (PHOTOMETRIC_CIELAB);
471         else if (strcmp(arg, "logl") == 0)
472             return (PHOTOMETRIC_LOGL);
473         else if (strcmp(arg, "logluv") == 0)
474             return (PHOTOMETRIC_LOGLUV);
475         else
476             return ((uint16) -1);
477 }
478 
479 /* vim: set ts=8 sts=8 sw=8 noet: */
480 /*
481  * Local Variables:
482  * mode: c
483  * c-basic-offset: 8
484  * fill-column: 78
485  * End:
486  */
487