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