1 
2 /*
3  * Copyright (c) 1988-1997 Sam Leffler
4  * Copyright (c) 1991-1997 Silicon Graphics, Inc.
5  * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and
8  * its documentation for any purpose is hereby granted without fee, provided
9  * that (i) the above copyright notices and this permission notice appear in
10  * all copies of the software and related documentation, and (ii) the names of
11  * Sam Leffler and Silicon Graphics may not be used in any advertising or
12  * publicity relating to the software without the specific, prior written
13  * permission of Sam Leffler and Silicon Graphics.
14  *
15  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
17  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
20  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
21  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
23  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
24  * OF THIS SOFTWARE.
25  */
26 
27 #include "tif_config.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32 
33 #if HAVE_APPLE_OPENGL_FRAMEWORK
34 # include <OpenGL/gl.h>
35 # include <GLUT/glut.h>
36 #else
37 # include <GL/gl.h>
38 # include <GL/glut.h>
39 #endif
40 
41 #include "tiffio.h"
42 #include "tiffiop.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], "%s", 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 		uint32 rastersize =
229 			_TIFFMultiply32(tif, img.width, img.height, "allocating raster buffer");
230 		if (raster != NULL)
231 			_TIFFfree(raster), raster = NULL;
232 		raster = (uint32*) _TIFFCheckMalloc(tif, rastersize, sizeof (uint32),
233 						    "allocating raster buffer");
234 		if (raster == NULL) {
235 			width = height = 0;
236 			TIFFError(filelist[fileindex], "No space for raster buffer");
237 			cleanup_and_exit();
238 		}
239 		width = w;
240 		height = h;
241 	}
242 	TIFFRGBAImageGet(&img, raster, img.width, img.height);
243 #if HOST_BIGENDIAN
244 	TIFFSwabArrayOfLong(raster,img.width*img.height);
245 #endif
246 	return 0;
247 }
248 
249 static int
prevImage(void)250 prevImage(void)
251 {
252         if (fileindex > 0)
253                 fileindex--;
254         else if (tif)
255                 return fileindex;
256         if (tif)
257                 TIFFClose(tif);
258         tif = TIFFOpen(filelist[fileindex], "r");
259         if (tif == NULL)
260                 return -1;
261         return fileindex;
262 }
263 
264 static int
nextImage(void)265 nextImage(void)
266 {
267         if (fileindex < filenum - 1)
268                 fileindex++;
269         else if (tif)
270                 return fileindex;
271         if (tif)
272                 TIFFClose(tif);
273         tif = TIFFOpen(filelist[fileindex], "r");
274         if (tif == NULL)
275                 return -1;
276         return fileindex;
277 }
278 
279 static void
setWindowSize(void)280 setWindowSize(void)
281 {
282         glutReshapeWindow(width, height);
283 }
284 
285 static void
raster_draw(void)286 raster_draw(void)
287 {
288   glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
289 }
290 
291 static void
raster_reshape(int win_w,int win_h)292 raster_reshape(int win_w, int win_h)
293 {
294         GLfloat xratio = (GLfloat)win_w/img.width;
295         GLfloat yratio = (GLfloat)win_h/img.height;
296         int     ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
297 
298         glPixelZoom(xratio, yratio);
299         glViewport(0, 0, win_w, win_h);
300         snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
301                 (unsigned int) TIFFCurrentDirectory(tif), ratio);
302         glutSetWindowTitle(title);
303 }
304 
305 static void
raster_keys(unsigned char key,int x,int y)306 raster_keys(unsigned char key, int x, int y)
307 {
308         switch (key) {
309                 case 'b':                       /* photometric MinIsBlack */
310                     photo = PHOTOMETRIC_MINISBLACK;
311                     initImage();
312                     break;
313                 case 'l':                       /* lsb-to-msb FillOrder */
314                     order = FILLORDER_LSB2MSB;
315                     initImage();
316                     break;
317                 case 'm':                       /* msb-to-lsb FillOrder */
318                     order = FILLORDER_MSB2LSB;
319                     initImage();
320                     break;
321                 case 'w':                       /* photometric MinIsWhite */
322                     photo = PHOTOMETRIC_MINISWHITE;
323                     initImage();
324                     break;
325                 case 'W':                       /* toggle warnings */
326                     owarning = TIFFSetWarningHandler(owarning);
327                     initImage();
328                     break;
329                 case 'E':                       /* toggle errors */
330                     oerror = TIFFSetErrorHandler(oerror);
331                     initImage();
332                     break;
333                 case 'z':                       /* reset to defaults */
334                 case 'Z':
335                     order = order0;
336                     photo = photo0;
337                     if (owarning == NULL)
338                         owarning = TIFFSetWarningHandler(NULL);
339                     if (oerror == NULL)
340                         oerror = TIFFSetErrorHandler(NULL);
341                     initImage();
342                     break;
343                 case 'q':                       /* exit */
344                 case '\033':
345                     cleanup_and_exit();
346         }
347         glutPostRedisplay();
348 }
349 
350 static void
raster_special(int key,int x,int y)351 raster_special(int key, int x, int y)
352 {
353         switch (key) {
354                 case GLUT_KEY_PAGE_UP:          /* previous logical image */
355                     if (TIFFCurrentDirectory(tif) > 0) {
356                             if (TIFFSetDirectory(tif,
357                                                  TIFFCurrentDirectory(tif)-1)) {
358                                     initImage();
359                                     setWindowSize();
360                         }
361                     } else {
362                             TIFFRGBAImageEnd(&img);
363                             prevImage();
364                             initImage();
365                             setWindowSize();
366                     }
367                 break;
368                 case GLUT_KEY_PAGE_DOWN:        /* next logical image */
369                     if (!TIFFLastDirectory(tif)) {
370                             if (TIFFReadDirectory(tif)) {
371                                     initImage();
372                                     setWindowSize();
373                             }
374                     } else {
375                             TIFFRGBAImageEnd(&img);
376                             nextImage();
377                             initImage();
378                             setWindowSize();
379                     }
380                 break;
381                 case GLUT_KEY_HOME:             /* 1st image in current file */
382                         if (TIFFSetDirectory(tif, 0)) {
383                                 TIFFRGBAImageEnd(&img);
384                                 initImage();
385                                 setWindowSize();
386                         }
387                 break;
388                 case GLUT_KEY_END:              /* last image in current file */
389                         TIFFRGBAImageEnd(&img);
390                         while (!TIFFLastDirectory(tif))
391                                 TIFFReadDirectory(tif);
392                         initImage();
393                         setWindowSize();
394                 break;
395         }
396         glutPostRedisplay();
397 }
398 
399 
400 
401 char* stuff[] = {
402 "usage: tiffgt [options] file.tif",
403 "where options are:",
404 " -c            use colormap visual",
405 " -d dirnum     set initial directory (default is 0)",
406 " -e            enable display of TIFF error messages",
407 " -l            force lsb-to-msb FillOrder",
408 " -m            force msb-to-lsb FillOrder",
409 " -o offset     set initial directory offset",
410 " -p photo      override photometric interpretation",
411 " -r            use fullcolor visual",
412 " -s            stop decoding on first error (default is ignore errors)",
413 " -v            enable verbose mode",
414 " -w            enable display of TIFF warning messages",
415 NULL
416 };
417 
418 static void
usage(void)419 usage(void)
420 {
421         char buf[BUFSIZ];
422         int i;
423 
424         setbuf(stderr, buf);
425                 fprintf(stderr, "%s\n\n", TIFFGetVersion());
426         for (i = 0; stuff[i] != NULL; i++)
427                 fprintf(stderr, "%s\n", stuff[i]);
428         exit(-1);
429 }
430 
431 static uint16
photoArg(const char * arg)432 photoArg(const char* arg)
433 {
434         if (strcmp(arg, "miniswhite") == 0)
435             return (PHOTOMETRIC_MINISWHITE);
436         else if (strcmp(arg, "minisblack") == 0)
437             return (PHOTOMETRIC_MINISBLACK);
438         else if (strcmp(arg, "rgb") == 0)
439             return (PHOTOMETRIC_RGB);
440         else if (strcmp(arg, "palette") == 0)
441             return (PHOTOMETRIC_PALETTE);
442         else if (strcmp(arg, "mask") == 0)
443             return (PHOTOMETRIC_MASK);
444         else if (strcmp(arg, "separated") == 0)
445             return (PHOTOMETRIC_SEPARATED);
446         else if (strcmp(arg, "ycbcr") == 0)
447             return (PHOTOMETRIC_YCBCR);
448         else if (strcmp(arg, "cielab") == 0)
449             return (PHOTOMETRIC_CIELAB);
450         else if (strcmp(arg, "logl") == 0)
451             return (PHOTOMETRIC_LOGL);
452         else if (strcmp(arg, "logluv") == 0)
453             return (PHOTOMETRIC_LOGLUV);
454         else
455             return ((uint16) -1);
456 }
457 
458 /* vim: set ts=8 sts=8 sw=8 noet: */
459 /*
460  * Local Variables:
461  * mode: c
462  * c-basic-offset: 8
463  * fill-column: 78
464  * End:
465  */
466