import libtiff 3.8.2 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
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
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
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
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
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
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
277 setWindowSize(void)
278 {
279 glutReshapeWindow(width, height);
280 }
281
282 static 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
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
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
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
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
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: */