1/* $Id: tiffgt.c 276 2010-06-30 12:18:30Z nijtmans $ */ 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 45extern int getopt(int, char**, char*); 46#endif 47 48static uint32 width = 0, height = 0; /* window width & height */ 49static uint32* raster = NULL; /* displayable image */ 50static TIFFRGBAImage img; 51static int order0 = 0, order; 52static uint16 photo0 = (uint16) -1, photo; 53static int stoponerr = 0; /* stop on read error */ 54static int verbose = 0; 55#define TITLE_LENGTH 1024 56static char title[TITLE_LENGTH]; /* window title line */ 57static uint32 xmax, ymax; 58static char** filelist = NULL; 59static int fileindex; 60static int filenum; 61static TIFFErrorHandler oerror; 62static TIFFErrorHandler owarning; 63 64static void cleanup_and_exit(void); 65static int initImage(void); 66static int prevImage(void); 67static int nextImage(void); 68static void setWindowSize(void); 69static void usage(void); 70static uint16 photoArg(const char*); 71static void raster_draw(void); 72static void raster_reshape(int, int); 73static void raster_keys(unsigned char, int, int); 74static void raster_special(int, int, int); 75 76extern char* optarg; 77extern int optind; 78static TIFF* tif = NULL; 79 80int 81main(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 184static void 185cleanup_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 197static int 198initImage(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 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 246static int 247prevImage(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 261static int 262nextImage(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 276static void 277setWindowSize(void) 278{ 279 glutReshapeWindow(width, height); 280} 281 282static void 283raster_draw(void) 284{ 285 glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster); 286} 287 288static void 289raster_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 302static void 303raster_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 347static void 348raster_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 398char* 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", 412NULL 413}; 414 415static void 416usage(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 428static uint16 429photoArg(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: */ 456/* 457 * Local Variables: 458 * mode: c 459 * c-basic-offset: 8 460 * fill-column: 78 461 * End: 462 */ 463