roentgen b75cab
/* $Id: tiffgt.c,v 1.10 2010-07-01 15:56:56 dron Exp $ */
roentgen b75cab
roentgen b75cab
/*
roentgen b75cab
 * Copyright (c) 1988-1997 Sam Leffler
roentgen b75cab
 * Copyright (c) 1991-1997 Silicon Graphics, Inc.
roentgen b75cab
 * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu></dron@ak4719.spb.edu>
roentgen b75cab
 *
roentgen b75cab
 * Permission to use, copy, modify, distribute, and sell this software and 
roentgen b75cab
 * its documentation for any purpose is hereby granted without fee, provided
roentgen b75cab
 * that (i) the above copyright notices and this permission notice appear in
roentgen b75cab
 * all copies of the software and related documentation, and (ii) the names of
roentgen b75cab
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
roentgen b75cab
 * publicity relating to the software without the specific, prior written
roentgen b75cab
 * permission of Sam Leffler and Silicon Graphics.
roentgen b75cab
 * 
roentgen b75cab
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
roentgen b75cab
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
roentgen b75cab
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
roentgen b75cab
 * 
roentgen b75cab
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
roentgen b75cab
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
roentgen b75cab
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
roentgen b75cab
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
roentgen b75cab
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
roentgen b75cab
 * OF THIS SOFTWARE.
roentgen b75cab
 */
roentgen b75cab
roentgen b75cab
#include "tif_config.h"
roentgen b75cab
#include <stdio.h></stdio.h>
roentgen b75cab
#include <stdlib.h></stdlib.h>
roentgen b75cab
#include <string.h></string.h>
roentgen b75cab
#include <unistd.h></unistd.h>
roentgen b75cab
roentgen b75cab
#if HAVE_APPLE_OPENGL_FRAMEWORK
roentgen b75cab
# include <opengl gl.h=""></opengl>
roentgen b75cab
# include <glut glut.h=""></glut>
roentgen b75cab
#else
roentgen b75cab
# include <gl gl.h=""></gl>
roentgen b75cab
# include <gl glut.h=""></gl>
roentgen b75cab
#endif
roentgen b75cab
roentgen b75cab
#include "tiffio.h"
roentgen b75cab
#include "tiffiop.h"
roentgen b75cab
roentgen b75cab
#ifndef HAVE_GETOPT
roentgen b75cab
extern int getopt(int, char**, char*);
roentgen b75cab
#endif
roentgen b75cab
roentgen b75cab
static  uint32  width = 0, height = 0;          /* window width & height */
roentgen b75cab
static  uint32* raster = NULL;                  /* displayable image */
roentgen b75cab
static TIFFRGBAImage img;
roentgen b75cab
static int      order0 = 0, order;
roentgen b75cab
static uint16   photo0 = (uint16) -1, photo;
roentgen b75cab
static int      stoponerr = 0;                  /* stop on read error */
roentgen b75cab
static int      verbose = 0;
roentgen b75cab
#define TITLE_LENGTH    1024
roentgen b75cab
static char     title[TITLE_LENGTH];            /* window title line */
roentgen b75cab
static uint32   xmax, ymax;
roentgen b75cab
static char**   filelist = NULL;
roentgen b75cab
static int      fileindex;
roentgen b75cab
static int      filenum;
roentgen b75cab
static TIFFErrorHandler oerror;
roentgen b75cab
static TIFFErrorHandler owarning;
roentgen b75cab
roentgen b75cab
static void	cleanup_and_exit(void);
roentgen b75cab
static int	initImage(void);
roentgen b75cab
static int	prevImage(void);
roentgen b75cab
static int	nextImage(void);
roentgen b75cab
static void	setWindowSize(void);
roentgen b75cab
static void	usage(void);
roentgen b75cab
static uint16	photoArg(const char*);
roentgen b75cab
static void	raster_draw(void);
roentgen b75cab
static void	raster_reshape(int, int);
roentgen b75cab
static void	raster_keys(unsigned char, int, int);
roentgen b75cab
static void	raster_special(int, int, int);
roentgen b75cab
roentgen b75cab
extern  char* optarg;
roentgen b75cab
extern  int optind;
roentgen b75cab
static TIFF* tif = NULL;
roentgen b75cab
roentgen b75cab
int
roentgen b75cab
main(int argc, char* argv[])
roentgen b75cab
{
roentgen b75cab
        int c;
roentgen b75cab
        int dirnum = -1;
roentgen b75cab
        uint32 diroff = 0;
roentgen b75cab
roentgen b75cab
        oerror = TIFFSetErrorHandler(NULL);
roentgen b75cab
        owarning = TIFFSetWarningHandler(NULL);
roentgen b75cab
        while ((c = getopt(argc, argv, "d:o:p:eflmsvw?")) != -1)
roentgen b75cab
            switch (c) {
roentgen b75cab
            case 'd':
roentgen b75cab
                dirnum = atoi(optarg);
roentgen b75cab
                break;
roentgen b75cab
            case 'e':
roentgen b75cab
                oerror = TIFFSetErrorHandler(oerror);
roentgen b75cab
                break;
roentgen b75cab
            case 'l':
roentgen b75cab
                order0 = FILLORDER_LSB2MSB;
roentgen b75cab
                break;
roentgen b75cab
            case 'm':
roentgen b75cab
                order0 = FILLORDER_MSB2LSB;
roentgen b75cab
                break;
roentgen b75cab
            case 'o':
roentgen b75cab
                diroff = strtoul(optarg, NULL, 0);
roentgen b75cab
                break;
roentgen b75cab
            case 'p':
roentgen b75cab
                photo0 = photoArg(optarg);
roentgen b75cab
                break;
roentgen b75cab
            case 's':
roentgen b75cab
                stoponerr = 1;
roentgen b75cab
                break;
roentgen b75cab
            case 'w':
roentgen b75cab
                owarning = TIFFSetWarningHandler(owarning);
roentgen b75cab
                break;
roentgen b75cab
            case 'v':
roentgen b75cab
                verbose = 1;
roentgen b75cab
                break;
roentgen b75cab
            case '?':
roentgen b75cab
                usage();
roentgen b75cab
                /*NOTREACHED*/
roentgen b75cab
            }
roentgen b75cab
        filenum = argc - optind;
roentgen b75cab
        if ( filenum < 1)
roentgen b75cab
                usage();
roentgen b75cab
roentgen b75cab
        glutInit(&argc, argv);
roentgen b75cab
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
roentgen b75cab
roentgen b75cab
        /*
roentgen b75cab
         * Get the screen size
roentgen b75cab
         */
roentgen b75cab
        xmax = glutGet(GLUT_SCREEN_WIDTH);
roentgen b75cab
        ymax = glutGet(GLUT_SCREEN_HEIGHT);
roentgen b75cab
roentgen b75cab
        /*
roentgen b75cab
         * Use 90% of the screen size
roentgen b75cab
         */
roentgen b75cab
        xmax = xmax - xmax / 10.0;
roentgen b75cab
        ymax = ymax - ymax / 10.0;
roentgen b75cab
roentgen b75cab
        filelist = (char **) _TIFFmalloc(filenum * sizeof(char*));
roentgen b75cab
        if (!filelist) {
roentgen b75cab
                TIFFError(argv[0], "Can not allocate space for the file list.");
roentgen b75cab
                return 1;
roentgen b75cab
        }
roentgen b75cab
        _TIFFmemcpy(filelist, argv + optind, filenum * sizeof(char*));
roentgen b75cab
        fileindex = -1;
roentgen b75cab
        if (nextImage() < 0) {
roentgen b75cab
                _TIFFfree(filelist);
roentgen b75cab
                return 2;
roentgen b75cab
        }
roentgen b75cab
        /*
roentgen b75cab
         * Set initial directory if user-specified
roentgen b75cab
         * file was opened successfully.
roentgen b75cab
         */
roentgen b75cab
        if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum))
roentgen b75cab
            TIFFError(argv[0], "Error, seeking to directory %d", dirnum);
roentgen b75cab
        if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff))
roentgen b75cab
            TIFFError(argv[0], "Error, setting subdirectory at %#x", diroff);
roentgen b75cab
        order = order0;
roentgen b75cab
        photo = photo0;
roentgen b75cab
	if (initImage() < 0){
roentgen b75cab
                _TIFFfree(filelist);
roentgen b75cab
                return 3;
roentgen b75cab
        }
roentgen b75cab
        /*
roentgen b75cab
         * Create a new window or reconfigure an existing
roentgen b75cab
         * one to suit the image to be displayed.
roentgen b75cab
         */
roentgen b75cab
        glutInitWindowSize(width, height);
roentgen b75cab
        snprintf(title, TITLE_LENGTH - 1, "%s [%u]", filelist[fileindex],
roentgen b75cab
                (unsigned int) TIFFCurrentDirectory(tif));
roentgen b75cab
        glutCreateWindow(title);
roentgen b75cab
        glutDisplayFunc(raster_draw);
roentgen b75cab
        glutReshapeFunc(raster_reshape);
roentgen b75cab
        glutKeyboardFunc(raster_keys);
roentgen b75cab
        glutSpecialFunc(raster_special);
roentgen b75cab
        glutMainLoop();
roentgen b75cab
roentgen b75cab
        cleanup_and_exit();
roentgen b75cab
        return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void 
roentgen b75cab
cleanup_and_exit(void)
roentgen b75cab
{
roentgen b75cab
        TIFFRGBAImageEnd(&img);
roentgen b75cab
        if (filelist != NULL)
roentgen b75cab
                _TIFFfree(filelist);
roentgen b75cab
        if (raster != NULL)
roentgen b75cab
                _TIFFfree(raster);
roentgen b75cab
        if (tif != NULL)
roentgen b75cab
                TIFFClose(tif);
roentgen b75cab
        exit(0);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
initImage(void)
roentgen b75cab
{
roentgen b75cab
        uint32 w, h;
roentgen b75cab
roentgen b75cab
        if (order)
roentgen b75cab
                TIFFSetField(tif, TIFFTAG_FILLORDER, order);
roentgen b75cab
        if (photo != (uint16) -1)
roentgen b75cab
                TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo);
roentgen b75cab
        if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) {
roentgen b75cab
                TIFFError(filelist[fileindex], "%s", title);
roentgen b75cab
                TIFFClose(tif);
roentgen b75cab
                tif = NULL;
roentgen b75cab
                return -1;
roentgen b75cab
        }
roentgen b75cab
roentgen b75cab
        /*
roentgen b75cab
         * Setup the image raster as required.
roentgen b75cab
         */
roentgen b75cab
        h = img.height;
roentgen b75cab
        w = img.width;
roentgen b75cab
        if (h > ymax) {
roentgen b75cab
                w = (int)(w * ((float)ymax / h));
roentgen b75cab
                h = ymax;
roentgen b75cab
        }
roentgen b75cab
        if (w > xmax) {
roentgen b75cab
                h = (int)(h * ((float)xmax / w));
roentgen b75cab
                w = xmax;
roentgen b75cab
        }
roentgen b75cab
roentgen b75cab
	if (w != width || h != height) {
roentgen b75cab
		uint32 rastersize =
roentgen b75cab
			_TIFFMultiply32(tif, img.width, img.height, "allocating raster buffer");
roentgen b75cab
		if (raster != NULL)
roentgen b75cab
			_TIFFfree(raster), raster = NULL;
roentgen b75cab
		raster = (uint32*) _TIFFCheckMalloc(tif, rastersize, sizeof (uint32),
roentgen b75cab
						    "allocating raster buffer");
roentgen b75cab
		if (raster == NULL) {
roentgen b75cab
			width = height = 0;
roentgen b75cab
			TIFFError(filelist[fileindex], "No space for raster buffer");
roentgen b75cab
			cleanup_and_exit();
roentgen b75cab
		}
roentgen b75cab
		width = w;
roentgen b75cab
		height = h;
roentgen b75cab
	}
roentgen b75cab
	TIFFRGBAImageGet(&img, raster, img.width, img.height);
roentgen b75cab
#if HOST_BIGENDIAN
roentgen b75cab
	TIFFSwabArrayOfLong(raster,img.width*img.height);
roentgen b75cab
#endif
roentgen b75cab
	return 0;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
prevImage(void)
roentgen b75cab
{
roentgen b75cab
        if (fileindex > 0)
roentgen b75cab
                fileindex--;
roentgen b75cab
        else if (tif)
roentgen b75cab
                return fileindex;
roentgen b75cab
        if (tif)
roentgen b75cab
                TIFFClose(tif);
roentgen b75cab
        tif = TIFFOpen(filelist[fileindex], "r");
roentgen b75cab
        if (tif == NULL)
roentgen b75cab
                return -1;
roentgen b75cab
        return fileindex;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static int
roentgen b75cab
nextImage(void)
roentgen b75cab
{
roentgen b75cab
        if (fileindex < filenum - 1)
roentgen b75cab
                fileindex++;
roentgen b75cab
        else if (tif)
roentgen b75cab
                return fileindex;
roentgen b75cab
        if (tif)
roentgen b75cab
                TIFFClose(tif);
roentgen b75cab
        tif = TIFFOpen(filelist[fileindex], "r");
roentgen b75cab
        if (tif == NULL)
roentgen b75cab
                return -1;
roentgen b75cab
        return fileindex;
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
setWindowSize(void)
roentgen b75cab
{
roentgen b75cab
        glutReshapeWindow(width, height);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
raster_draw(void)
roentgen b75cab
{
roentgen b75cab
  glDrawPixels(img.width, img.height, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *) raster);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
raster_reshape(int win_w, int win_h)
roentgen b75cab
{
roentgen b75cab
        GLfloat xratio = (GLfloat)win_w/img.width;
roentgen b75cab
        GLfloat yratio = (GLfloat)win_h/img.height;
roentgen b75cab
        int     ratio = (int)(((xratio > yratio)?xratio:yratio) * 100);
roentgen b75cab
roentgen b75cab
        glPixelZoom(xratio, yratio);
roentgen b75cab
        glViewport(0, 0, win_w, win_h);
roentgen b75cab
        snprintf(title, 1024, "%s [%u] %d%%", filelist[fileindex],
roentgen b75cab
                (unsigned int) TIFFCurrentDirectory(tif), ratio);
roentgen b75cab
        glutSetWindowTitle(title);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
raster_keys(unsigned char key, int x, int y)
roentgen b75cab
{
roentgen b75cab
        switch (key) {
roentgen b75cab
                case 'b':                       /* photometric MinIsBlack */
roentgen b75cab
                    photo = PHOTOMETRIC_MINISBLACK;
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'l':                       /* lsb-to-msb FillOrder */
roentgen b75cab
                    order = FILLORDER_LSB2MSB;
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'm':                       /* msb-to-lsb FillOrder */
roentgen b75cab
                    order = FILLORDER_MSB2LSB;
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'w':                       /* photometric MinIsWhite */
roentgen b75cab
                    photo = PHOTOMETRIC_MINISWHITE;
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'W':                       /* toggle warnings */
roentgen b75cab
                    owarning = TIFFSetWarningHandler(owarning);
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'E':                       /* toggle errors */
roentgen b75cab
                    oerror = TIFFSetErrorHandler(oerror);
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'z':                       /* reset to defaults */
roentgen b75cab
                case 'Z':
roentgen b75cab
                    order = order0;
roentgen b75cab
                    photo = photo0;
roentgen b75cab
                    if (owarning == NULL)
roentgen b75cab
                        owarning = TIFFSetWarningHandler(NULL);
roentgen b75cab
                    if (oerror == NULL)
roentgen b75cab
                        oerror = TIFFSetErrorHandler(NULL);
roentgen b75cab
                    initImage();
roentgen b75cab
                    break;
roentgen b75cab
                case 'q':                       /* exit */
roentgen b75cab
                case '\033':
roentgen b75cab
                    cleanup_and_exit();
roentgen b75cab
        }
roentgen b75cab
        glutPostRedisplay();
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
raster_special(int key, int x, int y)
roentgen b75cab
{
roentgen b75cab
        switch (key) {
roentgen b75cab
                case GLUT_KEY_PAGE_UP:          /* previous logical image */
roentgen b75cab
                    if (TIFFCurrentDirectory(tif) > 0) {
roentgen b75cab
                            if (TIFFSetDirectory(tif,
roentgen b75cab
                                                 TIFFCurrentDirectory(tif)-1)) {
roentgen b75cab
                                    initImage();
roentgen b75cab
                                    setWindowSize();
roentgen b75cab
                        }
roentgen b75cab
                    } else {
roentgen b75cab
                            TIFFRGBAImageEnd(&img);
roentgen b75cab
                            prevImage();
roentgen b75cab
                            initImage();
roentgen b75cab
                            setWindowSize();
roentgen b75cab
                    }
roentgen b75cab
                break;
roentgen b75cab
                case GLUT_KEY_PAGE_DOWN:        /* next logical image */
roentgen b75cab
                    if (!TIFFLastDirectory(tif)) {
roentgen b75cab
                            if (TIFFReadDirectory(tif)) {
roentgen b75cab
                                    initImage();
roentgen b75cab
                                    setWindowSize();
roentgen b75cab
                            }
roentgen b75cab
                    } else {
roentgen b75cab
                            TIFFRGBAImageEnd(&img);
roentgen b75cab
                            nextImage();
roentgen b75cab
                            initImage();
roentgen b75cab
                            setWindowSize();
roentgen b75cab
                    }
roentgen b75cab
                break;
roentgen b75cab
                case GLUT_KEY_HOME:             /* 1st image in current file */
roentgen b75cab
                        if (TIFFSetDirectory(tif, 0)) {
roentgen b75cab
                                TIFFRGBAImageEnd(&img);
roentgen b75cab
                                initImage();
roentgen b75cab
                                setWindowSize();
roentgen b75cab
                        }
roentgen b75cab
                break;
roentgen b75cab
                case GLUT_KEY_END:              /* last image in current file */
roentgen b75cab
                        TIFFRGBAImageEnd(&img);
roentgen b75cab
                        while (!TIFFLastDirectory(tif))
roentgen b75cab
                                TIFFReadDirectory(tif);
roentgen b75cab
                        initImage();
roentgen b75cab
                        setWindowSize();
roentgen b75cab
                break;
roentgen b75cab
        }
roentgen b75cab
        glutPostRedisplay();
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
roentgen b75cab
roentgen b75cab
char* stuff[] = {
roentgen b75cab
"usage: tiffgt [options] file.tif",
roentgen b75cab
"where options are:",
roentgen b75cab
" -c            use colormap visual",
roentgen b75cab
" -d dirnum     set initial directory (default is 0)",
roentgen b75cab
" -e            enable display of TIFF error messages",
roentgen b75cab
" -l            force lsb-to-msb FillOrder",
roentgen b75cab
" -m            force msb-to-lsb FillOrder",
roentgen b75cab
" -o offset     set initial directory offset",
roentgen b75cab
" -p photo      override photometric interpretation",
roentgen b75cab
" -r            use fullcolor visual",
roentgen b75cab
" -s            stop decoding on first error (default is ignore errors)",
roentgen b75cab
" -v            enable verbose mode",
roentgen b75cab
" -w            enable display of TIFF warning messages",
roentgen b75cab
NULL
roentgen b75cab
};
roentgen b75cab
roentgen b75cab
static void
roentgen b75cab
usage(void)
roentgen b75cab
{
roentgen b75cab
        char buf[BUFSIZ];
roentgen b75cab
        int i;
roentgen b75cab
roentgen b75cab
        setbuf(stderr, buf);
roentgen b75cab
                fprintf(stderr, "%s\n\n", TIFFGetVersion());
roentgen b75cab
        for (i = 0; stuff[i] != NULL; i++)
roentgen b75cab
                fprintf(stderr, "%s\n", stuff[i]);
roentgen b75cab
        exit(-1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
static uint16
roentgen b75cab
photoArg(const char* arg)
roentgen b75cab
{
roentgen b75cab
        if (strcmp(arg, "miniswhite") == 0)
roentgen b75cab
            return (PHOTOMETRIC_MINISWHITE);
roentgen b75cab
        else if (strcmp(arg, "minisblack") == 0)
roentgen b75cab
            return (PHOTOMETRIC_MINISBLACK);
roentgen b75cab
        else if (strcmp(arg, "rgb") == 0)
roentgen b75cab
            return (PHOTOMETRIC_RGB);
roentgen b75cab
        else if (strcmp(arg, "palette") == 0)
roentgen b75cab
            return (PHOTOMETRIC_PALETTE);
roentgen b75cab
        else if (strcmp(arg, "mask") == 0)
roentgen b75cab
            return (PHOTOMETRIC_MASK);
roentgen b75cab
        else if (strcmp(arg, "separated") == 0)
roentgen b75cab
            return (PHOTOMETRIC_SEPARATED);
roentgen b75cab
        else if (strcmp(arg, "ycbcr") == 0)
roentgen b75cab
            return (PHOTOMETRIC_YCBCR);
roentgen b75cab
        else if (strcmp(arg, "cielab") == 0)
roentgen b75cab
            return (PHOTOMETRIC_CIELAB);
roentgen b75cab
        else if (strcmp(arg, "logl") == 0)
roentgen b75cab
            return (PHOTOMETRIC_LOGL);
roentgen b75cab
        else if (strcmp(arg, "logluv") == 0)
roentgen b75cab
            return (PHOTOMETRIC_LOGLUV);
roentgen b75cab
        else
roentgen b75cab
            return ((uint16) -1);
roentgen b75cab
}
roentgen b75cab
roentgen b75cab
/* vim: set ts=8 sts=8 sw=8 noet: */
roentgen b75cab
/*
roentgen b75cab
 * Local Variables:
roentgen b75cab
 * mode: c
roentgen b75cab
 * c-basic-offset: 8
roentgen b75cab
 * fill-column: 78
roentgen b75cab
 * End:
roentgen b75cab
 */