]> git.saurik.com Git - wxWidgets.git/blame - src/tiff/tools/tiffgt.c
Correctly restore the originally used C locale in wxLocale dtor.
[wxWidgets.git] / src / tiff / tools / tiffgt.c
CommitLineData
8414a40c
VZ
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"
80ed523f 43#include "tiffiop.h"
8414a40c
VZ
44
45#ifndef HAVE_GETOPT
46extern int getopt(int, char**, char*);
47#endif
48
49static uint32 width = 0, height = 0; /* window width & height */
50static uint32* raster = NULL; /* displayable image */
51static TIFFRGBAImage img;
52static int order0 = 0, order;
53static uint16 photo0 = (uint16) -1, photo;
54static int stoponerr = 0; /* stop on read error */
55static int verbose = 0;
56#define TITLE_LENGTH 1024
57static char title[TITLE_LENGTH]; /* window title line */
58static uint32 xmax, ymax;
59static char** filelist = NULL;
60static int fileindex;
61static int filenum;
62static TIFFErrorHandler oerror;
63static TIFFErrorHandler owarning;
64
65static void cleanup_and_exit(void);
66static int initImage(void);
67static int prevImage(void);
68static int nextImage(void);
69static void setWindowSize(void);
70static void usage(void);
71static uint16 photoArg(const char*);
72static void raster_draw(void);
73static void raster_reshape(int, int);
74static void raster_keys(unsigned char, int, int);
75static void raster_special(int, int, int);
76
77extern char* optarg;
78extern int optind;
79static TIFF* tif = NULL;
80
81int
82main(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
185static void
186cleanup_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
198static int
199initImage(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)) {
80ed523f 208 TIFFError(filelist[fileindex], "%s", title);
8414a40c
VZ
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
80ed523f
VZ
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);
8414a40c 244#if HOST_BIGENDIAN
80ed523f 245 TIFFSwabArrayOfLong(raster,img.width*img.height);
8414a40c
VZ
246#endif
247 return 0;
248}
249
250static int
251prevImage(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
265static int
266nextImage(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
280static void
281setWindowSize(void)
282{
283 glutReshapeWindow(width, height);
284}
285
286static void
287raster_draw(void)
288{
289 glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
290}
291
292static void
293raster_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
306static void
307raster_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
351static void
352raster_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
402char* 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",
416NULL
417};
418
419static void
420usage(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
432static uint16
433photoArg(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: */
80ed523f
VZ
460/*
461 * Local Variables:
462 * mode: c
463 * c-basic-offset: 8
464 * fill-column: 78
465 * End:
466 */