1 /* $Id: tiffgt.c,v 1.7 2006/03/23 14:54:02 dron Exp $ */
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 #if HAVE_APPLE_OPENGL_FRAMEWORK
35 # include <OpenGL/gl.h>
36 # include <GLUT/glut.h>
37 #else
38 # include <GL/gl.h>
39 # include <GL/glut.h>
40 #endif
41 
42 #include "tiffio.h"
43 
44 #ifndef HAVE_GETOPT
45 extern int getopt(int, char**, char*);
46 #endif
47 
48 static  uint32  width = 0, height = 0;          /* window width & height */
49 static  uint32* raster = NULL;                  /* displayable image */
50 static TIFFRGBAImage img;
51 static int      order0 = 0, order;
52 static uint16   photo0 = (uint16) -1, photo;
53 static int      stoponerr = 0;                  /* stop on read error */
54 static int      verbose = 0;
55 #define TITLE_LENGTH    1024
56 static char     title[TITLE_LENGTH];            /* window title line */
57 static uint32   xmax, ymax;
58 static char**   filelist = NULL;
59 static int      fileindex;
60 static int      filenum;
61 static TIFFErrorHandler oerror;
62 static TIFFErrorHandler owarning;
63 
64 static void	cleanup_and_exit(void);
65 static int	initImage(void);
66 static int	prevImage(void);
67 static int	nextImage(void);
68 static void	setWindowSize(void);
69 static void	usage(void);
70 static uint16	photoArg(const char*);
71 static void	raster_draw(void);
72 static void	raster_reshape(int, int);
73 static void	raster_keys(unsigned char, int, int);
74 static void	raster_special(int, int, int);
75 
76 extern  char* optarg;
77 extern  int optind;
78 static TIFF* tif = NULL;
79 
80 int
main(int argc,char * argv[])81 main(int argc, char* argv[])
82 {
83         int c;
84         int dirnum = -1;
85         uint32 diroff = 0;
86 
87         oerror = TIFFSetErrorHandler(NULL);
88         owarning = TIFFSetWarningHandler(NULL);
89         while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
90             switch (c) {
91             case 'd':
92                 dirnum = atoi(optarg);
93                 break;
94             case 'e':
95                 oerror = TIFFSetErrorHandler(oerror);
96                 break;
97             case 'l':
98                 order0 = FILLORDER_LSB2MSB;
99                 break;
100             case 'm':
101                 order0 = FILLORDER_MSB2LSB;
102                 break;
103             case 'o':
104                 diroff = strtoul(optarg, NULL, 0);
105                 break;
106             case 'p':
107                 photo0 = photoArg(optarg);
108                 break;
109             case 's':
110                 stoponerr = 1;
111                 break;
112             case 'w':
113                 owarning = TIFFSetWarningHandler(owarning);
114                 break;
115             case 'v':
116                 verbose = 1;
117                 break;
118             case '?':
119                 usage();
120                 /*NOTREACHED*/
121             }
122         filenum = argc - optind;
123         if ( filenum < 1)
124                 usage();
125 
126         glutInit(&argc, argv);
127         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
128 
129         /*
130          * Get the screen size
131          */
132         xmax = glutGet(GLUT_SCREEN_WIDTH);
133         ymax = glutGet(GLUT_SCREEN_HEIGHT);
134 
135         /*
136          * Use 90% of the screen size
137          */
138         xmax = xmax - xmax / 10.0;
139         ymax = ymax - ymax / 10.0;
140 
141         filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
142         if (!filelist) {
143                 TIFFError(argv[0], "Can not allocate space for the file list.");
144                 return 1;
145         }
146         _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
147         fileindex = -1;
148         if (nextImage() < 0) {
149                 _TIFFfree(filelist);
150                 return 2;
151         }
152         /*
153          * Set initial directory if user-specified
154          * file was opened successfully.
155          */
156         if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
157             TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
158         if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
159             TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
160         order = order0;
161         photo = photo0;
162 	if (initImage() < 0){
163                 _TIFFfree(filelist);
164                 return 3;
165         }
166         /*
167          * Create a new window or reconfigure an existing
168          * one to suit the image to be displayed.
169          */
170         glutInitWindowSize(width, height);
171         snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
172                 (unsigned int) TIFFCurrentDirectory(tif));
173         glutCreateWindow(title);
174         glutDisplayFunc(raster_draw);
175         glutReshapeFunc(raster_reshape);
176         glutKeyboardFunc(raster_keys);
177         glutSpecialFunc(raster_special);
178         glutMainLoop();
179 
180         cleanup_and_exit();
181         return 0;
182 }
183 
184 static void
cleanup_and_exit(void)185 cleanup_and_exit(void)
186 {
187         TIFFRGBAImageEnd(&img);
188         if (filelist != NULL)
189                 _TIFFfree(filelist);
190         if (raster != NULL)
191                 _TIFFfree(raster);
192         if (tif != NULL)
193                 TIFFClose(tif);
194         exit(0);
195 }
196 
197 static int
initImage(void)198 initImage(void)
199 {
200         uint32 w, h;
201 
202         if (order)
203                 TIFFSetField(tif, TIFFTAG_FILLORDER, order);
204         if (photo != (uint16) -1)
205                 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo);
206         if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) {
207                 TIFFError(filelist[fileindex], title);
208                 TIFFClose(tif);
209                 tif = NULL;
210                 return -1;
211         }
212 
213         /*
214          * Setup the image raster as required.
215          */
216         h = img.height;
217         w = img.width;
218         if (h > ymax) {
219                 w = (int)(w * ((float)ymax / h));
220                 h = ymax;
221         }
222         if (w > xmax) {
223                 h = (int)(h * ((float)xmax / w));
224                 w = xmax;
225         }
226 
227         if (w != width || h != height) {
228             if (raster != NULL)
229                 _TIFFfree(raster), raster = NULL;
230             raster = (uint32*) _TIFFmalloc(img.width * img.height * sizeof (uint32));
231             if (raster == NULL) {
232                 width = height = 0;
233                 TIFFError(filelist[fileindex], "No space for raster buffer");
234                 cleanup_and_exit();
235             }
236             width = w;
237             height = h;
238         }
239         TIFFRGBAImageGet(&img, raster, img.width, img.height);
240 #if HOST_BIGENDIAN
241         TIFFSwabArrayOfLong(raster,img.width*img.height);
242 #endif
243 	return 0;
244 }
245 
246 static int
prevImage(void)247 prevImage(void)
248 {
249         if (fileindex > 0)
250                 fileindex--;
251         else if (tif)
252                 return fileindex;
253         if (tif)
254                 TIFFClose(tif);
255         tif = TIFFOpen(filelist[fileindex], "r");
256         if (tif == NULL)
257                 return -1;
258         return fileindex;
259 }
260 
261 static int
nextImage(void)262 nextImage(void)
263 {
264         if (fileindex < filenum - 1)
265                 fileindex++;
266         else if (tif)
267                 return fileindex;
268         if (tif)
269                 TIFFClose(tif);
270         tif = TIFFOpen(filelist[fileindex], "r");
271         if (tif == NULL)
272                 return -1;
273         return fileindex;
274 }
275 
276 static void
setWindowSize(void)277 setWindowSize(void)
278 {
279         glutReshapeWindow(width, height);
280 }
281 
282 static void
raster_draw(void)283 raster_draw(void)
284 {
285   glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
286 }
287 
288 static void
raster_reshape(int win_w,int win_h)289 raster_reshape(int win_w, int win_h)
290 {
291         GLfloat xratio = (GLfloat)win_w/img.width;
292         GLfloat yratio = (GLfloat)win_h/img.height;
293         int     ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
294 
295         glPixelZoom(xratio, yratio);
296         glViewport(0, 0, win_w, win_h);
297         snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
298                 (unsigned int) TIFFCurrentDirectory(tif), ratio);
299         glutSetWindowTitle(title);
300 }
301 
302 static void
raster_keys(unsigned char key,int x,int y)303 raster_keys(unsigned char key, int x, int y)
304 {
305         switch (key) {
306                 case 'b':                       /* photometric MinIsBlack */
307                     photo = PHOTOMETRIC_MINISBLACK;
308                     initImage();
309                     break;
310                 case 'l':                       /* lsb-to-msb FillOrder */
311                     order = FILLORDER_LSB2MSB;
312                     initImage();
313                     break;
314                 case 'm':                       /* msb-to-lsb FillOrder */
315                     order = FILLORDER_MSB2LSB;
316                     initImage();
317                     break;
318                 case 'w':                       /* photometric MinIsWhite */
319                     photo = PHOTOMETRIC_MINISWHITE;
320                     initImage();
321                     break;
322                 case 'W':                       /* toggle warnings */
323                     owarning = TIFFSetWarningHandler(owarning);
324                     initImage();
325                     break;
326                 case 'E':                       /* toggle errors */
327                     oerror = TIFFSetErrorHandler(oerror);
328                     initImage();
329                     break;
330                 case 'z':                       /* reset to defaults */
331                 case 'Z':
332                     order = order0;
333                     photo = photo0;
334                     if (owarning == NULL)
335                         owarning = TIFFSetWarningHandler(NULL);
336                     if (oerror == NULL)
337                         oerror = TIFFSetErrorHandler(NULL);
338                     initImage();
339                     break;
340                 case 'q':                       /* exit */
341                 case '\033':
342                     cleanup_and_exit();
343         }
344         glutPostRedisplay();
345 }
346 
347 static void
raster_special(int key,int x,int y)348 raster_special(int key, int x, int y)
349 {
350         switch (key) {
351                 case GLUT_KEY_PAGE_UP:          /* previous logical image */
352                     if (TIFFCurrentDirectory(tif) > 0) {
353                             if (TIFFSetDirectory(tif,
354                                                  TIFFCurrentDirectory(tif)-1)) {
355                                     initImage();
356                                     setWindowSize();
357                         }
358                     } else {
359                             TIFFRGBAImageEnd(&img);
360                             prevImage();
361                             initImage();
362                             setWindowSize();
363                     }
364                 break;
365                 case GLUT_KEY_PAGE_DOWN:        /* next logical image */
366                     if (!TIFFLastDirectory(tif)) {
367                             if (TIFFReadDirectory(tif)) {
368                                     initImage();
369                                     setWindowSize();
370                             }
371                     } else {
372                             TIFFRGBAImageEnd(&img);
373                             nextImage();
374                             initImage();
375                             setWindowSize();
376                     }
377                 break;
378                 case GLUT_KEY_HOME:             /* 1st image in current file */
379                         if (TIFFSetDirectory(tif, 0)) {
380                                 TIFFRGBAImageEnd(&img);
381                                 initImage();
382                                 setWindowSize();
383                         }
384                 break;
385                 case GLUT_KEY_END:              /* last image in current file */
386                         TIFFRGBAImageEnd(&img);
387                         while (!TIFFLastDirectory(tif))
388                                 TIFFReadDirectory(tif);
389                         initImage();
390                         setWindowSize();
391                 break;
392         }
393         glutPostRedisplay();
394 }
395 
396 
397 
398 char* stuff[] = {
399 "usage: tiffgt [options] file.tif",
400 "where options are:",
401 " -c            use colormap visual",
402 " -d dirnum     set initial directory (default is 0)",
403 " -e            enable display of TIFF error messages",
404 " -l            force lsb-to-msb FillOrder",
405 " -m            force msb-to-lsb FillOrder",
406 " -o offset     set initial directory offset",
407 " -p photo      override photometric interpretation",
408 " -r            use fullcolor visual",
409 " -s            stop decoding on first error (default is ignore errors)",
410 " -v            enable verbose mode",
411 " -w            enable display of TIFF warning messages",
412 NULL
413 };
414 
415 static void
usage(void)416 usage(void)
417 {
418         char buf[BUFSIZ];
419         int i;
420 
421         setbuf(stderr, buf);
422                 fprintf(stderr, "%s\n\n", TIFFGetVersion());
423         for (i = 0; stuff[i] != NULL; i++)
424                 fprintf(stderr, "%s\n", stuff[i]);
425         exit(-1);
426 }
427 
428 static uint16
photoArg(const char * arg)429 photoArg(const char* arg)
430 {
431         if (strcmp(arg, "miniswhite") == 0)
432             return (PHOTOMETRIC_MINISWHITE);
433         else if (strcmp(arg, "minisblack") == 0)
434             return (PHOTOMETRIC_MINISBLACK);
435         else if (strcmp(arg, "rgb") == 0)
436             return (PHOTOMETRIC_RGB);
437         else if (strcmp(arg, "palette") == 0)
438             return (PHOTOMETRIC_PALETTE);
439         else if (strcmp(arg, "mask") == 0)
440             return (PHOTOMETRIC_MASK);
441         else if (strcmp(arg, "separated") == 0)
442             return (PHOTOMETRIC_SEPARATED);
443         else if (strcmp(arg, "ycbcr") == 0)
444             return (PHOTOMETRIC_YCBCR);
445         else if (strcmp(arg, "cielab") == 0)
446             return (PHOTOMETRIC_CIELAB);
447         else if (strcmp(arg, "logl") == 0)
448             return (PHOTOMETRIC_LOGL);
449         else if (strcmp(arg, "logluv") == 0)
450             return (PHOTOMETRIC_LOGLUV);
451         else
452             return ((uint16) -1);
453 }
454 
455 /* vim: set ts=8 sts=8 sw=8 noet: */
456