/* * Get a strip-organized image with * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtStripSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileSeparateRoutine put = img->put.separate; uint16 orientation; u_char *buf; u_char *r, *g, *b, *a; uint32 row, y, nrow; tsize_t scanline; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t stripsize; int32 fromskew, toskew; int alpha = img->alpha; stripsize = TIFFStripSize(tif); r = buf = (u_char *)_TIFFmalloc(4*stripsize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } g = r + stripsize; b = g + stripsize; a = b + stripsize; if (!alpha) memset(a, 0xff, stripsize); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), r, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1), g, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2), b, nrow*scanline) < 0 && img->stoponerr) break; if (alpha && (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3), a, nrow*scanline) < 0 && img->stoponerr)) break; (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, r, g, b, a); y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); }
/* * Get a strip-organized image with * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtStripSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h) { TIFF* tif = img->tif; ImageIterTileSeparateRoutine callback = img->callback.separate; uint16 orientation; u_char *buf; u_char *r, *g, *b, *a; uint32 row, nrow; tsize_t scanline; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t stripsize; int32 fromskew; int alpha = img->alpha; stripsize = TIFFStripSize(tif); r = buf = (u_char *)_TIFFmalloc(4*stripsize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } g = r + stripsize; b = g + stripsize; a = b + stripsize; if (!alpha) memset(a, 0xff, stripsize); orientation = img->orientation; TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), r, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 1), g, nrow*scanline) < 0 && img->stoponerr) break; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 2), b, nrow*scanline) < 0 && img->stoponerr) break; if (alpha && (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 3), a, nrow*scanline) < 0 && img->stoponerr)) break; (*callback)(img, udata, 0, row, w, nrow, fromskew, r, g, b, a); } _TIFFfree(buf); return (1); }
int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) { uint16 photometric; TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); // To avoid dealing with YCbCr subsampling, let libtiff handle it if (photometric == PHOTOMETRIC_YCBCR) { TIFFRGBAImage img; char emsg[1024] = ""; UINT32 rows_per_strip, rows_to_read; int ok; TIFFGetFieldDefaulted(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); if ((row % rows_per_strip) != 0) { TRACE(("Row passed to ReadStrip() must be first in a strip.")); return -1; } if (TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg)) { TRACE(("Initialized RGBAImage\n")); img.req_orientation = ORIENTATION_TOPLEFT; img.row_offset = row; img.col_offset = 0; rows_to_read = min(rows_per_strip, img.height - row); TRACE(("rows to read: %d\n", rows_to_read)); ok = TIFFRGBAImageGet(&img, buffer, img.width, rows_to_read); TIFFRGBAImageEnd(&img); } else { ok = 0; } if (ok == 0) { TRACE(("Decode Error, row %d; msg: %s\n", row, emsg)); return -1; } return 0; } if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, row, 0), (tdata_t)buffer, -1) == -1) { TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, row, 0))); return -1; } return 0; }
static void svRGBContig(TIFF* tif, uint32* ss, int xsize, int ysize) { register int x, y; tsize_t stripsize = TIFFStripSize(tif); unsigned char *strip = (unsigned char *)_TIFFmalloc(stripsize); for (y = 0; y <= ysize; y += rowsperstrip) { register unsigned char *pp = strip; register uint32 n; n = rowsperstrip; if (n > ysize-y+1) n = ysize-y+1; do { for (x = 0; x <= xsize; x++) { uint32 v = ss[x]; pp[0] = v; pp[1] = v >> 8; pp[2] = v >> 16; pp += 3; } ss += xsize+1; } while (--n); if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0), strip, stripsize) < 0) break; } _TIFFfree(strip); }
/* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtStripContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h) { TIFF* tif = img->tif; ImageIterTileContigRoutine callback = img->callback.contig; uint16 orientation; uint32 row, nrow; u_char* buf; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t scanline; int32 fromskew; buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for strip buffer"); return (0); } orientation = img->orientation; TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow*scanline) < 0 && img->stoponerr) break; (*callback)(img, udata, 0, row, w, nrow, fromskew, buf); } _TIFFfree(buf); return (1); }
/* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ boolean TIFFRasterImpl::gtStripContig( const RGBvalue* Map, u_long h, u_long w ) { u_char* buf = new u_char[TIFFStripSize(tif_)]; if (buf == nil) { TIFFError(TIFFFileName(tif_), "No space for strip buffer"); return (false); } tileContigRoutine put = pickTileContigCase(Map); u_long y = setorientation(h); int toskew = (int)(orientation_ == ORIENTATION_TOPLEFT ? -w + -w : -w + w); u_long rowsperstrip = (u_long) -1L; TIFFGetField(tif_, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); u_long imagewidth; TIFFGetField(tif_, TIFFTAG_IMAGEWIDTH, &imagewidth); int scanline = TIFFScanlineSize(tif_); int fromskew = (int)(w < imagewidth ? imagewidth - w : 0); for (u_long row = 0; row < h; row += rowsperstrip) { u_int nrow = u_int(row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip( tif_, TIFFComputeStrip(tif_, row, 0), buf, nrow*scanline) < 0 ) { break; } (this->*put)(raster_ + y*w, buf, Map, w, nrow, fromskew, toskew); y += (orientation_ == ORIENTATION_TOPLEFT ? -nrow : nrow); } delete buf; return true; }
/* * Get a strip-organized image with * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ boolean TIFFRasterImpl::gtStripSeparate( const RGBvalue* Map, u_long h, u_long w ) { u_long stripsize = TIFFStripSize(tif_); u_char* buf = new u_char[3*stripsize]; u_char* r = buf; u_char* g = r + stripsize; u_char* b = g + stripsize; tileSeparateRoutine put = pickTileSeparateCase(Map); u_long y = setorientation(h); int toskew = (int)(orientation_ == ORIENTATION_TOPLEFT ? -w + -w : -w + w); u_long rowsperstrip = (u_long) -1L; TIFFGetField(tif_, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); u_long imagewidth; TIFFGetField(tif_, TIFFTAG_IMAGEWIDTH, &imagewidth); int scanline = TIFFScanlineSize(tif_); int fromskew = (int)(w < imagewidth ? imagewidth - w : 0); for (u_long row = 0; row < h; row += rowsperstrip) { u_int nrow = u_int(row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip( tif_, TIFFComputeStrip(tif_, row, 0), r, nrow*scanline) < 0 ) { break; } if (TIFFReadEncodedStrip( tif_, TIFFComputeStrip(tif_, row, 1), g, nrow*scanline) < 0 ) { break; } if (TIFFReadEncodedStrip( tif_, TIFFComputeStrip(tif_, row, 2), b, nrow*scanline) < 0 ) { break; } (this->*put)(raster_ + y*w, r, g, b, Map, w, nrow, fromskew, toskew); y += (orientation_ == ORIENTATION_TOPLEFT ? -nrow : nrow); } delete buf; return true; }
static void svRGBSeparate(TIFF* tif, uint32* ss, int xsize, int ysize) { tsize_t stripsize = TIFFStripSize(tif); unsigned char *rbuf = (unsigned char *)_TIFFmalloc(3*stripsize); unsigned char *gbuf = rbuf + stripsize; unsigned char *bbuf = gbuf + stripsize; register int y; for (y = 0; y <= ysize; y += rowsperstrip) { unsigned char *rp, *gp, *bp; register int x; register uint32 n; n = rowsperstrip; if (n > ysize-y+1) n = ysize-y+1; rp = rbuf; gp = gbuf; bp = bbuf; do { for (x = 0; x <= xsize; x++) { uint32 v = ss[x]; rp[x] = v; gp[x] = v >> 8; bp[x] = v >> 16; } rp += xsize+1, gp += xsize+1, bp += xsize+1; ss += xsize+1; } while (--n); if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,0), rbuf, stripsize) < 0) break; if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,1), gbuf, stripsize) < 0) break; if (TIFFWriteEncodedStrip(tif, TIFFComputeStrip(tif,y,2), bbuf, stripsize) < 0) break; } _TIFFfree(rbuf); }
/* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 * * Hacked from the tif_getimage.c file. * * This is set up to allow us to just copy the data to the raster * for 1-bit bitmaps */ static int getStripContig1Bit(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; uint16 orientation; uint32 row, y, nrow, rowstoread; uint32 pos; u_char* buf; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t scanline; int32 fromskew, toskew; tstrip_t strip; tsize_t stripsize; u_char* braster = (u_char*)raster; // byte wide raster uint32 wb = WIDTHBYTES(w); int ret = 1; buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); return (0); } y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? wb+wb : wb-wb); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0)/8; for (row = 0; row < h; row += nrow) { rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; nrow = (row + rowstoread > h ? h - row : rowstoread); strip = TIFFComputeStrip(tif,row+img->row_offset, 0); stripsize = ((row + img->row_offset)%rowsperstrip + nrow) * scanline; if (TIFFReadEncodedStrip(tif, strip, buf, stripsize ) < 0 && img->stoponerr) { ret = 0; break; } pos = ((row + img->row_offset) % rowsperstrip) * scanline; (*put)(img, (uint32*)(braster+y*wb), 0, y, w, nrow, fromskew, toskew, buf + pos); y += (orientation == ORIENTATION_TOPLEFT ?-(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (ret); }
/* * Get a strip-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtStripContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; uint16 orientation; uint32 row, y, nrow; u_char* buf; uint32 rowsperstrip; uint32 imagewidth = img->width; tsize_t scanline; int32 fromskew, toskew; buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for strip buffer"); return (0); } y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? w+w : w-w); TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); scanline = TIFFScanlineSize(tif); fromskew = (w < imagewidth ? imagewidth - w : 0); for (row = 0; row < h; row += rowsperstrip) { nrow = (row + rowsperstrip > h ? h - row : rowsperstrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow*scanline) < 0 && img->stoponerr) break; (*put)(img, raster+y*w, 0, y, w, nrow, fromskew, toskew, buf); y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); }
int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) { TIFFSTATE *clientstate = (TIFFSTATE *)state->context; char *filename = "tempfile.tif"; char *mode = "r"; TIFF *tiff; /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ TRACE(("in decoder: bytes %d\n", bytes)); TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, state->x, state->y, state->ystep)); TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, state->xoff, state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3])); TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3])); TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", im->mode, im->type, im->bands, im->xsize, im->ysize)); TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n", im->image8, im->image32, im->image, im->block)); TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize)); dump_state(clientstate); clientstate->size = bytes; clientstate->eof = clientstate->size; clientstate->loc = 0; clientstate->data = (tdata_t)buffer; clientstate->flrealloc = 0; dump_state(clientstate); TIFFSetWarningHandler(NULL); TIFFSetWarningHandlerExt(NULL); if (clientstate->fp) { TRACE(("Opening using fd: %d\n",clientstate->fp)); lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end. tiff = TIFFFdOpen(clientstate->fp, filename, mode); } else { TRACE(("Opening from string\n")); tiff = TIFFClientOpen(filename, mode, (thandle_t) clientstate, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); } if (!tiff){ TRACE(("Error, didn't get the tiff\n")); state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (clientstate->ifd){ int rv; uint32 ifdoffset = clientstate->ifd; TRACE(("reading tiff ifd %u\n", ifdoffset)); rv = TIFFSetSubDirectory(tiff, ifdoffset); if (!rv){ TRACE(("error in TIFFSetSubDirectory")); return -1; } } if (TIFFIsTiled(tiff)) { UINT32 x, y, tile_y, row_byte_size; UINT32 tile_width, tile_length, current_tile_width; UINT8 *new_data; TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size row_byte_size = (tile_width * state->bits + 7) / 8; state->bytes = row_byte_size * tile_length; /* overflow check for malloc */ if (state->bytes > INT_MAX - 1) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } /* realloc to fit whole tile */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } state->buffer = new_data; TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { for (x = state->xoff; x < state->xsize; x += tile_width) { if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) { TRACE(("Decode Error, Tile at %dx%d\n", x, y)); state->errcode = IMAGING_CODEC_BROKEN; TIFFClose(tiff); return -1; } TRACE(("Read tile at %dx%d; \n\n", x, y)); current_tile_width = min(tile_width, state->xsize - x); // iterate over each line in the tile and stuff data into image for (tile_y = 0; tile_y < min(tile_length, state->ysize - y); tile_y++) { TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); // UINT8 * bbb = state->buffer + tile_y * row_byte_size; // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize, state->buffer + tile_y * row_byte_size, current_tile_width ); } } } } else { UINT32 strip_row, row_byte_size; UINT8 *new_data; UINT32 rows_per_strip; TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); TRACE(("RowsPerStrip: %u \n", rows_per_strip)); // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size row_byte_size = (state->xsize * state->bits + 7) / 8; state->bytes = rows_per_strip * row_byte_size; TRACE(("StripSize: %d \n", state->bytes)); /* realloc to fit whole strip */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } state->buffer = new_data; for (; state->y < state->ysize; state->y += rows_per_strip) { if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); state->errcode = IMAGING_CODEC_BROKEN; TIFFClose(tiff); return -1; } TRACE(("Decoded strip for row %d \n", state->y)); // iterate over each row in the strip and stuff data into image for (strip_row = 0; strip_row < min(rows_per_strip, state->ysize - state->y); strip_row++) { TRACE(("Writing data into line %d ; \n", state->y + strip_row)); // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] + state->xoff * im->pixelsize, state->buffer + strip_row * row_byte_size, state->xsize); } } } TIFFClose(tiff); TRACE(("Done Decoding, Returning \n")); // Returning -1 here to force ImageFile.load to break, rather than // even think about looping back around. return -1; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(uint32_t)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; bool isRGB; uint8_t *bits; //pointer to source data uint8_t *bits2; //pointer to destination data cx_try { //check if it's a tiff file if (!m_tif) cx_throw("Error encountered while opening TIFF file"); // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) cx_throw("Error: page not present in TIFF file"); //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; info.dwType = CXIMAGE_FORMAT_TIF; cx_throw("output dimensions returned"); } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (int32_t)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (int32_t)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) { head.biBitCount=24; head.biClrUsed =0; } } if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) cx_throw("CxImageTIF can't create image"); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) cx_throw("No space for raster buffer"); // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); cx_throw("Corrupted TIFF file!"); } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); cx_throw("Cancelled"); } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (uint8_t)TIFFGetB(row[x]); *bits++ = (uint8_t)TIFFGetG(row[x]); *bits++ = (uint8_t)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(uint8_t)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { int32_t BIG_palette = (bitspersample > 8) && // + VK (photometric==PHOTOMETRIC_PALETTE); if (BIG_palette && (bitspersample > 24)) // + VK cx_throw("Too big palette to handle"); // + VK RGBQuad *pal; pal=(RGBQuad*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQuad)); // ! VK: it coasts nothing but more correct to use 256 as temp palette storage // ! VK: but for case of BIG palette it just copied if (pal==NULL) cx_throw("Unable to allocate TIFF palette"); int32_t bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8) // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(i*(255/((1<<bpp)-1))); } } else { for (int32_t i=0; i<(1<<bpp); i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(255-i*(255/((1<<bpp)-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? bool Palette16Bits = /*false*/ BIG_palette; if (!BIG_palette) { int32_t n= 1<<bpp; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=true; break; } } } // load the palette in the DIB for (int32_t i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(uint8_t) CVT(red[i]); pal[i].rgbGreen = (uint8_t) CVT(green[i]); pal[i].rgbBlue = (uint8_t) CVT(blue[i]); } else { pal[i].rgbRed = (uint8_t) red[i]; pal[i].rgbGreen = (uint8_t) green[i]; pal[i].rgbBlue = (uint8_t) blue[i]; } } break; } if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK free(pal); pal = NULL; } // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int32_t line = CalculateLine(width, bitspersample * samplesperpixel); int32_t bitsize = TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(int32_t)(head.biSizeImage*samplesperpixel)) bitsize = head.biSizeImage*samplesperpixel; if (bitsize<(int32_t)(info.dwEffWidth*rowsperstrip)) bitsize = info.dwEffWidth*rowsperstrip; if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 bitsize *= (bitspersample + 7)/8; int32_t tiled_image = TIFFIsTiled(m_tif); uint32 tw=0, tl=0; uint8_t* tilebuf=NULL; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int32_t)(1+width/tw); tilebuf = (uint8_t*)malloc(TIFFTileSize(m_tif)); } bits = (uint8_t*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK uint8_t * bits16 = NULL; // + VK int32_t line16 = 0; // + VK if (!tiled_image && bitspersample==16) { // + VK + line16 = line; line = CalculateLine(width, 8 * samplesperpixel); bits16 = bits; bits = (uint8_t*)malloc(bitsize); } if (bits==NULL){ if (bits16) free(bits16); // + VK if (pal) free(pal); // + VK if (tilebuf)free(tilebuf); // + VK cx_throw("CxImageTIF can't allocate memory"); } #ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it uint8_t* row_shifts = NULL; if (bits16) row_shifts = (uint8_t*)malloc(height); #endif for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); cx_throw("Cancelled"); } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int32_t iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); cx_throw("Corrupted tiled TIFF file!"); } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK #ifdef NOT_IGNORE_CORRUPTED free(bits); if (bits16) free(bits16); // + VK cx_throw("Corrupted TIFF file!"); #else break; #endif } } for (y = 0; y < nrow; y++) { int32_t offset=(nrow-y-1)*line; if ((bitspersample==16) && !BIG_palette) { // * VK int32_t offset16 = (nrow-y-1)*line16; // + VK if (bits16) { // + VK + #ifdef FIX_16BPP_DARKIMG int32_t the_shift; uint8_t hi_byte, hi_max=0; uint32_t xi; for (xi=0;xi<(uint32)line;xi++) { hi_byte = bits16[xi*2+offset16+1]; if(hi_byte>hi_max) hi_max = hi_byte; } the_shift = (hi_max == 0) ? 8 : 0; if (!the_shift) while( ! (hi_max & 0x80) ) { the_shift++; hi_max <<= 1; } row_shifts[height-ys-nrow+y] = the_shift; the_shift = 8 - the_shift; for (xi=0;xi<(uint32)line;xi++) bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; #else for (uint32_t xi=0;xi<(uint32)line;xi++) bits[xi+offset]=bits16[xi*2+offset16+1]; #endif } else { for (uint32_t xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; } } if (samplesperpixel==1) { if (BIG_palette) if (bits16) { int32_t offset16 = (nrow-y-1)*line16; // + VK MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits16 + offset16, width, bitspersample, pal ); } else MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample, pal ); else if ((bitspersample == head.biBitCount) || (bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,min((unsigned)line, info.dwEffWidth)); else MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample ); } else if (samplesperpixel==2) { //8bpp image with alpha layer int32_t xi=0; int32_t ii=0; int32_t yi=height-ys-nrow+y; #if CXIMAGE_SUPPORT_ALPHA if (!pAlpha) AlphaCreate(); // + VK #endif //CXIMAGE_SUPPORT_ALPHA while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int32_t xi=0; uint32 ii=0; int32_t yi=height-ys-nrow+y; RGBQuad c; int32_t l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii</*line*/width){ // * VK bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(uint8_t)max(0,min(255,(int32_t)(cr*255))); c.rgbGreen=(uint8_t)max(0,min(255,(int32_t)(cg*255))); c.rgbBlue =(uint8_t)max(0,min(255,(int32_t)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int32_t)width){ yi--; xi=0; } } } } } free(bits); if (bits16) free(bits16); #ifdef FIX_16BPP_DARKIMG if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { // 1. calculate maximum necessary shift int32_t min_row_shift = 8; for( y=0; y<height; y++ ) { if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y]; } // 2. for rows having less shift value, correct such rows: for( y=0; y<height; y++ ) { if (min_row_shift < row_shifts[y]) { int32_t need_shift = row_shifts[y] - min_row_shift; uint8_t* data = info.pImage + info.dwEffWidth * y; for( x=0; x<width; x++, data++ ) *data >>= need_shift; } }
static void TIFFWriteOvrRow( TIFFOvrCache * psCache ) { int nRet, iTileX, iTileY = psCache->nBlockOffset; unsigned char *pabyData; uint32 nBaseDirOffset; uint32 RowsInStrip; /* -------------------------------------------------------------------- */ /* If the output cache is multi-byte per sample, and the file */ /* being written to is of a different byte order than the current */ /* platform, we will need to byte swap the data. */ /* -------------------------------------------------------------------- */ if( TIFFIsByteSwapped(psCache->hTIFF) ) { if( psCache->nBitsPerPixel == 16 ) TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 2 ); else if( psCache->nBitsPerPixel == 32 ) TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 4 ); else if( psCache->nBitsPerPixel == 64 ) TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks, (psCache->nBytesPerBlock * psCache->nSamples) / 8 ); } /* -------------------------------------------------------------------- */ /* Record original directory position, so we can restore it at */ /* end. */ /* -------------------------------------------------------------------- */ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset ); assert( nRet == 1 ); /* -------------------------------------------------------------------- */ /* Write blocks to TIFF file. */ /* -------------------------------------------------------------------- */ for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ ) { int nTileID; if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) { int iSample; for( iSample = 0; iSample < psCache->nSamples; iSample++ ) { pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample ); if( psCache->bTiled ) { nTileID = TIFFComputeTile( psCache->hTIFF, iTileX * psCache->nBlockXSize, iTileY * psCache->nBlockYSize, 0, (tsample_t) iSample ); TIFFWriteEncodedTile( psCache->hTIFF, nTileID, pabyData, TIFFTileSize(psCache->hTIFF) ); } else { nTileID = TIFFComputeStrip( psCache->hTIFF, iTileY * psCache->nBlockYSize, (tsample_t) iSample ); RowsInStrip=psCache->nBlockYSize; if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, pabyData, TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); } } } else { pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 ); if( psCache->bTiled ) { nTileID = TIFFComputeTile( psCache->hTIFF, iTileX * psCache->nBlockXSize, iTileY * psCache->nBlockYSize, 0, 0 ); TIFFWriteEncodedTile( psCache->hTIFF, nTileID, pabyData, TIFFTileSize(psCache->hTIFF) ); } else { nTileID = TIFFComputeStrip( psCache->hTIFF, iTileY * psCache->nBlockYSize, 0 ); RowsInStrip=psCache->nBlockYSize; if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, pabyData, TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); } } } /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */ /* -------------------------------------------------------------------- */ /* Rotate buffers. */ /* -------------------------------------------------------------------- */ pabyData = psCache->pabyRow1Blocks; psCache->pabyRow1Blocks = psCache->pabyRow2Blocks; psCache->pabyRow2Blocks = pabyData; _TIFFmemset( pabyData, 0, psCache->nBytesPerRow ); psCache->nBlockOffset++; /* -------------------------------------------------------------------- */ /* Restore access to original directory. */ /* -------------------------------------------------------------------- */ TIFFFlush( psCache->hTIFF ); /* TODO: add checks on error status return of TIFFFlush */ TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); /* TODO: add checks on error status return of TIFFSetSubDirectory */ }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) throw "Error: page not present in TIFF file"; //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; throw "output dimensions returned"; } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } } if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) throw "CxImageTIF can't create image"; #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); throw "Cancelled"; } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/(head.biClrUsed-1))); } } else { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/(head.biClrUsed-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,head.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); long bitsize= TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel; int tiled_image = TIFFIsTiled(m_tif); uint32 tw, tl; BYTE* tilebuf; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); } bits = (BYTE*)malloc(bitsize); if (bits==NULL){ throw "CxImageTIF can't allocate memory"; } for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); throw "Cancelled"; } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); throw "Corrupted tiled TIFF file!"; } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } } for (y = 0; y < nrow; y++) { long offset=(nrow-y-1)*line; if (bitspersample==16) for (DWORD xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; if (samplesperpixel==1) { //simple 8bpp image memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth); } else if (samplesperpixel==2) { //8bpp image with alpha layer int xi=0; int ii=0; int yi=height-ys-nrow+y; while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int xi=0; int ii=0; int yi=height-ys-nrow+y; RGBQUAD c; int l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii<line){ bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int)width){ yi--; xi=0; } } } } } free(bits); if (tiled_image) free(tilebuf); switch(orientation){ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ Mirror(); break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ Flip(); Mirror(); break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ Flip(); break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ RotateRight(); Mirror(); break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ RotateLeft(); break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ RotateLeft(); Mirror(); break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ RotateRight(); break; } } } catch (char *message) { strncpy(info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); if (info.nEscape==-1) return true; return false; } TIFFClose(m_tif); return true; }
HDIB LoadTIFFinDIB(LPSTR lpFileName) { TIFF *tif; unsigned long imageLength; unsigned long imageWidth; unsigned int BitsPerSample; unsigned long LineSize; unsigned int SamplePerPixel; unsigned long RowsPerStrip; int PhotometricInterpretation; long nrow; unsigned long row; char *buf; LPBITMAPINFOHEADER lpDIB; HDIB hDIB; char *lpBits; HGLOBAL hStrip; int i,l; int Align; tif = TIFFOpen(lpFileName, "r"); if (!tif) goto TiffOpenError; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); LineSize = TIFFScanlineSize(tif); //Number of byte in ine line SamplePerPixel = (int) (LineSize/imageWidth); //Align = Number of byte to add at the end of each line of the DIB Align = 4 - (LineSize % 4); if (Align == 4) Align = 0; //Create a new DIB hDIB = CreateDIB((DWORD) imageWidth, (DWORD) imageLength, (WORD) (BitsPerSample*SamplePerPixel)); lpDIB = (LPBITMAPINFOHEADER) GlobalLock(hDIB); if (!lpDIB) goto OutOfDIBMemory; if (lpDIB) lpBits = FindDIBBits((LPSTR) lpDIB); //In the tiff file the lines are save from up to down //In a DIB the lines must be save from down to up if (lpBits) { lpBits = FindDIBBits((LPSTR) lpDIB); lpBits+=((imageWidth*SamplePerPixel)+Align)*(imageLength-1); //now lpBits pointe on the bottom line hStrip = GlobalAlloc(GHND,TIFFStripSize(tif)); buf = GlobalLock(hStrip); if (!buf) goto OutOfBufMemory; //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image have a color palette if (PhotometricInterpretation == 3) { uint16* red; uint16* green; uint16* blue; int16 i; LPBITMAPINFO lpbmi; int Palette16Bits; TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); //Is the palette 16 or 8 bits ? if (checkcmap(1<<BitsPerSample, red, green, blue) == 16) Palette16Bits = TRUE; else Palette16Bits = FALSE; lpbmi = (LPBITMAPINFO)lpDIB; //load the palette in the DIB for (i = (1<<BitsPerSample)-1; i >= 0; i--) { if (Palette16Bits) { lpbmi->bmiColors[i].rgbRed =(BYTE) CVT(red[i]); lpbmi->bmiColors[i].rgbGreen = (BYTE) CVT(green[i]); lpbmi->bmiColors[i].rgbBlue = (BYTE) CVT(blue[i]); } else { lpbmi->bmiColors[i].rgbRed = (BYTE) red[i]; lpbmi->bmiColors[i].rgbGreen = (BYTE) green[i]; lpbmi->bmiColors[i].rgbBlue = (BYTE) blue[i]; } } } //read the tiff lines and save them in the DIB //with RGB mode, we have to change the order of the 3 samples RGB <=> BGR for (row = 0; row < imageLength; row += RowsPerStrip) { nrow = (row + RowsPerStrip > imageLength ? imageLength - row : RowsPerStrip); if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf, nrow*LineSize)==-1) { goto TiffReadError; } else { for (l = 0; l < nrow; l++) { if (SamplePerPixel == 3) for (i=0; i< (int) (imageWidth); i++) { lpBits[i*SamplePerPixel+0]=buf[l*LineSize+i*Sample PerPixel+2]; lpBits[i*SamplePerPixel+1]=buf[l*LineSize+i*Sample PerPixel+1]; lpBits[i*SamplePerPixel+2]=buf[l*LineSize+i*Sample PerPixel+0]; } else memcpy(lpBits, &buf[(int) (l*LineSize)], (int) imageWidth*SamplePerPixel); lpBits-=imageWidth*SamplePerPixel+Align; } } } GlobalUnlock(hStrip); GlobalFree(hStrip); GlobalUnlock(hDIB); TIFFClose(tif); }
// Internal function used to load the Tiff. ILboolean iLoadTiffInternal() { TIFF *tif; uint16 photometric, planarconfig, orientation; uint16 samplesperpixel, bitspersample, *sampleinfo, extrasamples; uint32 w, h, d, linesize, tilewidth, tilelength; ILubyte *pImageData; ILuint i, ProfileLen, DirCount = 0; void *Buffer; ILimage *Image, *TempImage; ILushort si; ILfloat x_position, x_resolution, y_position, y_resolution; //TIFFRGBAImage img; //char emsg[1024]; // to avoid high order bits garbage when used as shorts w = h = d = linesize = tilewidth = tilelength = 0; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } TIFFSetWarningHandler (NULL); TIFFSetErrorHandler (NULL); //for debugging only //TIFFSetWarningHandler(warningHandler); //TIFFSetErrorHandler(errorHandler); tif = iTIFFOpen("r"); if (tif == NULL) { ilSetError(IL_COULD_NOT_OPEN_FILE); return IL_FALSE; } do { DirCount++; } while (TIFFReadDirectory(tif)); /* if (!ilTexImage(1, 1, 1, 1, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) { TIFFClose(tif); return IL_FALSE; } Image = iCurImage; for (i = 1; i < DirCount; i++) { Image->Next = ilNewImage(1, 1, 1, 1, 1); if (Image->Next == NULL) { TIFFClose(tif); return IL_FALSE; } Image = Image->Next; } iCurImage->NumNext = DirCount - 1; */ Image = NULL; for (i = 0; i < DirCount; i++) { TIFFSetDirectory(tif, (tdir_t)i); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH, &d); //TODO: d is ignored... TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &orientation); linesize = TIFFScanlineSize(tif); //added 2003-08-31 //1 bpp tiffs are not neccessarily greyscale, they can //have a palette (photometric == 3)...get this information TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); //special-case code for frequent data cases that may be read more //efficiently than with the TIFFReadRGBAImage() interface. //added 2004-05-12 //Get tile sizes and use TIFFReadRGBAImage() for tiled images for now tilewidth = w; tilelength = h; TIFFGetFieldDefaulted(tif, TIFFTAG_TILEWIDTH, &tilewidth); TIFFGetFieldDefaulted(tif, TIFFTAG_TILELENGTH, &tilelength); if (extrasamples == 0 && samplesperpixel == 1 //luminance or palette && (bitspersample == 8 || bitspersample == 1 || bitspersample == 16) && (photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_PALETTE) && (orientation == ORIENTATION_TOPLEFT || orientation == ORIENTATION_BOTLEFT) && tilewidth == w && tilelength == h ) { ILubyte* strip; tsize_t stripsize; ILuint y; uint32 rowsperstrip, j, linesread; //TODO: 1 bit/pixel images should not be stored as 8 bits... //(-> add new format) if (!Image) { int type = IL_UNSIGNED_BYTE; if (bitspersample == 16) type = IL_UNSIGNED_SHORT; if (!ilTexImage(w, h, 1, 1, IL_LUMINANCE, type, NULL)) { TIFFClose(tif); return IL_FALSE; } Image = iCurImage; } else { Image->Next = ilNewImage(w, h, 1, 1, 1); if (Image->Next == NULL) { TIFFClose(tif); return IL_FALSE; } Image = Image->Next; } if (photometric == PHOTOMETRIC_PALETTE) { //read palette uint16 *red, *green, *blue; //ILboolean is16bitpalette = IL_FALSE; ILubyte *entry; uint32 count = 1 << bitspersample, j; TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); Image->Format = IL_COLOUR_INDEX; Image->Pal.PalSize = (count)*3; Image->Pal.PalType = IL_PAL_RGB24; Image->Pal.Palette = (ILubyte*)ialloc(Image->Pal.PalSize); entry = Image->Pal.Palette; for (j = 0; j < count; ++j) { entry[0] = (ILubyte)(red[j] >> 8); entry[1] = (ILubyte)(green[j] >> 8); entry[2] = (ILubyte)(blue[j] >> 8); entry += 3; } } TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); stripsize = TIFFStripSize(tif); strip = (ILubyte*)ialloc(stripsize); if (bitspersample == 8 || bitspersample == 16) { ILubyte *dat = Image->Data; for (y = 0; y < h; y += rowsperstrip) { //the last strip may contain less data if the image //height is not evenly divisible by rowsperstrip if (y + rowsperstrip > h) { stripsize = linesize*(h - y); linesread = h - y; } else linesread = rowsperstrip; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) { ilSetError(IL_LIB_TIFF_ERROR); ifree(strip); TIFFClose(tif); return IL_FALSE; } if (photometric == PHOTOMETRIC_MINISWHITE) { //invert channel uint32 k, t2; for (j = 0; j < linesread; ++j) { t2 = j*linesize; //this works for 16bit images as well: the two bytes //making up a pixel can be inverted independently for (k = 0; k < Image->Bps; ++k) dat[k] = ~strip[t2 + k]; dat += w; } } else for(j = 0; j < linesread; ++j) memcpy(&Image->Data[(y + j)*Image->Bps], &strip[j*linesize], Image->Bps); } } else if (bitspersample == 1) { //TODO: add a native format to devil, so we don't have to //unpack the values here ILubyte mask, curr, *dat = Image->Data; uint32 k, sx, t2; for (y = 0; y < h; y += rowsperstrip) { //the last strip may contain less data if the image //height is not evenly divisible by rowsperstrip if (y + rowsperstrip > h) { stripsize = linesize*(h - y); linesread = h - y; } else linesread = rowsperstrip; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) { ilSetError(IL_LIB_TIFF_ERROR); ifree(strip); TIFFClose(tif); return IL_FALSE; } for (j = 0; j < linesread; ++j) { k = 0; sx = 0; t2 = j*linesize; while (k < w) { curr = strip[t2 + sx]; if (photometric == PHOTOMETRIC_MINISWHITE) curr = ~curr; for (mask = 0x80; mask != 0 && k < w; mask >>= 1){ if((curr & mask) != 0) dat[k] = 255; else dat[k] = 0; ++k; } ++sx; } dat += w; } } }
void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig, int nOverviews, int * panOvList, int nBitsPerPixel, int nSamples, TIFFOvrCache ** papoRawBIs, int nSXOff, int nSYOff, unsigned char *pabySrcTile, int nBlockXSize, int nBlockYSize, int nSampleFormat, const char * pszResampling ) { int iOverview, iSample; for( iSample = 0; iSample < nSamples; iSample++ ) { /* * We have to read a tile/strip for each sample for * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples * at once when handling the first sample. */ if( nPlanarConfig == PLANARCONFIG_SEPARATE || iSample == 0 ) { if( TIFFIsTiled(hTIFF) ) { TIFFReadEncodedTile( hTIFF, TIFFComputeTile(hTIFF, nSXOff, nSYOff, 0, iSample ), pabySrcTile, TIFFTileSize(hTIFF)); } else { TIFFReadEncodedStrip( hTIFF, TIFFComputeStrip(hTIFF, nSYOff, iSample), pabySrcTile, TIFFStripSize(hTIFF) ); } } /* * Loop over destination overview layers */ for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { TIFFOvrCache *poRBI = papoRawBIs[iOverview]; unsigned char *pabyOTile; int nTXOff, nTYOff, nOXOff, nOYOff, nOMult; int nOBlockXSize = poRBI->nBlockXSize; int nOBlockYSize = poRBI->nBlockYSize; int nSkewBits, nSampleByteOffset; /* * Fetch the destination overview tile */ nOMult = panOvList[iOverview]; nOXOff = (nSXOff/nOMult) / nOBlockXSize; nOYOff = (nSYOff/nOMult) / nOBlockYSize; pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample ); /* * Establish the offset into this tile at which we should * start placing data. */ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; /* * Figure out the skew (extra space between ``our samples'') and * the byte offset to the first sample. */ assert( (nBitsPerPixel % 8) == 0 ); if( nPlanarConfig == PLANARCONFIG_SEPARATE ) { nSkewBits = 0; nSampleByteOffset = 0; } else { nSkewBits = nBitsPerPixel * (nSamples-1); nSampleByteOffset = (nBitsPerPixel/8) * iSample; } /* * Perform the downsampling. */ #ifdef DBMALLOC malloc_chain_check( 1 ); #endif TIFF_DownSample( pabySrcTile + nSampleByteOffset, nBlockXSize, nBlockYSize, nSkewBits, nBitsPerPixel, pabyOTile, poRBI->nBlockXSize, poRBI->nBlockYSize, nTXOff, nTYOff, nOMult, nSampleFormat, pszResampling ); #ifdef DBMALLOC malloc_chain_check( 1 ); #endif } } }
static void TIFF_WriteOverview( TIFF *hTIFF, int nSamples, RawBlockedImage **papoRBI, int bTiled, int nCompressFlag, int nPhotometric, unsigned short *panRed, unsigned short *panGreen, unsigned short *panBlue, int bUseSubIFDs ) { int iSample; RawBlockedImage *poRBI = papoRBI[0]; /* -------------------------------------------------------------------- */ /* Setup TIFF fields. */ /* -------------------------------------------------------------------- */ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, poRBI->GetXSize() ); TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, poRBI->GetYSize() ); TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_SEPARATE ); TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, poRBI->GetBitsPerPixel() ); TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples ); TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag ); TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric ); if( bTiled ) { TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, poRBI->GetBlockXSize() ); TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, poRBI->GetBlockYSize() ); } else TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, poRBI->GetBlockYSize() ); TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE ); /* -------------------------------------------------------------------- */ /* Write color table if one is present. */ /* -------------------------------------------------------------------- */ if( panRed != NULL ) { TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue ); } /* -------------------------------------------------------------------- */ /* Write blocks to TIFF file. */ /* -------------------------------------------------------------------- */ for( iSample = 0; iSample < nSamples; iSample++ ) { int iTileX, iTileY; poRBI = papoRBI[iSample]; for( iTileY = 0; iTileY*poRBI->GetBlockYSize() < poRBI->GetYSize(); iTileY++ ) { for( iTileX = 0; iTileX*poRBI->GetBlockXSize() < poRBI->GetXSize(); iTileX++ ) { unsigned char *pabyData = poRBI->GetTile( iTileX, iTileY ); int nTileID; if( bTiled ) { nTileID = TIFFComputeTile(hTIFF, iTileX * poRBI->GetBlockXSize(), iTileY * poRBI->GetBlockYSize(), 0, iSample ); TIFFWriteEncodedTile( hTIFF, nTileID, pabyData, TIFFTileSize(hTIFF) ); } else { nTileID = TIFFComputeStrip(hTIFF, iTileY*poRBI->GetBlockYSize(), iSample); TIFFWriteEncodedStrip( hTIFF, nTileID, pabyData, TIFFStripSize( hTIFF ) ); } } } } TIFFWriteDirectory( hTIFF ); }
Image *Read (IStream *file, const Image::ReadOptions& options) { int nrow; int result = 0; long LineSize; TIFF *tif; Image *image ; uint16 BitsPerSample; uint16 BytesPerSample = 1; uint16 PhotometricInterpretation; uint16 SamplePerPixel; uint16 Orientation; uint32 RowsPerStrip; unsigned int width; unsigned int height; // TODO - TIFF files probably have some gamma info in them by default, but we're currently ignorant about that. // Until that is fixed, use whatever the user has chosen as default. GammaCurvePtr gamma; if (options.gammacorrect && options.defaultGamma) gamma = TranscodingGammaCurve::Get(options.workingGamma, options.defaultGamma); // [CLi] TIFF is specified to use associated (= premultiplied) alpha, so that's the preferred mode to use for the image container unless the user overrides // (e.g. to handle a non-compliant file). bool premul = true; if (options.premultiplyOverride) premul = options.premultiply; // Rather than have libTIFF complain about tags it doesn't understand, // we just suppress all the warnings. TIFFSetWarningHandler(SuppressTIFFWarnings); TIFFSetErrorHandler(SuppressTIFFWarnings); // Open and do initial processing tif = TIFFClientOpen("Dummy File Name", "r", file, Tiff_Read, Tiff_Write, Tiff_Seek, Tiff_Close, Tiff_Size, Tiff_Map, Tiff_Unmap); if (!tif) return (NULL) ; // Get basic information about the image int ExtraSamples, ExtraSampleInfo; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); TIFFGetField(tif, TIFFTAG_ORIENTATION, &Orientation); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &ExtraSamples, &ExtraSampleInfo); // don't support more than 16 bits per sample if (BitsPerSample == 16) { BytesPerSample = 2 ; options.warnings.push_back ("Warning: reading 16 bits/sample TIFF file; components crunched to 8"); } LineSize = TIFFScanlineSize(tif); assert (SamplePerPixel == (int) (LineSize / width) / BytesPerSample); // SamplePerPixel = (int)(LineSize / width); #if 0 // For now we are ignoring the orientation of the image... switch (Orientation) { case ORIENTATION_TOPLEFT: break; case ORIENTATION_TOPRIGHT: break; case ORIENTATION_BOTRIGHT: break; case ORIENTATION_BOTLEFT: break; case ORIENTATION_LEFTTOP: break; case ORIENTATION_RIGHTTOP: break; case ORIENTATION_RIGHTBOT: break; case ORIENTATION_LEFTBOT: break; default: break; } #endif //PhotometricInterpretation = 2 image is RGB //PhotometricInterpretation = 3 image have a color palette if (PhotometricInterpretation == PHOTOMETRIC_PALETTE && (TIFFIsTiled(tif) == 0)) { uint16 *red, *green, *blue; //load the palette int cmap_len = (1 << BitsPerSample); TIFFGetField(tif, TIFFTAG_COLORMAP, &red, &green, &blue); vector<Image::RGBMapEntry> colormap ; Image::RGBMapEntry entry; // I may be mistaken, but it appears that alpha/opacity information doesn't // appear in a Paletted Tiff image. Well - if it does, it's not as easy to // get at as RGB. // Read the palette // Is the palette 16 or 8 bits ? if (checkcmap(cmap_len, red, green, blue) == 16) { for (int i=0;i<cmap_len;i++) { entry.red = IntDecode(gamma, red[i], 65535); entry.green = IntDecode(gamma, green[i], 65535); entry.blue = IntDecode(gamma, blue[i], 65535); colormap.push_back (entry); } } else { for (int i=0;i<cmap_len;i++) { entry.red = IntDecode(gamma, red[i], 255); entry.green = IntDecode(gamma, green[i], 255); entry.blue = IntDecode(gamma, blue[i], 255); colormap.push_back (entry); } } Image::ImageDataType imagetype = options.itype; if (imagetype == Image::Undefined) imagetype = Image::Colour_Map; image = Image::Create (width, height, imagetype, colormap) ; image->SetPremultiplied(premul); // specify whether the color map data has premultiplied alpha boost::scoped_array<unsigned char> buf (new unsigned char [TIFFStripSize(tif)]); //read the tiff lines and save them in the image //with RGB mode, we have to change the order of the 3 samples RGB <=> BGR for (int row=0;row<height;row+=RowsPerStrip) { nrow = (row + (int)RowsPerStrip > height ? height - row : RowsPerStrip); TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, row, 0), buf.get(), nrow * LineSize); for (int l = 0, offset = 0; l < nrow ; l++, offset += LineSize) for (int x = 0 ; x < width ; x++) image->SetIndexedValue (x, row+l, buf[offset+x]) ; } } else { // Allocate the row buffers for the image boost::scoped_array<uint32> buf (new uint32 [width * height]) ; Image::ImageDataType imagetype = options.itype; if (imagetype == Image::Undefined) imagetype = ( GammaCurve::IsNeutral(gamma) ? Image::RGBA_Int8 : Image::RGBA_Gamma8 ); image = Image::Create (width, height, imagetype) ; image->SetPremultiplied(premul); // set desired storage mode regarding alpha premultiplication image->TryDeferDecoding(gamma, 255); // try to have gamma adjustment being deferred until image evaluation. TIFFReadRGBAImage(tif, width, height, buf.get(), 0); uint32 abgr, *tbuf = buf.get(); for (int i=height-1;i>=0;i--) { for (int j=0;j<width;j++) { abgr = *tbuf++; unsigned int b = (unsigned char)TIFFGetB(abgr); unsigned int g = (unsigned char)TIFFGetG(abgr); unsigned int r = (unsigned char)TIFFGetR(abgr); unsigned int a = (unsigned char)TIFFGetA(abgr); SetEncodedRGBAValue(image, j, i, gamma, 255, r, g, b, a, premul) ; } } } TIFFClose(tif); return (image) ; }
BOOL CImageTIFF::Read(FILE* stream) { TIFF* m_tif = TIFFOpenEx(stream, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=-1; uint16 photometric=0; uint16 compression=1; uint32 x, y; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; m_info.nNumFrames=0; while(TIFFSetDirectory(m_tif,(uint16)m_info.nNumFrames)) m_info.nNumFrames++; if (!TIFFSetDirectory(m_tif, (uint16)m_info.nFrame)) throw "Error: page not present in TIFF file"; //get image m_info TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); if (compression == COMPRESSION_LZW) throw "LZW compression is no longer supported due to Unisys patent enforcement"; TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); m_header.biWidth = width; m_header.biHeight = height; m_header.biClrUsed=0; m_info.nBkgndIndex =-1; isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ m_header.biBitCount=24; m_info.bColorType = COLORTYPE_COLOR; }else{ m_info.bColorType = COLORTYPE_PALETTE; if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ m_header.biBitCount=1; //B&W image m_header.biClrUsed =2; } else { m_header.biBitCount=8; //gray scale m_header.biClrUsed =256; } } else if (bitspersample == 4) { m_header.biBitCount=4; // 16 colors m_header.biClrUsed=16; } else { m_header.biBitCount=8; //256 colors m_header.biClrUsed=256; } } Create(m_header.biWidth,m_header.biHeight,m_header.biBitCount); //image creation if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = m_info.pImage; for (y = 0; y < height; y++) { bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); } row += width; bits2 += m_info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = i; } } else { for (int i = 0; i < 256; i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = 255 - i; } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,m_header.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); // int pitch = CalculatePitch(line); long bitsize= TIFFStripSize(m_tif); bits = (BYTE*)malloc(bitsize); for (ys = 0; ys < height; ys += rowsperstrip) { nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } for (y = 0; y < nrow; y++) { memcpy(m_info.pImage+m_info.dwEffWidth*(height-ys-nrow+y),bits+(nrow-y-1)*line,line); } /*if (m_header.biClrUsed==2){ for (y = 0; y < nrow; y++) { for (x = 0; x < width; x++) { SetPixelIndex(x,y+ys,(bits[y*line+(x>>3)]>>(7-x%8))&0x01); }}}*/ } free(bits); } } catch (char *message) { strncpy(m_info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); return FALSE; } TIFFClose(m_tif); return TRUE; }
// Internal function used to load the Tiff. ILboolean iLoadTiffInternal() { TIFF *tif; uint16 w, h, d, photometric, planarconfig; uint16 samplesperpixel, bitspersample, *sampleinfo, extrasamples; ILubyte *pImageData; ILuint i, ProfileLen, DirCount = 0; ILvoid *Buffer; ILimage *Image; ILushort si; //TIFFRGBAImage img; //char emsg[1024]; if (iCurImage == NULL) { ilSetError(IL_ILLEGAL_OPERATION); return IL_FALSE; } TIFFSetWarningHandler(NULL); TIFFSetErrorHandler(NULL); //for debugging only //TIFFSetWarningHandler(warningHandler); //TIFFSetErrorHandler(errorHandler); tif = iTIFFOpen("r"); if (tif == NULL) { ilSetError(IL_COULD_NOT_OPEN_FILE); return IL_FALSE; } do { DirCount++; } while (TIFFReadDirectory(tif)); /* if (!ilTexImage(1, 1, 1, 1, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) { TIFFClose(tif); return IL_FALSE; } Image = iCurImage; for (i = 1; i < DirCount; i++) { Image->Next = ilNewImage(1, 1, 1, 1, 1); if (Image->Next == NULL) { TIFFClose(tif); return IL_FALSE; } Image = Image->Next; } iCurImage->NumNext = DirCount - 1; */ Image = NULL; for (i = 0; i < DirCount; i++) { TIFFSetDirectory(tif, (tdir_t)i); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEDEPTH, &d); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &bitspersample); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); //added 2003-08-31 //1 bpp tiffs are not neccessarily greyscale, they can //have a palette (photometric == 3)...get this information TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); if (samplesperpixel - extrasamples == 1) { //luminance or palette ILubyte* strip; tsize_t stripsize; ILuint y; uint32 rowsperstrip; if(!Image) { if(!ilTexImage(w, h, 1, 1, IL_LUMINANCE, IL_UNSIGNED_BYTE, NULL)) { TIFFClose(tif); return IL_FALSE; } iCurImage->NumNext = 0; Image = iCurImage; } else { Image->Next = ilNewImage(w, h, 1, 1, 1); if(Image->Next == NULL) { TIFFClose(tif); return IL_FALSE; } Image = Image->Next; iCurImage->NumNext++; } TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); stripsize = TIFFStripSize(tif); strip = ialloc(stripsize); for(y = 0; y < h; y += rowsperstrip) { //if(y + rowsperstrip > h) // stripsize = (stripsize*(h - y))/rowsperstrip; if (TIFFReadEncodedStrip(tif, TIFFComputeStrip(tif, y, 0), strip, stripsize) == -1) { ilSetError(IL_LIB_TIFF_ERROR); ifree(strip); TIFFClose(tif); return IL_FALSE; } } ifree(strip); } else {//rgb or rgba if(!Image) { if(!ilTexImage(w, h, 1, 4, IL_RGBA, IL_UNSIGNED_BYTE, NULL)) { TIFFClose(tif); return IL_FALSE; } iCurImage->NumNext = 0; Image = iCurImage; } else { Image->Next = ilNewImage(w, h, 1, 4, 1); if(Image->Next == NULL) { TIFFClose(tif); return IL_FALSE; } Image = Image->Next; iCurImage->NumNext++; } if (samplesperpixel == 4) { TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (!sampleinfo || sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED) { si = EXTRASAMPLE_ASSOCALPHA; TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, &si); } } /* if (!ilResizeImage(Image, Image->Width, Image->Height, 1, 4, 1)) { TIFFClose(tif); return IL_FALSE; }*/ Image->Format = IL_RGBA; Image->Type = IL_UNSIGNED_BYTE; // Siigron: added u_long cast to shut up compiler warning //2003-08-31: changed flag from 1 (exit on error) to 0 (keep decoding) //this lets me view text.tif, but can give crashes with unsupported //tiffs... //2003-09-04: keep flag 1 for official version for now if (!TIFFReadRGBAImage(tif, Image->Width, Image->Height, (uint32*)Image->Data, 1)) { TIFFClose(tif); ilSetError(IL_LIB_TIFF_ERROR); return IL_FALSE; } } //else rgb or rgba if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &ProfileLen, &Buffer)) { if (Image->Profile && Image->ProfileSize) ifree(Image->Profile); Image->Profile = (ILubyte*)ialloc(ProfileLen); if (Image->Profile == NULL) { TIFFClose(tif); return IL_FALSE; } memcpy(Image->Profile, Buffer, ProfileLen); Image->ProfileSize = ProfileLen; //removed on 2003-08-24 as explained in bug 579574 on sourceforge //_TIFFfree(Buffer); } Image->Origin = IL_ORIGIN_LOWER_LEFT; // eiu...dunno if this is right /* Image = Image->Next; if (Image == NULL) // Should never happen except when we reach the end, but check anyway. break;*/ } //for tiff directories //TODO: put switch into the loop?? switch (samplesperpixel) { case 1: //added 2003-08-31 to keep palettized tiffs colored /* if(photometric != 3) ilConvertImage(IL_LUMINANCE, IL_UNSIGNED_BYTE); else //strip alpha as tiff supports no alpha palettes ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE);*/ break; case 3: //TODO: why the ifdef?? #ifdef __LITTLE_ENDIAN__ ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); #endif break; case 4: pImageData = iCurImage->Data; //removed on 2003-08-26...why was this here? libtiff should and does //take care of these things??? /* //invert alpha #ifdef __LITTLE_ENDIAN__ pImageData += 3; #endif for (i = iCurImage->Width * iCurImage->Height; i > 0; i--) { *pImageData ^= 255; pImageData += 4; } */ break; } TIFFClose(tif); ilFixImage(); return IL_TRUE; }