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
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:
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) {
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",
return (0);
}
break;
+ case PHOTOMETRIC_CIELAB:
+ break;
default:
sprintf(emsg, "Sorry, can not handle image with %s=%d",
photoTag, photometric);
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
img->redcmap = NULL;
img->greencmap = NULL;
img->bluecmap = NULL;
+ img->req_orientation = ORIENTATION_BOTLEFT; /* It is the default */
img->tif = tif;
img->stoponerr = stop;
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);
}
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);
/* 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;
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:
if (colorchannels < 3) {
"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);
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);
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);
!(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
}
/*
- * 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);
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;
+ }
}
/*
{
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);
}
/*
{
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;
int32 fromskew, toskew;
int alpha = img->alpha;
uint32 nrow;
+ int ret = 1, flip;
tilesize = TIFFTileSize(tif);
buf = (u_char*) _TIFFmalloc(4*tilesize);
TIFFError(TIFFFileName(tif), "No space for tile buffer");
return (0);
}
+ _TIFFmemset(buf, 0, 4*tilesize);
r = buf;
g = r + tilesize;
b = g + tilesize;
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);
}
/*
{
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);
}
/*
{
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);
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);
}
/*
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;
}
*/
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;
}
}
/*
- * 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]);
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;
+ }
}
}
*/
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]);
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);
+
}
/*
*/
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;
+ }
}
}
*/
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);
*/
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]);
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<<SHIFT) + 0.5))
-#define ONE_HALF ((int32)(1<<(SHIFT-1)))
-
-/*
- * Initialize the YCbCr->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;
}
/*
int i;
uint32* p;
+ if( nsamples == 0 )
+ nsamples = 1;
+
img->BWmap = (uint32**) _TIFFmalloc(
256*sizeof (uint32 *)+(256*nsamples*sizeof(uint32)));
if (img->BWmap == NULL) {
GREY(i&0xf);
break;
case 8:
+ case 16:
GREY(i);
break;
}
int32 x, range;
range = (int32)((1L<<img->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),
}
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)) {
/*
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);
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);
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;
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
* 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 );
}
/*
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 );
}
-
+
return (ok);
}