X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/50b27824dad1acdafef87c91a84fc986e6adbf49..cc9a39576ab6edb139c9bb77d01f4118853e04d2:/src/tiff/tif_getimage.c diff --git a/src/tiff/tif_getimage.c b/src/tiff/tif_getimage.c index 810885e851..f69fbc17aa 100644 --- a/src/tiff/tif_getimage.c +++ b/src/tiff/tif_getimage.c @@ -4,23 +4,23 @@ * Copyright (c) 1991-1997 Sam Leffler * Copyright (c) 1991-1997 Silicon Graphics, Inc. * - * Permission to use, copy, modify, distribute, and sell this software and + * 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. - * + * + * 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 + * 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. */ @@ -33,15 +33,37 @@ #include #include -static int LINKAGEMODE gtTileContig(TIFFRGBAImage*, uint32*, uint32, uint32); -static int LINKAGEMODE gtTileSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); -static int LINKAGEMODE gtStripContig(TIFFRGBAImage*, uint32*, uint32, uint32); -static int LINKAGEMODE gtStripSeparate(TIFFRGBAImage*, uint32*, uint32, uint32); -static int LINKAGEMODE pickTileContigCase(TIFFRGBAImage*); -static int LINKAGEMODE pickTileSeparateCase(TIFFRGBAImage*); +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"; +/* + * Helper constants used in Orientation tag handling + */ +#define FLIP_VERTICALLY 0x01 +#define FLIP_HORIZONTALLY 0x02 + +/* + * Color conversion constants. We will define display types here. + */ + +TIFFDisplay display_sRGB = { + { /* XYZ -> luminance matrix */ + { 3.2410F, -1.5374F, -0.4986F }, + { -0.9692F, 1.8760F, 0.0416F }, + { 0.0556F, -0.2040F, 1.0570F } + }, + 100.0F, 100.0F, 100.0F, /* Light o/p for reference white */ + 255, 255, 255, /* Pixel values for ref. white */ + 1.0F, 1.0F, 1.0F, /* Residual light o/p for black pixel */ + 2.4F, 2.4F, 2.4F, /* Gamma values for the three guns */ +}; + /* * Check the image to see if TIFFReadRGBAImage can deal with it. * 1/0 is returned according to whether or not the image can @@ -55,6 +77,10 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) uint16 photometric; int colorchannels; + if (!tif->tif_decodestatus) { + sprintf(emsg, "Sorry, requested compression method is not configured"); + return (0); + } switch (td->td_bitspersample) { case 1: case 2: case 4: case 8: case 16: @@ -82,13 +108,22 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_PALETTE: - if (td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_samplesperpixel != 1) { + if (td->td_planarconfig == PLANARCONFIG_CONTIG + && td->td_samplesperpixel != 1 + && td->td_bitspersample < 8 ) { sprintf(emsg, - "Sorry, can not handle contiguous data with %s=%d, and %s=%d", - photoTag, photometric, - "Samples/pixel", td->td_samplesperpixel); + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, photometric, + "Samples/pixel", td->td_samplesperpixel, + td->td_bitspersample); return (0); } + /* + ** We should likely validate that any extra samples are either + ** to be ignored, or are alpha, and if alpha we should try to use + ** them. But for now we won't bother with this. + */ break; case PHOTOMETRIC_YCBCR: if (td->td_planarconfig != PLANARCONFIG_CONTIG) { @@ -97,27 +132,25 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) return (0); } break; - case PHOTOMETRIC_RGB: + 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) { + 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", @@ -138,6 +171,8 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) return (0); } break; + case PHOTOMETRIC_CIELAB: + break; default: sprintf(emsg, "Sorry, can not handle image with %s=%d", photoTag, photometric); @@ -149,20 +184,22 @@ TIFFRGBAImageOK(TIFF* tif, char emsg[1024]) 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; - - if( img->redcmap ) { - _TIFFfree( img->redcmap ); - _TIFFfree( img->greencmap ); - _TIFFfree( img->bluecmap ); - } + 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; + if (img->cielab) + _TIFFfree(img->cielab), img->cielab = NULL; + + if( img->redcmap ) { + _TIFFfree( img->redcmap ); + _TIFFfree( img->greencmap ); + _TIFFfree( img->bluecmap ); + } } static int @@ -193,7 +230,8 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) img->redcmap = NULL; img->greencmap = NULL; img->bluecmap = NULL; - + img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */ + img->tif = tif; img->stoponerr = stop; TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); @@ -202,7 +240,7 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) case 8: case 16: break; default: - sprintf(emsg, "Sorry, can not image with %d-bit samples", + sprintf(emsg, "Sorry, can not handle images with %d-bit samples", img->bitspersample); return (0); } @@ -211,12 +249,32 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (extrasamples == 1) + { switch (sampleinfo[0]) { + case EXTRASAMPLE_UNSPECIFIED: /* Workaround for some images without */ + if (img->samplesperpixel == 4) /* correct info about alpha channel */ + img->alpha = EXTRASAMPLE_ASSOCALPHA; + break; case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ - img->alpha = sampleinfo[0]; - break; + img->alpha = sampleinfo[0]; + break; } + } + +#if DEFAULT_EXTRASAMPLE_AS_ALPHA == 1 + if( !TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) + img->photometric = PHOTOMETRIC_MINISWHITE; + + if( extrasamples == 0 + && img->samplesperpixel == 4 + && img->photometric == PHOTOMETRIC_RGB ) + { + img->alpha = EXTRASAMPLE_ASSOCALPHA; + extrasamples = 1; + } +#endif + colorchannels = img->samplesperpixel - extrasamples; TIFFGetFieldDefaulted(tif, TIFFTAG_COMPRESSION, &compress); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); @@ -257,15 +315,19 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) memcpy( img->redcmap, red_orig, n_color * 2 ); memcpy( img->greencmap, green_orig, n_color * 2 ); memcpy( img->bluecmap, blue_orig, n_color * 2 ); - + /* fall thru... */ case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: - if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) { + if (planarconfig == PLANARCONFIG_CONTIG + && img->samplesperpixel != 1 + && img->bitspersample < 8 ) { sprintf(emsg, - "Sorry, can not handle contiguous data with %s=%d, and %s=%d", - photoTag, img->photometric, - "Samples/pixel", img->samplesperpixel); + "Sorry, can not handle contiguous data with %s=%d, " + "and %s=%d and Bits/Sample=%d", + photoTag, img->photometric, + "Samples/pixel", img->samplesperpixel, + img->bitspersample); return (0); } break; @@ -276,14 +338,22 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) return (0); } /* It would probably be nice to have a reality check here. */ - if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { + if (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; - } + switch (compress) { + case COMPRESSION_OJPEG: + case COMPRESSION_JPEG: + TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); + img->photometric = PHOTOMETRIC_RGB; + break; + + default: + /* do nothing */; + break; + } break; - case PHOTOMETRIC_RGB: + case PHOTOMETRIC_RGB: if (colorchannels < 3) { sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", "Color channels", colorchannels); @@ -298,7 +368,7 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) "InkSet", inkset); return (0); } - if (img->samplesperpixel != 4) { + if (img->samplesperpixel < 4) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "Samples/pixel", img->samplesperpixel); return (0); @@ -330,6 +400,8 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) img->photometric = PHOTOMETRIC_RGB; /* little white lie */ img->bitspersample = 8; break; + case PHOTOMETRIC_CIELAB: + break; default: sprintf(emsg, "Sorry, can not handle image with %s=%d", photoTag, img->photometric); @@ -339,6 +411,7 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) img->BWmap = NULL; img->PALmap = NULL; img->ycbcr = NULL; + img->cielab = NULL; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); @@ -346,12 +419,11 @@ TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); if (img->isContig) { img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig; - (void) pickTileContigCase(img); + return pickTileContigCase(img); } else { img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate; - (void) pickTileSeparateCase(img); + return pickTileSeparateCase(img); } - return (1); } int @@ -370,17 +442,21 @@ TIFFRGBAImageGet(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) } /* - * Read the specified image into an ABGR-format raster. + * Read the specified image into an ABGR-format rastertaking in account + * specified orientation. */ int -TIFFReadRGBAImage(TIFF* tif, - uint32 rwidth, uint32 rheight, uint32* raster, int stop) +TIFFReadRGBAImageOriented(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, + int orientation, int stop) { char emsg[1024]; TIFFRGBAImage img; int ok; - if (TIFFRGBAImageBegin(&img, tif, stop, emsg)) { + if (TIFFRGBAImageOK(tif, emsg) && + TIFFRGBAImageBegin(&img, tif, stop, emsg)) { + img.req_orientation = orientation; /* XXX verify rwidth and rheight against width and height */ ok = TIFFRGBAImageGet(&img, raster+(rheight-img.height)*rwidth, rwidth, img.height); @@ -392,34 +468,77 @@ TIFFReadRGBAImage(TIFF* tif, return (ok); } -static uint32 -setorientation(TIFFRGBAImage* img, uint32 h) +/* + * Read the specified image into an ABGR-format raster. Use bottom left + * origin for raster by default. + */ +int +TIFFReadRGBAImage(TIFF* tif, + uint32 rwidth, uint32 rheight, uint32* raster, int stop) { - 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); + return TIFFReadRGBAImageOriented(tif, rwidth, rheight, raster, + ORIENTATION_BOTLEFT, stop); +} + +static int +setorientation(TIFFRGBAImage* img) +{ + switch (img->orientation) { + case ORIENTATION_TOPLEFT: + case ORIENTATION_LEFTTOP: + if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_TOPRIGHT: + case ORIENTATION_RIGHTTOP: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else + return 0; + case ORIENTATION_BOTRIGHT: + case ORIENTATION_RIGHTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTLEFT || + img->req_orientation == ORIENTATION_LEFTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + case ORIENTATION_BOTLEFT: + case ORIENTATION_LEFTBOT: + if (img->req_orientation == ORIENTATION_TOPLEFT || + img->req_orientation == ORIENTATION_LEFTTOP) + return FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_TOPRIGHT || + img->req_orientation == ORIENTATION_RIGHTTOP) + return FLIP_HORIZONTALLY | FLIP_VERTICALLY; + else if (img->req_orientation == ORIENTATION_BOTRIGHT || + img->req_orientation == ORIENTATION_RIGHTBOT) + return FLIP_HORIZONTALLY; + else + return 0; + default: /* NOTREACHED */ + return 0; + } } /* @@ -433,47 +552,86 @@ 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 col, row, y, rowstoread; + uint32 pos; uint32 tw, th; u_char* buf; int32 fromskew, toskew; uint32 nrow; + int ret = 1, flip; buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } + _TIFFmemset(buf, 0, TIFFTileSize(tif)); 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+img->col_offset, + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, buf, col+img->col_offset, row+img->row_offset, 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); + { + ret = 0; + break; + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + 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 + pos); + } + else + { + (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf + pos); + } + } + + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); - return (1); + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + + return (ret); } /* @@ -487,8 +645,8 @@ 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 col, row, y, rowstoread; + uint32 pos; uint32 tw, th; u_char* buf; u_char* r; @@ -499,6 +657,7 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) int32 fromskew, toskew; int alpha = img->alpha; uint32 nrow; + int ret = 1, flip; tilesize = TIFFTileSize(tif); buf = (u_char*) _TIFFmalloc(4*tilesize); @@ -506,6 +665,7 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } + _TIFFmemset(buf, 0, 4*tilesize); r = buf; g = r + tilesize; b = g + tilesize; @@ -514,43 +674,88 @@ gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 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+img->col_offset, + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(tw + w); + } + else { + y = 0; + toskew = -(int32)(tw - w); + } + + for (row = 0; row < h; row += nrow) + { + rowstoread = th - (row + img->row_offset) % th; + nrow = (row + rowstoread > h ? h - row : rowstoread); + for (col = 0; col < w; col += tw) + { + if (TIFFReadTile(tif, r, col+img->col_offset, row+img->row_offset,0,0) < 0 && img->stoponerr) - break; - if (TIFFReadTile(tif, g, col+img->col_offset, + { + ret = 0; + break; + } + if (TIFFReadTile(tif, g, col+img->col_offset, row+img->row_offset,0,1) < 0 && img->stoponerr) - break; - if (TIFFReadTile(tif, b, col+img->col_offset, + { + ret = 0; + break; + } + if (TIFFReadTile(tif, b, col+img->col_offset, row+img->row_offset,0,2) < 0 && img->stoponerr) - break; - if (alpha && TIFFReadTile(tif,a,col+img->col_offset, - row+img->row_offset,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); + { + ret = 0; + break; + } + if (alpha && TIFFReadTile(tif,a,col+img->col_offset, + row+img->row_offset,0,3) < 0 && img->stoponerr) + { + ret = 0; + break; + } + + pos = ((row+img->row_offset) % th) * TIFFTileRowSize(tif); + + 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 + pos, g + pos, b + pos, a + pos); + } else { + (*put)(img, raster+y*w+col, col, y, + tw, nrow, 0, toskew, r + pos, g + pos, b + pos, a + pos); + } + } + + y += (flip & FLIP_VERTICALLY ?-(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } } - } - y += (orientation == ORIENTATION_TOPLEFT ? - -(int32) nrow : (int32) nrow); } + _TIFFfree(buf); - return (1); + return (ret); } /* @@ -564,38 +769,71 @@ gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; - uint16 orientation; - uint32 row, y, nrow; + uint32 row, y, nrow, rowstoread; + uint32 pos; u_char* buf; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t scanline; int32 fromskew, toskew; + int ret = 1, flip; 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); + _TIFFmemset(buf, 0, TIFFStripSize(tif)); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } else { + y = 0; + toskew = -(int32)(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, + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif,row+img->row_offset, 0), - buf, nrow*scanline) < 0 + buf, + ((row + img->row_offset)%rowsperstrip + 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); + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf + pos); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } + } + _TIFFfree(buf); - return (1); + return (ret); } /* @@ -609,16 +847,17 @@ 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; + uint32 row, y, nrow, rowstoread; + uint32 pos; tsize_t scanline; uint32 rowsperstrip, offset_row; uint32 imagewidth = img->width; tsize_t stripsize; int32 fromskew, toskew; int alpha = img->alpha; + int ret = 1, flip; stripsize = TIFFStripSize(tif); r = buf = (u_char *)_TIFFmalloc(4*stripsize); @@ -626,39 +865,85 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } + _TIFFmemset(buf, 0, 4*stripsize); 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); + + flip = setorientation(img); + if (flip & FLIP_VERTICALLY) { + y = h - 1; + toskew = -(int32)(w + w); + } + else { + y = 0; + toskew = -(int32)(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); + for (row = 0; row < h; row += nrow) + { + rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; + nrow = (row + rowstoread > h ? h - row : rowstoread); offset_row = row + img->row_offset; - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), - r, nrow*scanline) < 0 && img->stoponerr) - break; - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), - g, nrow*scanline) < 0 && img->stoponerr) - break; - if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), - b, nrow*scanline) < 0 && img->stoponerr) - break; - if (alpha && - (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_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); + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 0), + r, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 1), + g, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 2), + b, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr) + { + ret = 0; + break; + } + if (alpha && + (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, offset_row, 3), + a, ((row + img->row_offset)%rowsperstrip + nrow) * scanline) < 0 + && img->stoponerr)) + { + ret = 0; + break; + } + + pos = ((row + img->row_offset) % rowsperstrip) * scanline; + (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, r + pos, g + pos, + b + pos, a + pos); + y += (flip & FLIP_VERTICALLY ? -(int32) nrow : (int32) nrow); + } + + if (flip & FLIP_HORIZONTALLY) { + uint32 line; + + for (line = 0; line < h; line++) { + uint32 *left = raster + (line * w); + uint32 *right = left + w - 1; + + while ( left < right ) { + uint32 temp = *left; + *left = *right; + *right = temp; + left++, right--; + } + } } + _TIFFfree(buf); - return (1); + return (ret); } /* @@ -716,7 +1001,7 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) 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; } @@ -732,7 +1017,7 @@ gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) ((uint32)W2B(r)|((uint32)W2B(g)<<8)|((uint32)W2B(b)<<16)|((uint32)W2B(a)<<24)) #define DECLAREContigPutFunc(name) \ -static void LINKAGEMODE name(\ +static void name(\ TIFFRGBAImage* img, \ uint32* cp, \ uint32 x, uint32 y, \ @@ -747,10 +1032,15 @@ static void LINKAGEMODE name(\ DECLAREContigPutFunc(put8bitcmaptile) { uint32** PALmap = img->PALmap; + int samplesperpixel = img->samplesperpixel; - (void) x; (void) y; + (void) y; while (h-- > 0) { - UNROLL8(w, NOP, *cp++ = PALmap[*pp++][0]); + for (x = w; x-- > 0;) + { + *cp++ = PALmap[*pp][0]; + pp += samplesperpixel; + } cp += toskew; pp += fromskew; } @@ -812,12 +1102,41 @@ DECLAREContigPutFunc(put1bitcmaptile) */ DECLAREContigPutFunc(putgreytile) { + int samplesperpixel = img->samplesperpixel; uint32** BWmap = img->BWmap; (void) y; while (h-- > 0) { for (x = w; x-- > 0;) - *cp++ = BWmap[*pp++][0]; + { + *cp++ = BWmap[*pp][0]; + pp += samplesperpixel; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * 16-bit greyscale => colormap/RGB + */ +DECLAREContigPutFunc(put16bitbwtile) +{ + int samplesperpixel = img->samplesperpixel; + uint32** BWmap = img->BWmap; + + (void) y; + while (h-- > 0) { + uint16 *wp = (uint16 *) pp; + + for (x = w; x-- > 0;) + { + /* use high order byte of 16bit value */ + + *cp++ = BWmap[*wp >> 8][0]; + pp += 2 * samplesperpixel; + wp += samplesperpixel; + } cp += toskew; pp += fromskew; } @@ -1019,7 +1338,7 @@ DECLAREContigPutFunc(putRGBUAcontig16bittile) * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. */ for (x = w; x-- > 0;) { - a = wp[3] >> 4; + a = wp[3] >> 4; r = (wp[0] * a) / 0x10eff; g = (wp[1] * a) / 0x10eff; b = (wp[2] * a) / 0x10eff; @@ -1084,7 +1403,7 @@ DECLAREContigPutFunc(putRGBcontig8bitCMYKMaptile) } #define DECLARESepPutFunc(name) \ -static void LINKAGEMODE name(\ +static void name(\ TIFFRGBAImage* img,\ uint32* cp,\ uint32 x, uint32 y, \ @@ -1214,7 +1533,7 @@ DECLARESepPutFunc(putRGBUAseparate16bittile) * we divide by (0xffff * 0xfff) / 0xff == 0x10eff. */ for (x = w; x-- > 0;) { - a = *wa++ >> 4; + a = *wa++ >> 4; r = (*wr++ * a) / 0x10eff; g = (*wg++ * a) / 0x10eff; b = (*wb++ * a) / 0x10eff; @@ -1226,44 +1545,89 @@ DECLARESepPutFunc(putRGBUAseparate16bittile) } /* - * 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. + * 8-bit packed CIE L*a*b 1976 samples => RGB + */ +DECLAREContigPutFunc(putcontig8bitCIELab) +{ + float X, Y, Z; + uint32 r, g, b; + (void) y; + fromskew *= 3; + while (h-- > 0) { + for (x = w; x-- > 0;) { + TIFFCIELabToXYZ(img->cielab, + (u_char)pp[0], + (signed char)pp[1], + (signed char)pp[2], + &X, &Y, &Z); + TIFFXYZToRGB(img->cielab, X, Y, Z, &r, &g, &b); + *cp++ = PACK(r, g, b); + pp += 3; + } + cp += toskew; + pp += fromskew; + } +} + +/* + * YCbCr -> RGB conversion and packing routines. */ -#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 YCbCrtoRGB(dst, Y) { \ + uint32 r, g, b; \ + TIFFYCbCrtoRGB(img->ycbcr, (Y), Cb, Cr, &r, &g, &b); \ + dst = PACK(r, g, b); \ } -#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 + * 8-bit packed YCbCr samples => RGB + * This function is generic for different sampling sizes, + * and can handle blocks sizes that aren't multiples of the + * sampling size. However, it is substantially less optimized + * than the specific sampling cases. It is used as a fallback + * for difficult blocks. */ -DECLAREContigPutFunc(putcontig8bitYCbCr44tile) +#ifdef notdef +static void putcontig8bitYCbCrGenericTile( + TIFFRGBAImage* img, + uint32* cp, + uint32 x, uint32 y, + uint32 w, uint32 h, + int32 fromskew, int32 toskew, + u_char* pp, + int h_group, + int v_group ) + { - YCbCrSetup; uint32* cp1 = cp+w+toskew; uint32* cp2 = cp1+w+toskew; uint32* cp3 = cp2+w+toskew; int32 incr = 3*w+4*toskew; + int32 Cb, Cr; + int group_size = v_group * h_group + 2; (void) y; - /* XXX adjust fromskew */ + fromskew = (fromskew * group_size) / h_group; + + for( yy = 0; yy < h; yy++ ) + { + u_char *pp_line; + int y_line_group = yy / v_group; + int y_remainder = yy - y_line_group * v_group; + + pp_line = pp + v_line_group * + + + for( xx = 0; xx < w; xx++ ) + { + Cb = pp + } + } for (; h >= 4; h -= 4) { x = w>>2; do { - int Cb = pp[16]; - int Cr = pp[17]; + Cb = pp[16]; + Cr = pp[17]; YCbCrtoRGB(cp [0], pp[ 0]); YCbCrtoRGB(cp [1], pp[ 1]); @@ -1289,38 +1653,180 @@ DECLAREContigPutFunc(putcontig8bitYCbCr44tile) pp += fromskew; } } +#endif + +/* + * 8-bit packed YCbCr samples w/ 4,4 subsampling => RGB + */ +DECLAREContigPutFunc(putcontig8bitYCbCr44tile) +{ + uint32* cp1 = cp+w+toskew; + uint32* cp2 = cp1+w+toskew; + uint32* cp3 = cp2+w+toskew; + int32 incr = 3*w+4*toskew; + + (void) y; + /* adjust fromskew */ + fromskew = (fromskew * 18) / 4; + if ((h & 3) == 0 && (w & 3) == 0) { + for (; h >= 4; h -= 4) { + x = w>>2; + do { + int32 Cb = pp[16]; + int32 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; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[16]; + int32 Cr = pp[17]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp3[3], pp[15]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[3], pp[11]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp3[2], pp[14]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[2], pp[10]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp3[1], pp[13]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[1], pp[ 9]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp3[0], pp[12]); /* FALLTHROUGH */ + case 3: YCbCrtoRGB(cp2[0], pp[ 8]); /* FALLTHROUGH */ + case 2: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; cp2 += x; cp3 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; cp2 += 4; cp3 += 4; + x -= 4; + } + pp += 18; + } + if (h <= 4) + break; + h -= 4; + 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; + fromskew = (fromskew * 10) / 4; + if ((h & 3) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>2; + do { + int32 Cb = pp[8]; + int32 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; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[8]; + int32 Cr = pp[9]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[3], pp[ 7]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [3], pp[ 3]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 3: + switch (h) { + default: YCbCrtoRGB(cp1[2], pp[ 6]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [2], pp[ 2]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 2: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 5]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 4]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 4) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 4; cp1 += 4; + x -= 4; + } + pp += 10; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } } } @@ -1329,15 +1835,13 @@ DECLAREContigPutFunc(putcontig8bitYCbCr42tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) { - YCbCrSetup; - (void) y; /* XXX adjust fromskew */ do { x = w>>2; do { - int Cb = pp[4]; - int Cr = pp[5]; + int32 Cb = pp[4]; + int32 Cr = pp[5]; YCbCrtoRGB(cp [0], pp[0]); YCbCrtoRGB(cp [1], pp[1]); @@ -1347,9 +1851,27 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) cp += 4; pp += 6; } while (--x); + + if( (w&3) != 0 ) + { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + + switch( (w&3) ) { + case 3: YCbCrtoRGB(cp [2], pp[2]); + case 2: YCbCrtoRGB(cp [1], pp[1]); + case 1: YCbCrtoRGB(cp [0], pp[0]); + case 0: break; + } + + cp += (w&3); + pp += 6; + } + cp += toskew; pp += fromskew; } while (--h); + } /* @@ -1357,28 +1879,62 @@ DECLAREContigPutFunc(putcontig8bitYCbCr41tile) */ 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; + fromskew = (fromskew * 6) / 2; + if ((h & 1) == 0 && (w & 1) == 0) { + for (; h >= 2; h -= 2) { + x = w>>1; + do { + int32 Cb = pp[4]; + int32 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; + } + } else { + while (h > 0) { + for (x = w; x > 0;) { + int32 Cb = pp[4]; + int32 Cr = pp[5]; + switch (x) { + default: + switch (h) { + default: YCbCrtoRGB(cp1[1], pp[ 3]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [1], pp[ 1]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + case 1: + switch (h) { + default: YCbCrtoRGB(cp1[0], pp[ 2]); /* FALLTHROUGH */ + case 1: YCbCrtoRGB(cp [0], pp[ 0]); /* FALLTHROUGH */ + } /* FALLTHROUGH */ + } + if (x < 2) { + cp += x; cp1 += x; + x = 0; + } + else { + cp += 2; cp1 += 2; + x -= 2; + } + pp += 6; + } + if (h <= 2) + break; + h -= 2; + cp += incr, cp1 += incr; + pp += fromskew; + } } } @@ -1387,22 +1943,32 @@ DECLAREContigPutFunc(putcontig8bitYCbCr22tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) { - YCbCrSetup; - (void) y; - /* XXX adjust fromskew */ + fromskew = (fromskew * 4) / 2; do { x = w>>1; do { - int Cb = pp[2]; - int Cr = pp[3]; + int32 Cb = pp[2]; + int32 Cr = pp[3]; - YCbCrtoRGB(cp[0], pp[0]); + YCbCrtoRGB(cp[0], pp[0]); YCbCrtoRGB(cp[1], pp[1]); cp += 2; pp += 4; } while (--x); + + if( (w&1) != 0 ) + { + int32 Cb = pp[2]; + int32 Cr = pp[3]; + + YCbCrtoRGB(cp [0], pp[0]); + + cp += 1; + pp += 4; + } + cp += toskew; pp += fromskew; } while (--h); @@ -1413,15 +1979,13 @@ DECLAREContigPutFunc(putcontig8bitYCbCr21tile) */ DECLAREContigPutFunc(putcontig8bitYCbCr11tile) { - YCbCrSetup; - (void) y; - /* XXX adjust fromskew */ + fromskew *= 3; do { - x = w>>1; + x = w; /* was x = w>>1; patched 2000/09/25 warmerda@home.com */ do { - int Cb = pp[1]; - int Cr = pp[2]; + int32 Cb = pp[1]; + int32 Cr = pp[2]; YCbCrtoRGB(*cp++, pp[0]); @@ -1431,125 +1995,87 @@ DECLAREContigPutFunc(putcontig8bitYCbCr11tile) 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) +static tileContigRoutine +initYCbCrConversion(TIFFRGBAImage* img) { - TIFFRGBValue* clamptab; - float* coeffs; - int i; + static char module[] = "initCIELabConversion"; - 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; - } - } + float *luma, *refBlackWhite; + uint16 hs, vs; + + if (img->ycbcr == NULL) { + img->ycbcr = (TIFFYCbCrToRGB*) _TIFFmalloc( + TIFFroundup(sizeof (TIFFYCbCrToRGB), sizeof (long)) + + 4*256*sizeof (TIFFRGBValue) + + 2*256*sizeof (int) + + 3*256*sizeof (int32) + ); + if (img->ycbcr == NULL) { + TIFFError(module, + "No space for YCbCr->RGB conversion state"); + return (NULL); + } + } + + TIFFGetFieldDefaulted(img->tif, TIFFTAG_YCBCRCOEFFICIENTS, &luma); + TIFFGetFieldDefaulted(img->tif, TIFFTAG_REFERENCEBLACKWHITE, + &refBlackWhite); + if (TIFFYCbCrToRGBInit(img->ycbcr, luma, refBlackWhite) < 0) + return NULL; + + /* + * 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); } -#undef SHIFT -#undef ONE_HALF -#undef FIX -#undef LumaBlue -#undef LumaGreen -#undef LumaRed static tileContigRoutine -initYCbCrConversion(TIFFRGBAImage* img) +initCIELabConversion(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); + static char module[] = "initCIELabConversion"; + + float *whitePoint; + float refWhite[3]; + + if (!img->cielab) { + img->cielab = (TIFFCIELabToRGB *) + _TIFFmalloc(sizeof(TIFFCIELabToRGB)); + if (!img->cielab) { + TIFFError(module, + "No space for CIE L*a*b*->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); + TIFFGetFieldDefaulted(img->tif, TIFFTAG_WHITEPOINT, &whitePoint); + refWhite[1] = 100.0F; + refWhite[0] = whitePoint[0] / whitePoint[1] * refWhite[1]; + refWhite[2] = (1.0F - whitePoint[0] - whitePoint[1]) + / whitePoint[1] * refWhite[1]; + if (TIFFCIELabToRGBInit(img->cielab, &display_sRGB, refWhite) < 0) { + TIFFError(module, + "Failed to initialize CIE L*a*b*->RGB conversion state."); + _TIFFfree(img->cielab); + return NULL; + } + + return &putcontig8bitCIELab; } /* @@ -1568,6 +2094,9 @@ makebwmap(TIFFRGBAImage* img) int i; uint32* p; + if( nsamples == 0 ) + nsamples = 1; + img->BWmap = (uint32**) _TIFFmalloc( 256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32))); if (img->BWmap == NULL) { @@ -1601,6 +2130,7 @@ makebwmap(TIFFRGBAImage* img) GREY(i&0xf); break; case 8: + case 16: GREY(i); break; } @@ -1613,13 +2143,18 @@ makebwmap(TIFFRGBAImage* img) * 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); + + /* treat 16 bit the same as eight bit */ + if( img->bitspersample == 16 ) + range = (int32) 255; + img->Map = (TIFFRGBValue*) _TIFFmalloc((range+1) * sizeof (TIFFRGBValue)); if (img->Map == NULL) { TIFFError(TIFFFileName(img->tif), @@ -1628,12 +2163,12 @@ setupMap(TIFFRGBAImage* img) } if (img->photometric == PHOTOMETRIC_MINISWHITE) { for (x = 0; x <= range; x++) - img->Map[x] = ((range - x) * 255) / range; + img->Map[x] = (TIFFRGBValue) (((range - x) * 255) / range); } else { for (x = 0; x <= range; x++) - img->Map[x] = (x * 255) / range; + img->Map[x] = (TIFFRGBValue) ((x * 255) / range); } - if (img->bitspersample <= 8 && + if (img->bitspersample <= 16 && (img->photometric == PHOTOMETRIC_MINISBLACK || img->photometric == PHOTOMETRIC_MINISWHITE)) { /* @@ -1707,7 +2242,7 @@ makecmap(TIFFRGBAImage* img) 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); +#define CMAP(x) c = (TIFFRGBValue) x; *p++ = PACK(r[c]&0xff, g[c]&0xff, b[c]&0xff); switch (bitspersample) { case 1: CMAP(i>>7); @@ -1738,7 +2273,7 @@ makecmap(TIFFRGBAImage* img) return (1); } -/* +/* * Construct any mapping table used * by the associated put routine. */ @@ -1830,16 +2365,21 @@ pickTileContigCase(TIFFRGBAImage* img) 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; + case 16: put = put16bitbwtile; break; + 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; + case PHOTOMETRIC_CIELAB: + if (img->bitspersample == 8) + put = initCIELabConversion(img); + break; } } return ((img->put.contig = put) != 0); @@ -1910,7 +2450,7 @@ TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) "Can't use TIFFReadRGBAStrip() with tiled file."); return (0); } - + TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); if( (row % rowsperstrip) != 0 ) { @@ -1919,7 +2459,7 @@ TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) return (0); } - if (TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + if (TIFFRGBAImageOK(tif, emsg) && TIFFRGBAImageBegin(&img, tif, 0, emsg)) { img.row_offset = row; img.col_offset = 0; @@ -1928,15 +2468,15 @@ TIFFReadRGBAStrip(TIFF* tif, uint32 row, uint32 * raster ) rows_to_read = img.height - row; else rows_to_read = rowsperstrip; - + ok = TIFFRGBAImageGet(&img, raster, img.width, rows_to_read ); - + TIFFRGBAImageEnd(&img); } else { TIFFError(TIFFFileName(tif), emsg); ok = 0; } - + return (ok); } @@ -1955,20 +2495,20 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) int ok; uint32 tile_xsize, tile_ysize; uint32 read_xsize, read_ysize; - int i_row; + uint32 i_row; /* * Verify that our request is legal - on a tile file, and on a * tile boundary. */ - + if( !TIFFIsTiled( tif ) ) { TIFFError(TIFFFileName(tif), "Can't use TIFFReadRGBATile() with stripped file."); return (0); } - + TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tile_xsize); TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tile_ysize); if( (col % tile_xsize) != 0 || (row % tile_ysize) != 0 ) @@ -1982,10 +2522,11 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) /* * Setup the RGBA reader. */ - - if ( !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { - TIFFError(TIFFFileName(tif), emsg); - return( 0 ); + + if (!TIFFRGBAImageOK(tif, emsg) + || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) { + TIFFError(TIFFFileName(tif), emsg); + return( 0 ); } /* @@ -1999,7 +2540,7 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) read_ysize = img.height - row; else read_ysize = tile_ysize; - + if( col + tile_xsize > img.width ) read_xsize = img.width - col; else @@ -2008,12 +2549,12 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) /* * Read the chunk of imagery. */ - + img.row_offset = row; img.col_offset = col; ok = TIFFRGBAImageGet(&img, raster, read_xsize, read_ysize ); - + TIFFRGBAImageEnd(&img); /* @@ -2021,23 +2562,21 @@ TIFFReadRGBATile(TIFF* tif, uint32 col, uint32 row, uint32 * raster) * shifting the data around as if a full tile of data is being returned. * * This is all the more complicated because the image is organized in - * bottom to top format. + * bottom to top format. */ if( read_xsize == tile_xsize && read_ysize == tile_ysize ) return( ok ); - for( i_row = 0; i_row < read_ysize; i_row++ ) - { - _TIFFmemcpy( raster + (tile_ysize - i_row - 1) * tile_xsize, - raster + (read_ysize - i_row - 1) * read_xsize, - read_xsize * sizeof(uint32) ); + for( i_row = 0; i_row < read_ysize; i_row++ ) { + memmove( raster + (tile_ysize - i_row - 1) * tile_xsize, + raster + (read_ysize - i_row - 1) * read_xsize, + read_xsize * sizeof(uint32) ); _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize+read_xsize, 0, sizeof(uint32) * (tile_xsize - read_xsize) ); } - for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) - { + for( i_row = read_ysize; i_row < tile_ysize; i_row++ ) { _TIFFmemset( raster + (tile_ysize - i_row - 1) * tile_xsize, 0, sizeof(uint32) * tile_xsize ); }