/* $Header: /cvs/maptools/cvsroot/libtiff/libtiff/tif_getimage.c,v 1.1.1.1 1999-07-27 21:50:27 mike Exp $ */ /* * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 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. */ /* * TIFF Library * * Read and return a packed RGBA image. */ #include "tiffiop.h" #include #include static int gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); static int gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); static int gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); static int gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); static int pickTileContigCase(TIFFRGBAImage*); static int pickTileSeparateCase(TIFFRGBAImage*); static const char photoTag[] = "PhotometricInterpretation"; /* * Check the image to see if TIFFReadRGBAImage can deal with it. * 1/0 is returned according to whether or not the image can * be handled. If 0 is returned, emsg contains the reason * why it is being rejected. */ int TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) { TIFFDirectory* td = &tif->tif_dir; uint16 photometric; int colorchannels; switch (td->td_bitspersample) { case 1: case 2: case 4: case 8: case 16: break; default: sprintf(emsg, "Sorry, can not handle images with %d-bit samples", td->td_bitspersample); return (0); } colorchannels = td->td_samplesperpixel - td->td_extrasamples; if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photometric)) { switch (colorchannels) { case 1: photometric = PHOTOMETRIC_MINISBLACK; break; case 3: photometric = PHOTOMETRIC_RGB; break; default: sprintf(emsg, "Missing needed %s tag", photoTag); return (0); } } switch (photometric) { case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_PALETTE: if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_samplesperpixel != 1) { sprintf(emsg, "Sorry, can not handle contiguous data with %s=%d, and %s=%d", photoTag, photometric, "Samples/pixel", td->td_samplesperpixel); return (0); } break; case PHOTOMETRIC_YCBCR: if (td->td_planarconfig != PLANARCONFIG_CONTIG) { sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d", "Planarconfiguration", td->td_planarconfig); return (0); } break; case PHOTOMETRIC_RGB: if (colorchannels < 3) { sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", "Color channels", colorchannels); return (0); } break; #ifdef CMYK_SUPPORT case PHOTOMETRIC_SEPARATED: if (td->td_inkset != INKSET_CMYK) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "InkSet", td->td_inkset); return (0); } if (td->td_samplesperpixel != 4) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "Samples/pixel", td->td_samplesperpixel); return (0); } break; #endif case PHOTOMETRIC_LOGL: if (td->td_compression != COMPRESSION_SGILOG) { sprintf(emsg, "Sorry, LogL data must have %s=%d", "Compression", COMPRESSION_SGILOG); return (0); } break; case PHOTOMETRIC_LOGLUV: if (td->td_compression != COMPRESSION_SGILOG && td->td_compression != COMPRESSION_SGILOG24) { sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); return (0); } if (td->td_planarconfig != PLANARCONFIG_CONTIG) { sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", "Planarconfiguration", td->td_planarconfig); return (0); } break; default: sprintf(emsg, "Sorry, can not handle image with %s=%d", photoTag, photometric); return (0); } return (1); } void TIFFRGBAImageEnd(TIFFRGBAImage* img) { if (img->Map) _TIFFfree(img->Map), img->Map = NULL; if (img->BWmap) _TIFFfree(img->BWmap), img->BWmap = NULL; if (img->PALmap) _TIFFfree(img->PALmap), img->PALmap = NULL; if (img->ycbcr) _TIFFfree(img->ycbcr), img->ycbcr = NULL; } static int isCCITTCompression(TIFF* tif) { uint16 compress; TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); return (compress == COMPRESSION_CCITTFAX3 || compress == COMPRESSION_CCITTFAX4 || compress == COMPRESSION_CCITTRLE || compress == COMPRESSION_CCITTRLEW); } int TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) { uint16* sampleinfo; uint16 extrasamples; uint16 planarconfig; uint16 compress; int colorchannels; img->tif = tif; img->stoponerr = stop; TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); switch (img->bitspersample) { case 1: case 2: case 4: case 8: case 16: break; default: sprintf(emsg, "Sorry, can not image with %d-bit samples", img->bitspersample); return (0); } img->alpha = 0; TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (extrasamples == 1) switch (sampleinfo[0]) { case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ img->alpha = sampleinfo[0]; break; } colorchannels = img->samplesperpixel - extrasamples; TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { switch (colorchannels) { case 1: if (isCCITTCompression(tif)) img->photometric = PHOTOMETRIC_MINISWHITE; else img->photometric = PHOTOMETRIC_MINISBLACK; break; case 3: img->photometric = PHOTOMETRIC_RGB; break; default: sprintf(emsg, "Missing needed %s tag", photoTag); return (0); } } switch (img->photometric) { case PHOTOMETRIC_PALETTE: if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &img->redcmap, &img->greencmap, &img->bluecmap)) { TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag"); return (0); } /* fall thru... */ case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) { sprintf(emsg, "Sorry, can not handle contiguous data with %s=%d, and %s=%d", photoTag, img->photometric, "Samples/pixel", img->samplesperpixel); return (0); } break; case PHOTOMETRIC_YCBCR: if (planarconfig != PLANARCONFIG_CONTIG) { sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d", "Planarconfiguration", planarconfig); return (0); } /* It would probably be nice to have a reality check here. */ if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { /* can rely on libjpeg to convert to RGB */ /* XXX should restore current state on exit */ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); img->photometric = PHOTOMETRIC_RGB; } break; case PHOTOMETRIC_RGB: if (colorchannels < 3) { sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", "Color channels", colorchannels); return (0); } break; case PHOTOMETRIC_SEPARATED: { uint16 inkset; TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); if (inkset != INKSET_CMYK) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "InkSet", inkset); return (0); } if (img->samplesperpixel != 4) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "Samples/pixel", img->samplesperpixel); return (0); } break; } case PHOTOMETRIC_LOGL: if (compress != COMPRESSION_SGILOG) { sprintf(emsg, "Sorry, LogL data must have %s=%d", "Compression", COMPRESSION_SGILOG); return (0); } TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); img->photometric = PHOTOMETRIC_MINISBLACK; /* little white lie */ img->bitspersample = 8; break; case PHOTOMETRIC_LOGLUV: if (compress != COMPRESSION_SGILOG && compress != COMPRESSION_SGILOG24) { sprintf(emsg, "Sorry, LogLuv data must have %s=%d or %d", "Compression", COMPRESSION_SGILOG, COMPRESSION_SGILOG24); return (0); } if (planarconfig != PLANARCONFIG_CONTIG) { sprintf(emsg, "Sorry, can not handle LogLuv images with %s=%d", "Planarconfiguration", planarconfig); return (0); } TIFFSetField(tif, TIFFTAG_SGILOGDATAFMT, SGILOGDATAFMT_8BIT); img->photometric = PHOTOMETRIC_RGB; /* little white lie */ img->bitspersample = 8; break; default: sprintf(emsg, "Sorry, can not handle image with %s=%d", photoTag, img->photometric); return (0); } img->Map = NULL; img->BWmap = NULL; img->PALmap = NULL; img->ycbcr = NULL; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); img->isContig = !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); if (img->isContig) { img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig; (void) pickTileContigCase(img); } else { img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate; (void) pickTileSeparateCase(img); } return (1); } int TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { if (img->get == NULL) { TIFFError(TIFFFileName(img->tif), "No \"get\" routine setup"); return (0); } if (img->put.any == NULL) { TIFFError(TIFFFileName(img->tif), "No \"put\" routine setupl; probably can not handle image format"); return (0); } return (*img->get)(img, raster, w, h); } /* * Read the specified image into an ABGR-format raster. */ int TIFFReadRGBAImage(TIFF* tif, uint32 rwidth, uint32 rheight, uint32* raster, int stop) { char emsg[1024]; TIFFRGBAImage img; int ok; if (TIFFRGBAImageBegin(&img, tif, stop, emsg)) { /* XXX verify rwidth and rheight against width and height */ ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, rwidth, img.height); TIFFRGBAImageEnd(&img); } else { TIFFError(TIFFFileName(tif), emsg); ok = 0; } return (ok); } static uint32 setorientation(TIFFRGBAImage* img, uint32 h) { TIFF* tif = img->tif; uint32 y; switch (img->orientation) { case ORIENTATION_BOTRIGHT: case ORIENTATION_RIGHTBOT: /* XXX */ case ORIENTATION_LEFTBOT: /* XXX */ TIFFWarning(TIFFFileName(tif), "using bottom-left orientation"); img->orientation = ORIENTATION_BOTLEFT; /* fall thru... */ case ORIENTATION_BOTLEFT: y = 0; break; case ORIENTATION_TOPRIGHT: case ORIENTATION_RIGHTTOP: /* XXX */ case ORIENTATION_LEFTTOP: /* XXX */ default: TIFFWarning(TIFFFileName(tif), "using top-left orientation"); img->orientation = ORIENTATION_TOPLEFT; /* fall thru... */ case ORIENTATION_TOPLEFT: y = h-1; break; } return (y); } /* * Get an tile-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; uint16 orientation; uint32 col, row, y; uint32 tw, th; u_char* buf; int32 fromskew, toskew; uint32 nrow; buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*put)(img, raster+y*w+col, col, y, npix, nrow, fromskew, toskew + fromskew, buf); } else { (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf); } } y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); } /* * Get an tile-organized image that has * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileSeparateRoutine put = img->put.separate; uint16 orientation; uint32 col, row, y; uint32 tw, th; u_char* buf; u_char* r; u_char* g; u_char* b; u_char* a; tsize_t tilesize; int32 fromskew, toskew; int alpha = img->alpha; uint32 nrow; tilesize = TIFFTileSize(tif); buf = (u_char*) _TIFFmalloc(4*tilesize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } r = buf; g = r + tilesize; b = g + tilesize; a = b + tilesize; if (!alpha) memset(a, 0xff, tilesize); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr) break; if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*put)(img, raster+y*w+col, col, y, npix, nrow, fromskew, toskew + fromskew, r, g, b, a); } else { (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, r, g, b, a); } } y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); } /* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; uint16 orientation; uint32 row, y, nrow; u_char* buf; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t scanline; int32 fromskew, toskew; buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for strip buffer"); return (0); } y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow*scanline) < 0 && img->stoponerr) break; (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf); y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); } /* * Get a strip-organized image with * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileSeparateRoutine put = img->put.separate; uint16 orientation; u_char *buf; u_char *r, *g, *b, *a; uint32 row, y, nrow; tsize_t scanline; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t stripsize; int32 fromskew, toskew; int alpha = img->alpha; stripsize = TIFFStripSize(tif); r = buf = (u_char *)_TIFFmalloc(4*stripsize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } g = r + stripsize; b = g + stripsize; a = b + stripsize; if (!alpha) memset(a, 0xff, stripsize); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), r, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1), g, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2), b, nrow*scanline) < 0 && img->stoponerr) break; if (alpha && (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3), a, nrow*scanline) < 0 && img->stoponerr)) break; (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, r, g, b, a); y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); } /* * The following routines move decoded data returned * from the TIFF library into rasters filled with packed * ABGR pixels (i.e. suitable for passing to lrecwrite.) * * The routines have been created according to the most * important cases and optimized. pickTileContigCase and * pickTileSeparateCase analyze the parameters and select * the appropriate "put" routine to use. */ #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 SKEW4(r,g,b,a,skew) { r += skew; g += skew; b += skew; a+= skew; } #define A1 ((uint32)(0xffL<<24)) #define PACK(r,g,b) \ ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|A1) #define PACK4(r,g,b,a) \ ((uint32)(r)|((uint32)(g)<<8)|((uint32)(b)<<16)|((uint32)(a)<<24)) #define W2B(v) (((v)>>8)&0xff) #define PACKW(r,g,b) \ ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|A1) #define PACKW4(r,g,b,a) \ ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) #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 \ ) /* * 8-bit palette => colormap/RGB */ DECLAREContigPutFunc(put8bitcmaptile) { uint32** PALmap = img->PALmap; (void) x; (void) y; while (h-- > 0) { UNROLL8(w, NOP, *cp++ = PALmap[*pp++][0]); cp += toskew; pp += fromskew; } } /* * 4-bit palette => colormap/RGB */ DECLAREContigPutFunc(put4bitcmaptile) { uint32** PALmap = img->PALmap; (void) x; (void) y; fromskew /= 2; while (h-- > 0) { uint32* bw; UNROLL2(w, bw = PALmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 2-bit palette => colormap/RGB */ DECLAREContigPutFunc(put2bitcmaptile) { uint32** PALmap = img->PALmap; (void) x; (void) y; fromskew /= 4; while (h-- > 0) { uint32* bw; UNROLL4(w, bw = PALmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 1-bit palette => colormap/RGB */ DECLAREContigPutFunc(put1bitcmaptile) { uint32** PALmap = img->PALmap; (void) x; (void) y; fromskew /= 8; while (h-- > 0) { uint32* bw; UNROLL8(w, bw = PALmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 8-bit greyscale => colormap/RGB */ DECLAREContigPutFunc(putgreytile) { uint32** BWmap = img->BWmap; (void) y; while (h-- > 0) { for (x = w; x-- > 0;) *cp++ = BWmap[*pp++][0]; cp += toskew; pp += fromskew; } } /* * 1-bit bilevel => colormap/RGB */ DECLAREContigPutFunc(put1bitbwtile) { uint32** BWmap = img->BWmap; (void) x; (void) y; fromskew /= 8; while (h-- > 0) { uint32* bw; UNROLL8(w, bw = BWmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 2-bit greyscale => colormap/RGB */ DECLAREContigPutFunc(put2bitbwtile) { uint32** BWmap = img->BWmap; (void) x; (void) y; fromskew /= 4; while (h-- > 0) { uint32* bw; UNROLL4(w, bw = BWmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 4-bit greyscale => colormap/RGB */ DECLAREContigPutFunc(put4bitbwtile) { uint32** BWmap = img->BWmap; (void) x; (void) y; fromskew /= 2; while (h-- > 0) { uint32* bw; UNROLL2(w, bw = BWmap[*pp++], *cp++ = *bw++); cp += toskew; pp += fromskew; } } /* * 8-bit packed samples, no Map => RGB */ DECLAREContigPutFunc(putRGBcontig8bittile) { int samplesperpixel = img->samplesperpixel; (void) x; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { UNROLL8(w, NOP, *cp++ = PACK(pp[0], pp[1], pp[2]); pp += samplesperpixel); cp += toskew; pp += fromskew; } } /* * 8-bit packed samples, w/ Map => RGB */ DECLAREContigPutFunc(putRGBcontig8bitMaptile) { TIFFRGBValue* Map = img->Map; int samplesperpixel = img->samplesperpixel; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = PACK(Map[pp[0]], Map[pp[1]], Map[pp[2]]); pp += samplesperpixel; } pp += fromskew; cp += toskew; } } /* * 8-bit packed samples => RGBA w/ associated alpha * (known to have Map == NULL) */ DECLAREContigPutFunc(putRGBAAcontig8bittile) { int samplesperpixel = img->samplesperpixel; (void) x; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { UNROLL8(w, NOP, *cp++ = PACK4(pp[0], pp[1], pp[2], pp[3]); pp += samplesperpixel); cp += toskew; pp += fromskew; } } /* * 8-bit packed samples => RGBA w/ unassociated alpha * (known to have Map == NULL) */ DECLAREContigPutFunc(putRGBUAcontig8bittile) { int samplesperpixel = img->samplesperpixel; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { uint32 r, g, b, a; for (x = w; x-- > 0;) { a = pp[3]; r = (pp[0] * a) / 255; g = (pp[1] * a) / 255; b = (pp[2] * a) / 255; *cp++ = PACK4(r,g,b,a); pp += samplesperpixel; } cp += toskew; pp += fromskew; } } /* * 16-bit packed samples => RGB */ DECLAREContigPutFunc(putRGBcontig16bittile) { int samplesperpixel = img->samplesperpixel; uint16 *wp = (uint16 *)pp; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = PACKW(wp[0], wp[1], wp[2]); wp += samplesperpixel; } cp += toskew; wp += fromskew; } } /* * 16-bit packed samples => RGBA w/ associated alpha * (known to have Map == NULL) */ DECLAREContigPutFunc(putRGBAAcontig16bittile) { int samplesperpixel = img->samplesperpixel; uint16 *wp = (uint16 *)pp; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { for (x = w; x-- > 0;) { *cp++ = PACKW4(wp[0], wp[1], wp[2], wp[3]); wp += samplesperpixel; } cp += toskew; wp += fromskew; } } /* * 16-bit packed samples => RGBA w/ unassociated alpha * (known to have Map == NULL) */ DECLAREContigPutFunc(putRGBUAcontig16bittile) { int samplesperpixel = img->samplesperpixel; uint16 *wp = (uint16 *)pp; (void) y; fromskew *= samplesperpixel; while (h-- > 0) { uint32 r,g,b,a; /* * We shift alpha down four bits just in case unsigned * arithmetic doesn't handle the full range. * We still have plenty of accuracy, since the output is 8 bits. * So we have (r * 0xffff) * (a * 0xfff)) = r*a * (0xffff*0xfff) * Since we want r*a * 0xff for eight bit output, * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. */ for (x = w; x-- > 0;) { a = wp[3] >> 4; r = (wp[0] * a) / 0x10eff; g = (wp[1] * a) / 0x10eff; b = (wp[2] * a) / 0x10eff; *cp++ = PACK4(r,g,b,a); wp += samplesperpixel; } cp += toskew; wp += fromskew; } } /* * 8-bit packed CMYK samples w/o Map => RGB * * NB: The conversion of CMYK->RGB is *very* crude. */ DECLAREContigPutFunc(putRGBcontig8bitCMYKtile) { int samplesperpixel = img->samplesperpixel; uint16 r, g, b, k; (void) x; (void) y; fromskew *= samplesperpixel; 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++ = PACK(r, g, b); pp += samplesperpixel); cp += toskew; pp += fromskew; } } /* * 8-bit packed CMYK samples w/Map => RGB * * NB: The conversion of CMYK->RGB is *very* crude. */ DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) { int samplesperpixel = img->samplesperpixel; TIFFRGBValue* Map = img->Map; uint16 r, g, b, k; (void) y; fromskew *= samplesperpixel; 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++ = PACK(Map[r], Map[g], Map[b]); pp += samplesperpixel; } pp += fromskew; cp += toskew; } } #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\ ) /* * 8-bit unpacked samples => RGB */ DECLARESepPutFunc(putRGBseparate8bittile) { (void) img; (void) x; (void) y; (void) a; while (h-- > 0) { UNROLL8(w, NOP, *cp++ = PACK(*r++, *g++, *b++)); SKEW(r, g, b, fromskew); cp += toskew; } } /* * 8-bit unpacked samples => RGB */ DECLARESepPutFunc(putRGBseparate8bitMaptile) { TIFFRGBValue* Map = img->Map; (void) y; (void) a; while (h-- > 0) { for (x = w; x > 0; x--) *cp++ = PACK(Map[*r++], Map[*g++], Map[*b++]); SKEW(r, g, b, fromskew); cp += toskew; } } /* * 8-bit unpacked samples => RGBA w/ associated alpha */ DECLARESepPutFunc(putRGBAAseparate8bittile) { (void) img; (void) x; (void) y; while (h-- > 0) { UNROLL8(w, NOP, *cp++ = PACK4(*r++, *g++, *b++, *a++)); SKEW4(r, g, b, a, fromskew); cp += toskew; } } /* * 8-bit unpacked samples => RGBA w/ unassociated alpha */ DECLARESepPutFunc(putRGBUAseparate8bittile) { (void) img; (void) y; while (h-- > 0) { uint32 rv, gv, bv, av; for (x = w; x-- > 0;) { av = *a++; rv = (*r++ * av) / 255; gv = (*g++ * av) / 255; bv = (*b++ * av) / 255; *cp++ = PACK4(rv,gv,bv,av); } SKEW4(r, g, b, a, fromskew); cp += toskew; } } /* * 16-bit unpacked samples => RGB */ DECLARESepPutFunc(putRGBseparate16bittile) { uint16 *wr = (uint16*) r; uint16 *wg = (uint16*) g; uint16 *wb = (uint16*) b; (void) img; (void) y; (void) a; while (h-- > 0) { for (x = 0; x < w; x++) *cp++ = PACKW(*wr++, *wg++, *wb++); SKEW(wr, wg, wb, fromskew); cp += toskew; } } /* * 16-bit unpacked samples => RGBA w/ associated alpha */ DECLARESepPutFunc(putRGBAAseparate16bittile) { uint16 *wr = (uint16*) r; uint16 *wg = (uint16*) g; uint16 *wb = (uint16*) b; uint16 *wa = (uint16*) a; (void) img; (void) y; while (h-- > 0) { for (x = 0; x < w; x++) *cp++ = PACKW4(*wr++, *wg++, *wb++, *wa++); SKEW4(wr, wg, wb, wa, fromskew); cp += toskew; } } /* * 16-bit unpacked samples => RGBA w/ unassociated alpha */ DECLARESepPutFunc(putRGBUAseparate16bittile) { uint16 *wr = (uint16*) r; uint16 *wg = (uint16*) g; uint16 *wb = (uint16*) b; uint16 *wa = (uint16*) a; (void) img; (void) y; while (h-- > 0) { uint32 r,g,b,a; /* * We shift alpha down four bits just in case unsigned * arithmetic doesn't handle the full range. * We still have plenty of accuracy, since the output is 8 bits. * So we have (r * 0xffff) * (a * 0xfff)) = r*a * (0xffff*0xfff) * Since we want r*a * 0xff for eight bit output, * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. */ for (x = w; x-- > 0;) { a = *wa++ >> 4; r = (*wr++ * a) / 0x10eff; g = (*wg++ * a) / 0x10eff; b = (*wb++ * a) / 0x10eff; *cp++ = PACK4(r,g,b,a); } SKEW4(wr, wg, wb, wa, fromskew); cp += toskew; } } /* * YCbCr -> RGB conversion and packing routines. The colorspace * conversion algorithm comes from the IJG v5a code; see below * for more information on how it works. */ #define YCbCrtoRGB(dst, yc) { \ int Y = (yc); \ dst = PACK( \ 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/ 4,4 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) { YCbCrSetup; uint32* cp1 = cp+w+toskew; uint32* cp2 = cp1+w+toskew; uint32* cp3 = cp2+w+toskew; int32 incr = 3*w+4*toskew; (void) y; /* XXX adjust fromskew */ for (; h >= 4; h -= 4) { x = w>>2; do { int Cb = pp[16]; int Cr = pp[17]; YCbCrtoRGB(cp [0], pp[ 0]); YCbCrtoRGB(cp [1], pp[ 1]); YCbCrtoRGB(cp [2], pp[ 2]); YCbCrtoRGB(cp [3], pp[ 3]); YCbCrtoRGB(cp1[0], pp[ 4]); YCbCrtoRGB(cp1[1], pp[ 5]); YCbCrtoRGB(cp1[2], pp[ 6]); YCbCrtoRGB(cp1[3], pp[ 7]); YCbCrtoRGB(cp2[0], pp[ 8]); YCbCrtoRGB(cp2[1], pp[ 9]); YCbCrtoRGB(cp2[2], pp[10]); YCbCrtoRGB(cp2[3], pp[11]); YCbCrtoRGB(cp3[0], pp[12]); YCbCrtoRGB(cp3[1], pp[13]); YCbCrtoRGB(cp3[2], pp[14]); YCbCrtoRGB(cp3[3], pp[15]); cp += 4, cp1 += 4, cp2 += 4, cp3 += 4; pp += 18; } while (--x); cp += incr, cp1 += incr, cp2 += incr, cp3 += incr; pp += fromskew; } } /* * 8-bit packed YCbCr samples w/ 4,2 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) { YCbCrSetup; uint32* cp1 = cp+w+toskew; int32 incr = 2*toskew+w; (void) y; /* XXX adjust fromskew */ for (; h >= 2; h -= 2) { x = w>>2; do { int Cb = pp[8]; int Cr = pp[9]; YCbCrtoRGB(cp [0], pp[0]); YCbCrtoRGB(cp [1], pp[1]); YCbCrtoRGB(cp [2], pp[2]); YCbCrtoRGB(cp [3], pp[3]); YCbCrtoRGB(cp1[0], pp[4]); YCbCrtoRGB(cp1[1], pp[5]); YCbCrtoRGB(cp1[2], pp[6]); YCbCrtoRGB(cp1[3], pp[7]); cp += 4, cp1 += 4; pp += 10; } while (--x); cp += incr, cp1 += incr; pp += fromskew; } } /* * 8-bit packed YCbCr samples w/ 4,1 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) { YCbCrSetup; (void) y; /* XXX adjust fromskew */ do { x = w>>2; do { int Cb = pp[4]; int Cr = pp[5]; YCbCrtoRGB(cp [0], pp[0]); YCbCrtoRGB(cp [1], pp[1]); YCbCrtoRGB(cp [2], pp[2]); YCbCrtoRGB(cp [3], pp[3]); cp += 4; pp += 6; } while (--x); cp += toskew; pp += fromskew; } while (--h); } /* * 8-bit packed YCbCr samples w/ 2,2 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) { YCbCrSetup; uint32* cp1 = cp+w+toskew; int32 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; } } /* * 8-bit packed YCbCr samples w/ 2,1 subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) { YCbCrSetup; (void) y; /* XXX adjust fromskew */ do { x = w>>1; do { int Cb = pp[2]; int Cr = pp[3]; YCbCrtoRGB(cp[0], pp[0]); YCbCrtoRGB(cp[1], pp[1]); cp += 2; pp += 4; } while (--x); cp += toskew; pp += fromskew; } while (--h); } /* * 8-bit packed YCbCr samples w/ no subsampling => RGB */ DECLAREContigPutFunc(putcontig8bitYCbCr11tile) { YCbCrSetup; (void) y; /* XXX adjust fromskew */ do { x = w>>1; do { int Cb = pp[1]; int Cr = pp[2]; YCbCrtoRGB(*cp++, pp[0]); pp += 3; } while (--x); cp += toskew; pp += fromskew; } while (--h); } #undef YCbCrSetup #undef YCbCrtoRGB #define LumaRed coeffs[0] #define LumaGreen coeffs[1] #define LumaBlue coeffs[2] #define SHIFT 16 #define FIX(x) ((int32)((x) * (1L<RGB conversion tables. The conversion * is done according to the 6.0 spec: * * R = Y + Cr*(2 - 2*LumaRed) * B = Y + Cb*(2 - 2*LumaBlue) * G = Y * - LumaBlue*Cb*(2-2*LumaBlue)/LumaGreen * - LumaRed*Cr*(2-2*LumaRed)/LumaGreen * * To avoid floating point arithmetic the fractional constants that * come out of the equations are represented as fixed point values * in the range 0...2^16. We also eliminate multiplications by * pre-calculating possible values indexed by Cb and Cr (this code * assumes conversion is being done for 8-bit samples). */ static void TIFFYCbCrToRGBInit(TIFFYCbCrToRGB* ycbcr, TIFF* tif) { TIFFRGBValue* clamptab; float* coeffs; int i; clamptab = (TIFFRGBValue*)( (tidata_t) ycbcr+TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long))); _TIFFmemset(clamptab, 0, 256); /* v < 0 => 0 */ ycbcr->clamptab = (clamptab += 256); for (i = 0; i < 256; i++) clamptab[i] = i; _TIFFmemset(clamptab+256, 255, 2*256); /* v > 255 => 255 */ TIFFGetFieldDefaulted(tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs); _TIFFmemcpy(ycbcr->coeffs, coeffs, 3*sizeof (float)); { float f1 = 2-2*LumaRed; int32 D1 = FIX(f1); float f2 = LumaRed*f1/LumaGreen; int32 D2 = -FIX(f2); float f3 = 2-2*LumaBlue; int32 D3 = FIX(f3); float f4 = LumaBlue*f3/LumaGreen; int32 D4 = -FIX(f4); int x; ycbcr->Cr_r_tab = (int*) (clamptab + 3*256); ycbcr->Cb_b_tab = ycbcr->Cr_r_tab + 256; ycbcr->Cr_g_tab = (int32*) (ycbcr->Cb_b_tab + 256); ycbcr->Cb_g_tab = ycbcr->Cr_g_tab + 256; /* * i is the actual input pixel value in the range 0..255 * Cb and Cr values are in the range -128..127 (actually * they are in a range defined by the ReferenceBlackWhite * tag) so there is some range shifting to do here when * constructing tables indexed by the raw pixel data. * * XXX handle ReferenceBlackWhite correctly to calculate * Cb/Cr values to use in constructing the tables. */ for (i = 0, x = -128; i < 256; i++, x++) { ycbcr->Cr_r_tab[i] = (int)((D1*x + ONE_HALF)>>SHIFT); ycbcr->Cb_b_tab[i] = (int)((D3*x + ONE_HALF)>>SHIFT); ycbcr->Cr_g_tab[i] = D2*x; ycbcr->Cb_g_tab[i] = D4*x + ONE_HALF; } } } #undef SHIFT #undef ONE_HALF #undef FIX #undef LumaBlue #undef LumaGreen #undef LumaRed static tileContigRoutine initYCbCrConversion(TIFFRGBAImage* img) { uint16 hs, vs; if (img->ycbcr == NULL) { img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) + 4*256*sizeof (TIFFRGBValue) + 2*256*sizeof (int) + 2*256*sizeof (int32) ); if (img->ycbcr == NULL) { TIFFError(TIFFFileName(img->tif), "No space for YCbCr->RGB conversion state"); return (NULL); } TIFFYCbCrToRGBInit(img->ycbcr, img->tif); } else { float* coeffs; TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &coeffs); if (_TIFFmemcmp(coeffs, img->ycbcr->coeffs, 3*sizeof (float)) != 0) TIFFYCbCrToRGBInit(img->ycbcr, img->tif); } /* * The 6.0 spec says that subsampling must be * one of 1, 2, or 4, and that vertical subsampling * must always be <= horizontal subsampling; so * there are only a few possibilities and we just * enumerate the cases. */ TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRSUBSAMPLING, &hs, &vs); switch ((hs<<4)|vs) { case 0x44: return (putcontig8bitYCbCr44tile); case 0x42: return (putcontig8bitYCbCr42tile); case 0x41: return (putcontig8bitYCbCr41tile); case 0x22: return (putcontig8bitYCbCr22tile); case 0x21: return (putcontig8bitYCbCr21tile); case 0x11: return (putcontig8bitYCbCr11tile); } return (NULL); } /* * Greyscale images with less than 8 bits/sample are handled * with a table to avoid lots of shifts and masks. The table * is setup so that put*bwtile (below) can retrieve 8/bitspersample * pixel values simply by indexing into the table with one * number. */ static int makebwmap(TIFFRGBAImage* img) { TIFFRGBValue* Map = img->Map; int bitspersample = img->bitspersample; int nsamples = 8 / bitspersample; int i; uint32* p; img->BWmap = (uint32**) _TIFFmalloc( 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); if (img->BWmap == NULL) { TIFFError(TIFFFileName(img->tif), "No space for B&W mapping table"); return (0); } p = (uint32*)(img->BWmap + 256); for (i = 0; i < 256; i++) { TIFFRGBValue c; img->BWmap[i] = p; switch (bitspersample) { #define GREY(x) c = Map[x]; *p++ = PACK(c,c,c); case 1: GREY(i>>7); GREY((i>>6)&1); GREY((i>>5)&1); GREY((i>>4)&1); GREY((i>>3)&1); GREY((i>>2)&1); GREY((i>>1)&1); GREY(i&1); break; case 2: GREY(i>>6); GREY((i>>4)&3); GREY((i>>2)&3); GREY(i&3); break; case 4: GREY(i>>4); GREY(i&0xf); break; case 8: GREY(i); break; } #undef GREY } return (1); } /* * Construct a mapping table to convert from the range * of the data samples to [0,255] --for display. This * process also handles inverting B&W images when needed. */ static int setupMap(TIFFRGBAImage* img) { int32 x, range; range = (int32)((1L<bitspersample)-1); img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); if (img->Map == NULL) { TIFFError(TIFFFileName(img->tif), "No space for photometric conversion table"); return (0); } if (img->photometric == PHOTOMETRIC_MINISWHITE) { for (x = 0; x <= range; x++) img->Map[x] = ((range - x) * 255) / range; } else { for (x = 0; x <= range; x++) img->Map[x] = (x * 255) / range; } if (img->bitspersample <= 8 && (img->photometric == PHOTOMETRIC_MINISBLACK || img->photometric == PHOTOMETRIC_MINISWHITE)) { /* * Use photometric mapping table to construct * unpacking tables for samples <= 8 bits. */ if (!makebwmap(img)) return (0); /* no longer need Map, free it */ _TIFFfree(img->Map), img->Map = NULL; } return (1); } static int checkcmap(TIFFRGBAImage* img) { uint16* r = img->redcmap; uint16* g = img->greencmap; uint16* b = img->bluecmap; long n = 1L<bitspersample; while (n-- > 0) if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) return (16); return (8); } static void cvtcmap(TIFFRGBAImage* img) { uint16* r = img->redcmap; uint16* g = img->greencmap; uint16* b = img->bluecmap; long i; for (i = (1L<bitspersample)-1; i >= 0; i--) { #define CVT(x) ((uint16)((x)>>8)) r[i] = CVT(r[i]); g[i] = CVT(g[i]); b[i] = CVT(b[i]); #undef CVT } } /* * Palette images with <= 8 bits/sample are handled * with a table to avoid lots of shifts and masks. The table * is setup so that put*cmaptile (below) can retrieve 8/bitspersample * pixel values simply by indexing into the table with one * number. */ static int makecmap(TIFFRGBAImage* img) { int bitspersample = img->bitspersample; int nsamples = 8 / bitspersample; uint16* r = img->redcmap; uint16* g = img->greencmap; uint16* b = img->bluecmap; uint32 *p; int i; img->PALmap = (uint32**) _TIFFmalloc( 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); if (img->PALmap == NULL) { TIFFError(TIFFFileName(img->tif), "No space for Palette mapping table"); return (0); } p = (uint32*)(img->PALmap + 256); for (i = 0; i < 256; i++) { TIFFRGBValue c; img->PALmap[i] = p; #define CMAP(x) c = x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); switch (bitspersample) { case 1: CMAP(i>>7); CMAP((i>>6)&1); CMAP((i>>5)&1); CMAP((i>>4)&1); CMAP((i>>3)&1); CMAP((i>>2)&1); CMAP((i>>1)&1); CMAP(i&1); break; case 2: CMAP(i>>6); CMAP((i>>4)&3); CMAP((i>>2)&3); CMAP(i&3); break; case 4: CMAP(i>>4); CMAP(i&0xf); break; case 8: CMAP(i); break; } #undef CMAP } return (1); } /* * Construct any mapping table used * by the associated put routine. */ static int buildMap(TIFFRGBAImage* img) { switch (img->photometric) { case PHOTOMETRIC_RGB: case PHOTOMETRIC_YCBCR: case PHOTOMETRIC_SEPARATED: if (img->bitspersample == 8) break; /* fall thru... */ case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_MINISWHITE: if (!setupMap(img)) return (0); break; case PHOTOMETRIC_PALETTE: /* * Convert 16-bit colormap to 8-bit (unless it looks * like an old-style 8-bit colormap). */ if (checkcmap(img) == 16) cvtcmap(img); else TIFFWarning(TIFFFileName(img->tif), "Assuming 8-bit colormap"); /* * Use mapping table and colormap to construct * unpacking tables for samples < 8 bits. */ if (img->bitspersample <= 8 && !makecmap(img)) return (0); break; } return (1); } /* * Select the appropriate conversion routine for packed data. */ static int pickTileContigCase(TIFFRGBAImage* img) { tileContigRoutine put = 0; if (buildMap(img)) { switch (img->photometric) { case PHOTOMETRIC_RGB: switch (img->bitspersample) { case 8: if (!img->Map) { if (img->alpha == EXTRASAMPLE_ASSOCALPHA) put = putRGBAAcontig8bittile; else if (img->alpha == EXTRASAMPLE_UNASSALPHA) put = putRGBUAcontig8bittile; else put = putRGBcontig8bittile; } else put = putRGBcontig8bitMaptile; break; case 16: put = putRGBcontig16bittile; if (!img->Map) { if (img->alpha == EXTRASAMPLE_ASSOCALPHA) put = putRGBAAcontig16bittile; else if (img->alpha == EXTRASAMPLE_UNASSALPHA) put = putRGBUAcontig16bittile; } break; } break; case PHOTOMETRIC_SEPARATED: if (img->bitspersample == 8) { if (!img->Map) put = putRGBcontig8bitCMYKtile; else put = putRGBcontig8bitCMYKMaptile; } break; case PHOTOMETRIC_PALETTE: switch (img->bitspersample) { case 8: put = put8bitcmaptile; break; case 4: put = put4bitcmaptile; break; case 2: put = put2bitcmaptile; break; case 1: put = put1bitcmaptile; break; } break; case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: switch (img->bitspersample) { case 8: put = putgreytile; break; case 4: put = put4bitbwtile; break; case 2: put = put2bitbwtile; break; case 1: put = put1bitbwtile; break; } break; case PHOTOMETRIC_YCBCR: if (img->bitspersample == 8) put = initYCbCrConversion(img); break; } } return ((img->put.contig = put) != 0); } /* * Select the appropriate conversion routine for unpacked data. * * NB: we assume that unpacked single channel data is directed * to the "packed routines. */ static int pickTileSeparateCase(TIFFRGBAImage* img) { tileSeparateRoutine put = 0; if (buildMap(img)) { switch (img->photometric) { case PHOTOMETRIC_RGB: switch (img->bitspersample) { case 8: if (!img->Map) { if (img->alpha == EXTRASAMPLE_ASSOCALPHA) put = putRGBAAseparate8bittile; else if (img->alpha == EXTRASAMPLE_UNASSALPHA) put = putRGBUAseparate8bittile; else put = putRGBseparate8bittile; } else put = putRGBseparate8bitMaptile; break; case 16: put = putRGBseparate16bittile; if (!img->Map) { if (img->alpha == EXTRASAMPLE_ASSOCALPHA) put = putRGBAAseparate16bittile; else if (img->alpha == EXTRASAMPLE_UNASSALPHA) put = putRGBUAseparate16bittile; } break; } break; } } return ((img->put.separate = put) != 0); }