/* $Header: /usr/people/sam/tiff/tools/RCS/sgigt.c,v 1.66 1996/01/10 19:35:32 sam Rel $ */ /* * Copyright (c) 1988-1996 Sam Leffler * Copyright (c) 1991-1996 Silicon Graphics, Inc. * * Permission to use, copy, modify, distribute, and sell this software and * its documentation for any purpose is hereby granted without fee, provided * that (i) the above copyright notices and this permission notice appear in * all copies of the software and related documentation, and (ii) the names of * Sam Leffler and Silicon Graphics may not be used in any advertising or * publicity relating to the software without the specific, prior written * permission of Sam Leffler and Silicon Graphics. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #include #include #include #include #include #include #include "tiffio.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif /* XXX fudge adjustment for window borders */ #define YFUDGE 20 #define XFUDGE 20 static tileContigRoutine putContig; static tileSeparateRoutine putSeparate; static uint32 width, height; /* window width & height */ static uint32* raster = NULL; /* displayable image */ extern Colorindex greyi(int); static void setupColormapSupport(TIFFRGBAImage*); static void putContigAndDraw(TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, unsigned char*); static void putSeparateAndDraw(TIFFRGBAImage*, uint32*, uint32, uint32, uint32, uint32, int32, int32, unsigned char*, unsigned char*, unsigned char*, unsigned char*); static int prevImage(char* argv[], int ix, int b, int e, int wrap); static int nextImage(char* argv[], int ix, int b, int e, int wrap); static void usage(void); static uint16 photoArg(const char*); static void beep(void); extern char* optarg; extern int optind; int main(int argc, char* argv[]) { static Cursor hourglass = { 0x1ff0, 0x1ff0, 0x0820, 0x0820, 0x0820, 0x0c60, 0x06c0, 0x0100, 0x0100, 0x06c0, 0x0c60, 0x0820, 0x0820, 0x0820, 0x1ff0, 0x1ff0 }; int isRGB0 = -1, isRGB; int verbose = 0; int stoponerr = 0; /* stop on read error */ char* filename; TIFF* tif = NULL; int fg = 0; int c; int dirnum = -1; int order0 = 0, order; uint32 diroff = 0; uint16 photo0 = (uint16) -1, photo; long x, y, xmax, ymax; int ix, nix; TIFFErrorHandler oerror = TIFFSetErrorHandler(NULL); TIFFErrorHandler owarning = TIFFSetWarningHandler(NULL); uint32 w, h; long wid = -1; while ((c = getopt(argc, argv, "d:o:p:cerflmsvw")) != -1) switch (c) { case 'c': isRGB0 = 0; break; case 'd': dirnum = atoi(optarg); break; case 'e': oerror = TIFFSetErrorHandler(oerror); break; case 'f': fg = 1; break; case 'l': order0 = FILLORDER_LSB2MSB; break; case 'm': order0 = FILLORDER_MSB2LSB; break; case 'o': diroff = strtoul(optarg, NULL, 0); break; case 'p': photo0 = photoArg(optarg); break; case 'r': isRGB0 = 1; break; case 's': stoponerr = 1; break; case 'w': owarning = TIFFSetWarningHandler(owarning); break; case 'v': verbose = 1; break; case '?': usage(); /*NOTREACHED*/ } if (argc - optind < 1) usage(); xmax = getgdesc(GD_XPMAX) - XFUDGE; ymax = getgdesc(GD_YPMAX) - YFUDGE; ix = optind; do { tif = TIFFOpen(argv[ix], "r"); } while (tif == NULL && (ix = nextImage(argv, ix, optind, argc, FALSE))); if (tif == NULL) exit(0); if (ix == optind) { /* * Set initial directory if user-specified * file was opened successfully. */ if (dirnum != -1 && !TIFFSetDirectory(tif, dirnum)) TIFFError(argv[ix], "Error, seeking to directory %d", dirnum); if (diroff != 0 && !TIFFSetSubDirectory(tif, diroff)) TIFFError(argv[ix], "Error, setting subdirectory at %#x", diroff); } isRGB = isRGB0; order = order0; photo = photo0; goto newfile0; for (;;) { TIFFRGBAImage img; char title[1024]; /* window title line */ const char* cp; int isrgb; if (order) TIFFSetField(tif, TIFFTAG_FILLORDER, order); if (photo != (uint16) -1) TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photo); if (!TIFFRGBAImageBegin(&img, tif, stoponerr, title)) { TIFFError(filename, title); goto bad2; } /* * Use a full-color window if the image is * full color or a palette image and the * hardware support is present. */ isrgb = isRGB; if (isrgb == -1) isrgb = (img.bitspersample >= 8 && (img.photometric == PHOTOMETRIC_RGB || img.photometric == PHOTOMETRIC_YCBCR || img.photometric == PHOTOMETRIC_SEPARATED || img.photometric == PHOTOMETRIC_PALETTE)); /* * Check to see if the hardware can display 24-bit RGB. */ if (isrgb && getgdesc(GD_BITS_NORM_SNG_RED) < img.bitspersample && !getgdesc(GD_DITHER)) { if (verbose) printf("Warning, display is incapable of full RGB,%s\n", " using dithered colormap"); isrgb = 0; } /* * Colormap-based display is done by overriding the put * routine to install a private method that understands * how to convert RGBA values to suitable colormap indices. */ if (!isrgb) setupColormapSupport(&img); /* * Override default ``put routine'' with private * routine that also draws the raster on the display. */ if (img.put.any == 0) { TIFFError(filename, "No \"put\" routine; must not handle image format"); goto bad3; } if (img.isContig) { putContig = img.put.contig; img.put.contig = putContigAndDraw; } else { putSeparate = img.put.separate; img.put.separate = putSeparateAndDraw; } /* * Setup the image raster as required. */ if ((w = img.width) > xmax) w = xmax; if ((h = img.height) > ymax) h = ymax; if (w != width || h != height) { if (raster != NULL) _TIFFfree(raster), raster = NULL; raster = (uint32*) _TIFFmalloc(w * h * sizeof (uint32)); if (raster == 0) { width = height = 0; TIFFError(filename, "No space for raster buffer"); goto bad3; } width = w; height = h; } /* * Create a new window or reconfigure an existing * one to suit the image to be displayed. */ if (wid < 0) { x = (xmax+XFUDGE-width)/2; y = (ymax+YFUDGE-height)/2; prefposition(x, x+width-1, y, y+height-1); cp = strrchr(filename, '/'); sprintf(title, "%s [%u] %s", cp == NULL ? filename : cp+1, (unsigned int) TIFFCurrentDirectory(tif), isrgb ? " rgb" : " cmap"); if (fg) foreground(); wid = winopen(title); if (wid < 0) { TIFFError(filename, "Can not create window"); TIFFRGBAImageEnd(&img); break; } curstype(C16X1); defcursor(1, hourglass); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); qdevice(RIGHTMOUSE); qdevice(KEYBD); qdevice(PAGEUPKEY); qdevice(PAGEDOWNKEY); qdevice(HOMEKEY); qdevice(ENDKEY); } else { x = (xmax+XFUDGE-width)/2; y = (ymax+YFUDGE-height)/2; winposition(x, x+width-1, y, y+height-1); viewport(0, width-1, 0, height-1); cp = strrchr(filename, '/'); sprintf(title, "%s [%u] %s", cp == NULL ? filename : cp+1, (unsigned int) TIFFCurrentDirectory(tif), isrgb ? " rgb" : " cmap"); wintitle(title); } singlebuffer(); if (isrgb) { RGBmode(); gconfig(); } else { cmode(); gconfig(); } /* * Fetch the image. */ setcursor(1, 0, 0); greyi(225); clear(); (void) TIFFRGBAImageGet(&img, raster, width, height); setcursor(0, 0, 0); /* * Process input. */ for (;;) { short val; switch (qread(&val)) { case KEYBD: switch (val) { case 'b': /* photometric MinIsBlack */ photo = PHOTOMETRIC_MINISBLACK; goto newpage; case 'l': /* lsb-to-msb FillOrder */ order = FILLORDER_LSB2MSB; goto newpage; case 'm': /* msb-to-lsb FillOrder */ order = FILLORDER_MSB2LSB; goto newpage; case 'c': /* colormap visual */ isRGB = 0; goto newpage; case 'r': /* RGB visual */ isRGB = 1; goto newpage; case 'w': /* photometric MinIsWhite */ photo = PHOTOMETRIC_MINISWHITE; goto newpage; case 'W': /* toggle warnings */ owarning = TIFFSetWarningHandler(owarning); goto newpage; case 'E': /* toggle errors */ oerror = TIFFSetErrorHandler(oerror); goto newpage; case 'z': /* reset to defaults */ case 'Z': order = order0; photo = photo0; isRGB = isRGB0; if (owarning == NULL) owarning = TIFFSetWarningHandler(NULL); if (oerror == NULL) oerror = TIFFSetErrorHandler(NULL); goto newpage; case 'q': /* exit */ case '\033': TIFFRGBAImageEnd(&img); goto done; } break; case PAGEUPKEY: /* previous logical image */ if (val) { if (TIFFCurrentDirectory(tif) > 0) { if (TIFFSetDirectory(tif, TIFFCurrentDirectory(tif)-1)) goto newpage; beep(); /* XXX */ } else { ix = prevImage(argv, ix, optind, argc, TRUE); /* XXX set directory to last image in new file */ goto newfile; } } break; case PAGEDOWNKEY: /* next logical image */ if (val) { if (!TIFFLastDirectory(tif)) { if (TIFFReadDirectory(tif)) goto newpage; beep(); /* XXX */ } else { ix = nextImage(argv, ix, optind, argc, TRUE); goto newfile; } } break; case HOMEKEY: /* 1st image in current file */ if (val) { if (TIFFSetDirectory(tif, 0)) goto newpage; beep(); } break; case ENDKEY: /* last image in current file */ if (val) { /* XXX */ beep(); } break; case RIGHTMOUSE: /* previous file */ if (val) { if (nix = prevImage(argv, ix, optind, argc, FALSE)) { ix = nix; goto newfile; } beep(); } break; case LEFTMOUSE: /* next file */ if (val) { if (nix = nextImage(argv, ix, optind, argc, FALSE)) { ix = nix; goto newfile; } beep(); } break; case MIDDLEMOUSE: /* first file */ if (val) { if (nix = nextImage(argv, optind-1, optind, argc, FALSE)) { ix = nix; goto newfile; } beep(); } break; case REDRAW: lrectwrite(0, 0, width-1, height-1, raster); break; } } newfile: TIFFRGBAImageEnd(&img); if (tif != NULL && argv[ix] != filename) TIFFClose(tif), tif = NULL; /* fall thru... */ newfile0: if (argv[ix] == NULL) break; filename = argv[ix]; if (tif == NULL) { tif = TIFFOpen(filename, "r"); if (tif == NULL) goto bad1; isRGB = isRGB0; order = order0; photo = photo0; } continue; newpage: TIFFRGBAImageEnd(&img); continue; bad3: TIFFRGBAImageEnd(&img); bad2: TIFFClose(tif), tif = NULL; bad1: argv[ix] = NULL; /* don't revisit file */ ix = nextImage(argv, ix, optind, argc, TRUE); goto newfile0; } done: if (wid >= 0) winclose(wid); if (raster != NULL) _TIFFfree(raster); if (tif != NULL) TIFFClose(tif); return (0); } static int prevImage(char* argv[], int ix, int b, int e, int wrap) { int i; for (i = ix-1; i >= b && argv[i] == NULL; i--) ; if (i < b) { if (wrap) { for (i = e-1; i > ix && argv[i] == NULL; i--) ; } else i = 0; } return (i); } static int nextImage(char* argv[], int ix, int b, int e, int wrap) { int i; for (i = ix+1; i < e && argv[i] == NULL; i++) ; if (i >= e) { if (wrap) { for (i = b; i < ix && argv[i] == NULL; i++) ; } else i = 0; } return (i); } static void beep(void) { greyi(0); clear(); sginap(5); lrectwrite(0, 0, width-1, height-1, raster); } char* stuff[] = { "usage: tiffgt [options] file.tif", "where options are:", " -c use colormap visual", " -d dirnum set initial directory (default is 0)", " -e enable display of TIFF error messages", " -f run program in the foreground", " -l force lsb-to-msb FillOrder", " -m force msb-to-lsb FillOrder", " -o offset set initial directory offset", " -p photo override photometric interpretation", " -r use fullcolor visual", " -s stop decoding on first error (default is ignore errors)", " -v enable verbose mode", " -w enable display of TIFF warning messages", NULL }; static void usage(void) { char buf[BUFSIZ]; int i; setbuf(stderr, buf); for (i = 0; stuff[i] != NULL; i++) fprintf(stderr, "%s\n", stuff[i]); exit(-1); } static uint16 photoArg(const char* arg) { if (strcmp(arg, "miniswhite") == 0) return (PHOTOMETRIC_MINISWHITE); else if (strcmp(arg, "minisblack") == 0) return (PHOTOMETRIC_MINISBLACK); else if (strcmp(arg, "rgb") == 0) return (PHOTOMETRIC_RGB); else if (strcmp(arg, "palette") == 0) return (PHOTOMETRIC_PALETTE); else if (strcmp(arg, "mask") == 0) return (PHOTOMETRIC_MASK); else if (strcmp(arg, "separated") == 0) return (PHOTOMETRIC_SEPARATED); else if (strcmp(arg, "ycbcr") == 0) return (PHOTOMETRIC_YCBCR); else if (strcmp(arg, "cielab") == 0) return (PHOTOMETRIC_CIELAB); else return ((uint16) -1); } static void putContigAndDraw(TIFFRGBAImage* img, uint32* raster, uint32 x, uint32 y, uint32 w, uint32 h, int32 fromskew, int32 toskew, unsigned char* cp) { (*putContig)(img, raster, x, y, w, h, fromskew, toskew, cp); if (x+w == width) { w = width; if (img->orientation == ORIENTATION_TOPLEFT) lrectwrite(0, y-(h-1), w-1, y, raster-x-(h-1)*w); else lrectwrite(0, y, w-1, y+h-1, raster); } } static void putSeparateAndDraw(TIFFRGBAImage* img, uint32* raster, uint32 x, uint32 y, uint32 w, uint32 h, int32 fromskew, int32 toskew, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a) { (*putSeparate)(img, raster, x, y, w, h, fromskew, toskew, r, g, b, a); if (x+w == width) { w = width; if (img->orientation == ORIENTATION_TOPLEFT) lrectwrite(x, y-(h-1), w-1, y, raster-x-(h-1)*w); else lrectwrite(x, y, w-1, y+h-1, raster); } } /* * {red,green,blue}_inverse are tables in libgutil.a that * do an inverse map from (r,g,b) to the closest colormap * index in the "standard" GL colormap. grey_inverse is * the equivalent map for mapping greyscale values to * colormap indices. We access these maps directly instead * of through the rgbi and greyi functions to avoid the * additional overhead of the color calls that they make. */ extern u_char red_inverse[256]; extern u_char green_inverse[256]; extern u_char blue_inverse[256]; extern u_char grey_inverse[256]; #define greyi(g) grey_inverse[g] static u_char rgbi(u_char r, u_char g, u_char b) { return (r == g && g == b ? grey_inverse[r] : red_inverse[r] + green_inverse[g] + blue_inverse[b]); } /* * The following routines move decoded data returned * from the TIFF library into rasters that are suitable * for passing to lrecwrite. They do the necessary * conversions for when a colormap drawing mode is used. */ #define REPEAT8(op) REPEAT4(op); REPEAT4(op) #define REPEAT4(op) REPEAT2(op); REPEAT2(op) #define REPEAT2(op) op; op #define CASE8(x,op) \ switch (x) { \ case 7: op; case 6: op; case 5: op; \ case 4: op; case 3: op; case 2: op; \ case 1: op; \ } #define CASE4(x,op) switch (x) { case 3: op; case 2: op; case 1: op; } #define NOP #define UNROLL8(w, op1, op2) { \ uint32 _x; \ for (_x = w; _x >= 8; _x -= 8) { \ op1; \ REPEAT8(op2); \ } \ if (_x > 0) { \ op1; \ CASE8(_x,op2); \ } \ } #define UNROLL4(w, op1, op2) { \ uint32 _x; \ for (_x = w; _x >= 4; _x -= 4) { \ op1; \ REPEAT4(op2); \ } \ if (_x > 0) { \ op1; \ CASE4(_x,op2); \ } \ } #define UNROLL2(w, op1, op2) { \ uint32 _x; \ for (_x = w; _x >= 2; _x -= 2) { \ op1; \ REPEAT2(op2); \ } \ if (_x) { \ op1; \ op2; \ } \ } #define SKEW(r,g,b,skew) { r += skew; g += skew; b += skew; } #define DECLAREContigPutFunc(name) \ static void name(\ TIFFRGBAImage* img, \ uint32* cp, \ uint32 x, uint32 y, \ uint32 w, uint32 h, \ int32 fromskew, int32 toskew, \ u_char* pp \ ) #define DECLARESepPutFunc(name) \ static void name(\ TIFFRGBAImage* img,\ uint32* cp,\ uint32 x, uint32 y, \ uint32 w, uint32 h,\ int32 fromskew, int32 toskew,\ u_char* r, u_char* g, u_char* b, u_char* a\ ) static tileContigRoutine libput; /* * 8-bit packed samples => colormap */ DECLAREContigPutFunc(putcontig8bittile) { int samplesperpixel = img->samplesperpixel; TIFFRGBValue* Map = img->Map; (void) y; fromskew *= samplesperpixel; if (Map) { while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = rgbi(Map[pp[0]], Map[pp[1]], Map[pp[2]]); pp += samplesperpixel; } cp += toskew; pp += fromskew; } } else { while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = rgbi(pp[0], pp[1], pp[2]); pp += samplesperpixel; } cp += toskew; pp += fromskew; } } } /* * Convert 8-bit packed samples => colormap */ DECLAREContigPutFunc(cvtcontig8bittile) { (*libput)(img, cp, x, y, w, h, fromskew, toskew, pp); while (h-- > 0) { UNROLL8(w, NOP, cp[0] = rgbi(TIFFGetR(cp[0]),TIFFGetG(cp[0]),TIFFGetB(cp[0])); cp++ ); cp += toskew; } } /* * 16-bit packed samples => colormap */ DECLAREContigPutFunc(putcontig16bittile) { int samplesperpixel = img->samplesperpixel; TIFFRGBValue* Map = img->Map; (void) y; fromskew *= samplesperpixel; if (Map) { while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = rgbi(Map[pp[0]], Map[pp[1]], Map[pp[2]]); pp += samplesperpixel; } cp += toskew; pp += fromskew; } } else { while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = rgbi(pp[0], pp[1], pp[2]); pp += samplesperpixel; } cp += toskew; pp += fromskew; } } } /* * 8-bit unpacked samples => colormap */ DECLARESepPutFunc(putseparate8bittile) { TIFFRGBValue* Map = img->Map; (void) y; (void) a; if (Map) { while (h-- > 0) { for (x = w; x-- > 0;) *cp++ = rgbi(Map[*r++], Map[*g++], Map[*b++]); SKEW(r, g, b, fromskew); cp += toskew; } } else { while (h-- > 0) { for (x = w; x-- > 0;) *cp++ = rgbi(*r++, *g++, *b++); SKEW(r, g, b, fromskew); cp += toskew; } } } /* * 16-bit unpacked samples => colormap */ DECLARESepPutFunc(putseparate16bittile) { TIFFRGBValue* Map = img->Map; (void) y; (void) a; if (Map) { while (h-- > 0) { for (x = 0; x < w; x++) *cp++ = rgbi(Map[*r++], Map[*g++], Map[*b++]); SKEW(r, g, b, fromskew); cp += toskew; } } else { while (h-- > 0) { for (x = 0; x < w; x++) *cp++ = rgbi(*r++, *g++, *b++); SKEW(r, g, b, fromskew); cp += toskew; } } } /* * 8-bit packed CMYK samples => cmap * * NB: The conversion of CMYK->RGB is *very* crude. */ DECLAREContigPutFunc(putcontig8bitCMYKtile) { int samplesperpixel = img->samplesperpixel; TIFFRGBValue* Map = img->Map; uint16 r, g, b, k; (void) y; fromskew *= samplesperpixel; if (Map) { while (h-- > 0) { for (x = w; x-- > 0;) { k = 255 - pp[3]; r = (k*(255-pp[0]))/255; g = (k*(255-pp[1]))/255; b = (k*(255-pp[2]))/255; *cp++ = rgbi(Map[r], Map[g], Map[b]); pp += samplesperpixel; } pp += fromskew; cp += toskew; } } else { while (h-- > 0) { UNROLL8(w, NOP, k = 255 - pp[3]; r = (k*(255-pp[0]))/255; g = (k*(255-pp[1]))/255; b = (k*(255-pp[2]))/255; *cp++ = rgbi(r, g, b); pp += samplesperpixel); cp += toskew; pp += fromskew; } } } #define YCbCrtoRGB(dst, yc) { \ int Y = (yc); \ dst = rgbi( \ clamptab[Y+Crrtab[Cr]], \ clamptab[Y + (int)((Cbgtab[Cb]+Crgtab[Cr])>>16)], \ clamptab[Y+Cbbtab[Cb]]); \ } #define YCbCrSetup \ TIFFYCbCrToRGB* ycbcr = img->ycbcr; \ int* Crrtab = ycbcr->Cr_r_tab; \ int* Cbbtab = ycbcr->Cb_b_tab; \ int32* Crgtab = ycbcr->Cr_g_tab; \ int32* Cbgtab = ycbcr->Cb_g_tab; \ TIFFRGBValue* clamptab = ycbcr->clamptab /* * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) { YCbCrSetup; uint32* cp1 = cp+w+toskew; unsigned int incr = 2*toskew+w; (void) y; /* XXX adjust fromskew */ for (; h >= 2; h -= 2) { x = w>>1; do { int Cb = pp[4]; int Cr = pp[5]; YCbCrtoRGB(cp [0], pp[0]); YCbCrtoRGB(cp [1], pp[1]); YCbCrtoRGB(cp1[0], pp[2]); YCbCrtoRGB(cp1[1], pp[3]); cp += 2, cp1 += 2; pp += 6; } while (--x); cp += incr, cp1 += incr; pp += fromskew; } } #undef YCbCrSetup #undef YCbCrtoRGB /* * Setup to handle conversion for display in a colormap * window. Many cases are handled by massaging the mapping * tables used by the normal library code to convert 32-bit * packed RGBA samples into colormap indices. Other cases * are handled with special-case routines that replace the * normal ``put routine'' installed by the library. */ static void setupColormapSupport(TIFFRGBAImage* img) { int bitspersample = img->bitspersample; int i; if (img->BWmap) { i = 255; do { uint32* p = img->BWmap[i]; switch (bitspersample) { #define GREY(x) p[x] = greyi(TIFFGetR(p[x])) case 1: GREY(7); GREY(6); GREY(5); GREY(4); case 2: GREY(3); GREY(2); case 4: GREY(1); case 8: GREY(0); } #undef GREY } while (i--); } else if (img->PALmap) { i = 255; do { uint32 rgb; uint32* p = img->PALmap[i]; #define CMAP(x) \ (rgb = p[x], p[x] = rgbi(TIFFGetR(rgb),TIFFGetG(rgb),TIFFGetB(rgb))) switch (bitspersample) { case 1: CMAP(7); CMAP(6); CMAP(5); CMAP(4); case 2: CMAP(3); CMAP(2); case 4: CMAP(1); case 8: CMAP(0); } #undef CMAP } while (i--); } else if (img->isContig) { switch (img->photometric) { case PHOTOMETRIC_RGB: switch (bitspersample) { case 8: img->put.contig = putcontig8bittile; break; case 16: img->put.contig = putcontig16bittile; break; } break; case PHOTOMETRIC_SEPARATED: switch (bitspersample) { case 8: img->put.contig = putcontig8bitCMYKtile; break; } break; case PHOTOMETRIC_YCBCR: if (img->bitspersample == 8) { uint16 hs, vs; TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); switch ((hs<<4)|vs) { case 0x22: /* most common case */ img->put.contig = putcontig8bitYCbCr22tile; break; default: /* all others cost more */ libput = img->put.contig; img->put.contig = cvtcontig8bittile; break; } } break; } } else { switch (img->photometric) { case PHOTOMETRIC_RGB: switch (img->bitspersample) { case 8: img->put.separate = putseparate8bittile; break; case 16: img->put.separate = putseparate16bittile; break; } break; } } }