Define _CRT_NONSTDC_NO_WARNINGS for zlib compilation with MSVC.
[wxWidgets.git] / src / tiff / tools / tiffgt.c
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
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], "%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
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
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
280 setWindowSize(void)
281 {
282 glutReshapeWindow(width, height);
283 }
284
285 static 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
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
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
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
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
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 */