static int TileBasedXform(cmsHTRANSFORM hXForm, TIFF* in, TIFF* out, int nPlanes) { tsize_t BufSizeIn = TIFFTileSize(in); tsize_t BufSizeOut = TIFFTileSize(out); unsigned char *BufferIn, *BufferOut; ttile_t i, TileCount = TIFFNumberOfTiles(in) / nPlanes; uint32 tw, tl; int PixelCount, j; TIFFGetFieldDefaulted(in, TIFFTAG_TILEWIDTH, &tw); TIFFGetFieldDefaulted(in, TIFFTAG_TILELENGTH, &tl); PixelCount = (int) tw * tl; BufferIn = (unsigned char *) _TIFFmalloc(BufSizeIn * nPlanes); if (!BufferIn) OutOfMem(BufSizeIn * nPlanes); BufferOut = (unsigned char *) _TIFFmalloc(BufSizeOut * nPlanes); if (!BufferOut) OutOfMem(BufSizeOut * nPlanes); for (i = 0; i < TileCount; i++) { for (j=0; j < nPlanes; j++) { if (TIFFReadEncodedTile(in, i + (j* TileCount), BufferIn + (j*BufSizeIn), BufSizeIn) < 0) goto cleanup; } cmsDoTransform(hXForm, BufferIn, BufferOut, PixelCount); for (j=0; j < nPlanes; j++) { if (TIFFWriteEncodedTile(out, i + (j*TileCount), BufferOut + (j*BufSizeOut), BufSizeOut) < 0) goto cleanup; } } _TIFFfree(BufferIn); _TIFFfree(BufferOut); return 1; cleanup: _TIFFfree(BufferIn); _TIFFfree(BufferOut); return 0; }
/* * Setup the raw data buffer used for encoding. */ static int TIFFBufferSetup(TIFF* tif, const char* module) { tsize_t size; if (isTiled(tif)) tif->tif_tilesize = size = TIFFTileSize(tif); else tif->tif_scanlinesize = size = TIFFScanlineSize(tif); /* * Make raw data buffer at least 8K */ if (size < 8*1024) size = 8*1024; tif->tif_rawdata = (tidata_t)_TIFFmalloc(size); if (tif->tif_rawdata == NULL) { TIFFError(module, "%s: No space for output buffer", tif->tif_name); return (0); } tif->tif_flags |= TIFF_MYBUFFER; tif->tif_rawdatasize = size; tif->tif_rawcc = 0; tif->tif_rawcp = tif->tif_rawdata; return (1); }
static int cpTiles(TIFF* in, TIFF* out) { tsize_t bufsize = TIFFTileSize(in); unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize); if (buf) { ttile_t t, nt = TIFFNumberOfTiles(in); tsize_t *bytecounts; TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts); for (t = 0; t < nt; t++) { if (bytecounts[t] > bufsize) { buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]); if (!buf) goto bad; bufsize = bytecounts[t]; } if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 || TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) { _TIFFfree(buf); return 0; } } _TIFFfree(buf); return 1; } bad: TIFFError(TIFFFileName(in), "Can't allocate space for tile buffer."); return (0); }
static tsize_t my_readtile(TIFF *tif, tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t sample) { tsize_t r = TIFFReadTile(tif, buf, x, y, z, sample); if (r == -1) memset(buf, 0, r = TIFFTileSize(tif)); return r; }
static int cpTiles(TIFF* in, TIFF* out) { tmsize_t bufsize = TIFFTileSize(in); unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize); if (buf) { ttile_t t, nt = TIFFNumberOfTiles(in); uint64 *bytecounts; TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts); for (t = 0; t < nt; t++) { if (bytecounts[t] > (uint64) bufsize) { buf = (unsigned char *)_TIFFrealloc(buf, (tmsize_t)bytecounts[t]); if (!buf) return (0); bufsize = (tmsize_t)bytecounts[t]; } if (TIFFReadRawTile(in, t, buf, (tmsize_t)bytecounts[t]) < 0 || TIFFWriteRawTile(out, t, buf, (tmsize_t)bytecounts[t]) < 0) { _TIFFfree(buf); return (0); } } _TIFFfree(buf); return (1); } return (0); }
static bool tiletoimg(img *d, TIFF *T, bool c, int e, int k) { int n = 1 << (d->n - e); int m = 1 << d->m; int s = 1 << k; int y = 0; int x = 0; float *p; if ((p = (float *) malloc(TIFFTileSize(T)))) { for (y = 0; y < n; y += s) for (x = 0; x < m; x += s) { if (TIFFReadTile(T, p, x, y, 0, 0) == -1) return false; if (c) tiletoimgz(y, x, d, s, p); else tiletoimgr(y, x, d, s, p); if (e) { reverse(p, c ? d->p * 2 : d->p, s * s); if (c) tiletoimgz(2 * n - y - s, m - x - s, d, s, p); else tiletoimgr(2 * n - y - s, m - x - s, d, s, p); } } free(p); } return (y == n && x == m); }
/* * Get an tile-organized image that has * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtTileSeparate(TIFFImageIter* img, void *udata, uint32 w, uint32 h) { TIFF* tif = img->tif; ImageIterTileSeparateRoutine callback = img->callback.separate; uint16 orientation; uint32 col, row; uint32 tw, th; u_char* buf; u_char* r; u_char* g; u_char* b; u_char* a; tsize_t tilesize; int32 fromskew; int alpha = img->alpha; uint32 nrow; tilesize = TIFFTileSize(tif); buf = (u_char*) _TIFFmalloc(4*tilesize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } r = buf; g = r + tilesize; b = g + tilesize; a = b + tilesize; if (!alpha) memset(a, 0xff, tilesize); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); orientation = img->orientation; for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr) break; if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*callback)(img, udata, col, row, npix, nrow, fromskew, r, g, b, a); } else { (*callback)(img, udata, col, row, tw, nrow, 0, r, g, b, a); } } } _TIFFfree(buf); return (1); }
static int cpTiles(TIFF* in, TIFF* out) { tsize_t bufsize = TIFFTileSize(in); unsigned char *buf = (unsigned char *)_TIFFmalloc(bufsize); if (buf) { ttile_t t, nt = TIFFNumberOfTiles(in); uint32 *bytecounts; if (!TIFFGetField(in, TIFFTAG_TILEBYTECOUNTS, &bytecounts)) { fprintf(stderr, "tiffsplit: tile byte counts are missing\n"); return (0); } for (t = 0; t < nt; t++) { if (bytecounts[t] > (uint32) bufsize) { buf = (unsigned char *)_TIFFrealloc(buf, bytecounts[t]); if (!buf) return (0); bufsize = bytecounts[t]; } if (TIFFReadRawTile(in, t, buf, bytecounts[t]) < 0 || TIFFWriteRawTile(out, t, buf, bytecounts[t]) < 0) { _TIFFfree(buf); return (0); } } _TIFFfree(buf); return (1); } return (0); }
/* * Verify file is writable and that the directory * information is setup properly. In doing the latter * we also "freeze" the state of the directory so * that important information is not changed. */ int TIFFWriteCheck(TIFF* tif, int tiles, const char* module) { if (tif->tif_mode == O_RDONLY) { TIFFErrorExt(tif->tif_clientdata, module, "%s: File not open for writing", tif->tif_name); return (0); } if (tiles ^ isTiled(tif)) { TIFFErrorExt(tif->tif_clientdata, tif->tif_name, tiles ? "Can not write tiles to a stripped image" : "Can not write scanlines to a tiled image"); return (0); } /* * On the first write verify all the required information * has been setup and initialize any data structures that * had to wait until directory information was set. * Note that a lot of our work is assumed to remain valid * because we disallow any of the important parameters * from changing after we start writing (i.e. once * TIFF_BEENWRITING is set, TIFFSetField will only allow * the image's length to be changed). */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Must set \"ImageWidth\" before writing data", tif->tif_name); return (0); } if (tif->tif_dir.td_samplesperpixel == 1) { /* * Planarconfiguration is irrelevant in case of single band * images and need not be included. We will set it anyway, * because this field is used in other parts of library even * in the single band case. */ if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) tif->tif_dir.td_planarconfig = PLANARCONFIG_CONTIG; } else { if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { TIFFErrorExt(tif->tif_clientdata, module, "%s: Must set \"PlanarConfiguration\" before writing data", tif->tif_name); return (0); } } if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { tif->tif_dir.td_nstrips = 0; TIFFErrorExt(tif->tif_clientdata, module, "%s: No space for %s arrays", tif->tif_name, isTiled(tif) ? "tile" : "strip"); return (0); } tif->tif_tilesize = isTiled(tif) ? TIFFTileSize(tif) : (tsize_t) -1; tif->tif_scanlinesize = TIFFScanlineSize(tif); tif->tif_flags |= TIFF_BEENWRITING; return (1); }
/* * Get an tile-organized image that has * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ boolean TIFFRasterImpl::gtTileSeparate( const RGBvalue* Map, u_long h, u_long w ) { u_long tilesize = TIFFTileSize(tif_); u_char* buf = new u_char[3*tilesize]; if (buf == nil) { TIFFError(TIFFFileName(tif_), "No space for tile buffer"); return false; } u_char* r = buf; u_char* g = r + tilesize; u_char* b = g + tilesize; tileSeparateRoutine put = pickTileSeparateCase(Map); u_long tw; TIFFGetField(tif_, TIFFTAG_TILEWIDTH, &tw); u_long th; TIFFGetField(tif_, TIFFTAG_TILELENGTH, &th); u_long y = setorientation(h); int toskew = (int)(orientation_ == ORIENTATION_TOPLEFT ? -tw+-w : -tw+w); for (u_long row = 0; row < h; row += th) { u_long nrow = (row + th > h ? h - row : th); for (u_long col = 0; col < w; col += tw) { if (TIFFReadTile(tif_, r, col, row, 0, 0) < 0) { break; } if (TIFFReadTile(tif_, g, col, row, 0, 1) < 0) { break; } if (TIFFReadTile(tif_, b, col, row, 0, 2) < 0) { break; } if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ u_long npix = w - col; int fromskew = (int)(tw - npix); (this->*put)( raster_ + y*w + col, r, g, b, Map, npix, nrow, fromskew, toskew + fromskew ); } else (this->*put)( raster_ + y*w + col, r, g, b, Map, tw, nrow, 0, toskew ); } y += (orientation_ == ORIENTATION_TOPLEFT ? -nrow : nrow); } delete buf; return true; }
/* * Verify file is writable and that the directory * information is setup properly. In doing the latter * we also "freeze" the state of the directory so * that important information is not changed. */ static int TIFFWriteCheck(TIFF* tif, int tiles, const char* module) { if (tif->tif_mode == O_RDONLY) { TIFFError(module, "%s: File not open for writing", tif->tif_name); return (0); } if (tiles ^ isTiled(tif)) { TIFFError(tif->tif_name, tiles ? "Can not write tiles to a stripped image" : "Can not write scanlines to a tiled image"); return (0); } /* * On the first write verify all the required information * has been setup and initialize any data structures that * had to wait until directory information was set. * Note that a lot of our work is assumed to remain valid * because we disallow any of the important parameters * from changing after we start writing (i.e. once * TIFF_BEENWRITING is set, TIFFSetField will only allow * the image's length to be changed). */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { TIFFError(module, "%s: Must set \"ImageWidth\" before writing data", tif->tif_name); return (0); } if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { TIFFError(module, "%s: Must set \"PlanarConfiguration\" before writing data", tif->tif_name); return (0); } if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { tif->tif_dir.td_nstrips = 0; TIFFError(module, "%s: No space for %s arrays", tif->tif_name, isTiled(tif) ? "tile" : "strip"); return (0); } tif->tif_tilesize = TIFFTileSize(tif); tif->tif_scanlinesize = TIFFScanlineSize(tif); tif->tif_flags |= TIFF_BEENWRITING; return (1); }
/* * Get an tile-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtTileContig(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileContigRoutine put = img->put.contig; uint16 orientation; uint32 col, row, y; uint32 tw, th; u_char* buf; int32 fromskew, toskew; uint32 nrow; buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*put)(img, raster+y*w+col, col, y, npix, nrow, fromskew, toskew + fromskew, buf); } else { (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, buf); } } y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); }
/** * Constructor. * * @param ifd the directory the tile belongs to. */ Impl(std::shared_ptr<IFD>& ifd): ifd(ifd), tilewidth(), tileheight(), planarconfig(), samples(), tilecount(), nrows(), ncols(), ntiles(), buffersize() { Sentry sentry; ::TIFF *tiff = getTIFF(); // Get basic image metadata. uint32_t imagewidth = ifd->getImageWidth(); uint32_t imageheight = ifd->getImageHeight(); planarconfig = ifd->getPlanarConfiguration(); samples = ifd->getSamplesPerPixel(); tilewidth = ifd->getTileWidth(); tileheight = ifd->getTileHeight(); type = ifd->getTileType(); // Get tile-specific metadata, falling back to // strip-specific metadata if not present. if (type == TILE) { tilecount = TIFFNumberOfTiles(tiff); buffersize = TIFFTileSize(tiff); } else { tilecount = TIFFNumberOfStrips(tiff); buffersize = TIFFStripSize(tiff); } // Compute row and column counts. nrows = imageheight / tileheight; if (imageheight % tileheight) ++nrows; ncols = imagewidth / tilewidth; if (imagewidth % tilewidth) ++ncols; ntiles = nrows * ncols; }
static void read_tile_from_file(struct tiff_tile *t, char *filename, int tidx) { TIFF *tif = tiffopen_fancy(filename, "r"); if (!tif) fail("could not open TIFF file \"%s\" for reading", filename); uint32_t w, h; uint16_t spp, bps, fmt, planarity; TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bps); TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &fmt); TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarity); t->spp = spp; t->bps = bps; t->fmt = fmt; t->broken = false; if (planarity != PLANARCONFIG_CONTIG) fail("broken pixels not supported yet"); if (TIFFIsTiled(tif)) { int nt = TIFFNumberOfTiles(tif); if (tidx < 0 || tidx >= nt) fail("bad tile index %d", tidx); t->w = tiff_tilewidth(tif);; t->h = tiff_tilelength(tif); int ii[2]; tiff_tile_corner(ii, tif, tidx); //int ii = tw*i; //int jj = th*j; int tbytes = TIFFTileSize(tif); t->data = xmalloc(tbytes); memset(t->data, 0, tbytes); int r = my_readtile(tif, t->data, ii[0], ii[1], 0, 0); if (r != tbytes) fail("could not read tile"); } else { // not tiled, read the whole image into 0th tile read_scanlines(t, tif); } TIFFClose(tif); }
/* * Get an tile-organized image that has * PlanarConfiguration contiguous if SamplesPerPixel > 1 * or * SamplesPerPixel == 1 */ static int gtTileContig(TIFFImageIter* img, void *udata, uint32 w, uint32 h) { TIFF* tif = img->tif; ImageIterTileContigRoutine callback = img->callback.contig; uint16 orientation; uint32 col, row; uint32 tw, th; u_char* buf; int32 fromskew; uint32 nrow; buf = (u_char*) _TIFFmalloc(TIFFTileSize(tif)); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); orientation = img->orientation; for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, buf, col, row, 0, 0) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*callback)(img, udata, col, row, npix, nrow, fromskew, buf); } else { (*callback)(img, udata, col, row, tw, nrow, 0, buf); } } } _TIFFfree(buf); return (1); }
// Write a 4x5 tiled test tiff intended to have the correct sizes for a mipmap void writeTiledTiff(const char* fileName) { uint32 height = 5; uint32 width = 4; uint16 samplesPerPixel = 3; uint16 bitsPerSample = 8; uint32 tileWidth = 16; uint32 tileHeight = 16; //TIFF* outFile = TIFFStreamOpen("stream", &outStream); TIFF* outFile = TIFFOpen(fileName, "w"); setTiffFields(outFile, width, height, samplesPerPixel, bitsPerSample); TIFFSetField(outFile, TIFFTAG_TILEWIDTH, tileWidth); TIFFSetField(outFile, TIFFTAG_TILELENGTH, tileHeight); tsize_t bufSize = TIFFTileSize(outFile); char* buf = reinterpret_cast<char*>(_TIFFmalloc(bufSize)); _TIFFmemset(buf, 0x00, bufSize); // first directory TIFFWriteEncodedTile(outFile, 0, buf, bufSize); TIFFWriteDirectory(outFile); // rest of the directories while(width > 1 || height > 1) { width = std::max<uint32>((width+1)/2, 1); height = std::max<uint32>((height+1)/2, 1); setTiffFields(outFile, width, height, samplesPerPixel, bitsPerSample); TIFFSetField(outFile, TIFFTAG_TILEWIDTH, tileWidth); TIFFSetField(outFile, TIFFTAG_TILELENGTH, tileHeight); TIFFWriteEncodedTile(outFile, 0, buf, bufSize); TIFFWriteDirectory(outFile); } TIFFClose(outFile); _TIFFfree(buf); }
/* Pack the pixels in @area from @in into a TIFF tile buffer. */ static void pack2tiff( Write *write, Layer *layer, VipsRegion *in, VipsRect *area, VipsPel *q ) { int y; /* JPEG compression can read outside the pixel area for edge tiles. It * always compresses 8x8 blocks, so if the image width or height is * not a multiple of 8, it can look beyond the pixels we will write. * * Black out the tile first to make sure these edge pixels are always * zero. */ if( write->compression == COMPRESSION_JPEG && (area->width < write->tilew || area->height < write->tileh) ) memset( q, 0, TIFFTileSize( layer->tif ) ); for( y = area->top; y < VIPS_RECT_BOTTOM( area ); y++ ) { VipsPel *p = (VipsPel *) VIPS_REGION_ADDR( in, area->left, y ); if( write->im->Coding == VIPS_CODING_LABQ ) LabQ2LabC( q, p, area->width ); else if( write->onebit ) eightbit2onebit( write, q, p, area->width ); else if( (in->im->Bands == 1 || in->im->Bands == 2) && write->miniswhite ) invert_band0( write, q, p, area->width ); else if( write->im->BandFmt == VIPS_FORMAT_SHORT && write->im->Type == VIPS_INTERPRETATION_LABS ) LabS2Lab16( q, p, area->width ); else memcpy( q, p, area->width * VIPS_IMAGE_SIZEOF_PEL( write->im ) ); q += write->tls; } }
/* * Read the specified tile and setup for decoding. The data buffer is * expanded, as necessary, to hold the tile's data. */ int TIFFFillTile(TIFF* tif, uint32 tile) { static const char module[] = "TIFFFillTile"; TIFFDirectory *td = &tif->tif_dir; if (!_TIFFFillStriles( tif ) || !tif->tif_dir.td_stripbytecount) return 0; if ((tif->tif_flags&TIFF_NOREADRAW)==0) { uint64 bytecount = td->td_stripbytecount[tile]; if ((int64)bytecount <= 0) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFErrorExt(tif->tif_clientdata, module, "%I64u: Invalid tile byte count, tile %lu", (unsigned __int64) bytecount, (unsigned long) tile); #else TIFFErrorExt(tif->tif_clientdata, module, "%llu: Invalid tile byte count, tile %lu", (unsigned long long) bytecount, (unsigned long) tile); #endif return (0); } /* To avoid excessive memory allocations: */ /* Byte count should normally not be larger than a number of */ /* times the uncompressed size plus some margin */ if( bytecount > 1024 * 1024 ) { /* 10 and 4096 are just values that could be adjusted. */ /* Hopefully they are safe enough for all codecs */ tmsize_t stripsize = TIFFTileSize(tif); if( stripsize != 0 && (bytecount - 4096) / 10 > (uint64)stripsize ) { uint64 newbytecount = (uint64)stripsize * 10 + 4096; if( (int64)newbytecount >= 0 ) { #if defined(__WIN32__) && (defined(_MSC_VER) || defined(__MINGW32__)) TIFFWarningExt(tif->tif_clientdata, module, "Too large tile byte count %I64u, tile %lu. Limiting to %I64u", (unsigned __int64) bytecount, (unsigned long) tile, (unsigned __int64) newbytecount); #else TIFFErrorExt(tif->tif_clientdata, module, "Too large tile byte count %llu, tile %lu. Limiting to %llu", (unsigned long long) bytecount, (unsigned long) tile, (unsigned long long) newbytecount); #endif bytecount = newbytecount; } } } if (isMapped(tif)) { /* * We must check for overflow, potentially causing * an OOB read. Instead of simple * * td->td_stripoffset[tile]+bytecount > tif->tif_size * * comparison (which can overflow) we do the following * two comparisons: */ if (bytecount > (uint64)tif->tif_size || td->td_stripoffset[tile] > (uint64)tif->tif_size - bytecount) { tif->tif_curtile = NOTILE; return (0); } } if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) { /* * The image is mapped into memory and we either don't * need to flip bits or the compression routine is * going to handle this operation itself. In this * case, avoid copying the raw data and instead just * reference the data from the memory mapped file * image. This assumes that the decompression * routines do not modify the contents of the raw data * buffer (if they try to, the application will get a * fault since the file is mapped read-only). */ if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata) { _TIFFfree(tif->tif_rawdata); tif->tif_rawdata = NULL; tif->tif_rawdatasize = 0; } tif->tif_flags &= ~TIFF_MYBUFFER; tif->tif_rawdatasize = (tmsize_t)bytecount; tif->tif_rawdata = tif->tif_base + (tmsize_t)td->td_stripoffset[tile]; tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = (tmsize_t) bytecount; tif->tif_flags |= TIFF_BUFFERMMAP; } else { /* * Expand raw data buffer, if needed, to hold data * tile coming from file (perhaps should set upper * bound on the size of a buffer we'll use?). */ tmsize_t bytecountm; bytecountm=(tmsize_t)bytecount; if ((uint64)bytecountm!=bytecount) { TIFFErrorExt(tif->tif_clientdata,module,"Integer overflow"); return(0); } if (bytecountm > tif->tif_rawdatasize) { tif->tif_curtile = NOTILE; if ((tif->tif_flags & TIFF_MYBUFFER) == 0) { TIFFErrorExt(tif->tif_clientdata, module, "Data buffer too small to hold tile %lu", (unsigned long) tile); return (0); } } if (tif->tif_flags&TIFF_BUFFERMMAP) { tif->tif_curtile = NOTILE; tif->tif_rawdata = NULL; tif->tif_rawdatasize = 0; tif->tif_flags &= ~TIFF_BUFFERMMAP; } if( isMapped(tif) ) { if (bytecountm > tif->tif_rawdatasize && !TIFFReadBufferSetup(tif, 0, bytecountm)) { return (0); } if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, bytecountm, module) != bytecountm) { return (0); } } else { if (TIFFReadRawStripOrTile2(tif, tile, 0, bytecountm, module) != bytecountm) { return (0); } } tif->tif_rawdataoff = 0; tif->tif_rawdataloaded = bytecountm; if (!isFillOrder(tif, td->td_fillorder) && (tif->tif_flags & TIFF_NOBITREV) == 0) TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdataloaded); } } return (TIFFStartTile(tif, tile)); }
void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList, int bUseSubIFDs, const char *pszResampleMethod, int (*pfnProgress)( double, void * ), void * pProgressData ) { TIFFOvrCache **papoRawBIs; uint32 nXSize, nYSize, nBlockXSize, nBlockYSize; uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples, nPlanarConfig, nSampleFormat; int bTiled, nSXOff, nSYOff, i; unsigned char *pabySrcTile; uint16 *panRedMap, *panGreenMap, *panBlueMap; TIFFErrorHandler pfnWarning; /* -------------------------------------------------------------------- */ /* Get the base raster size. */ /* -------------------------------------------------------------------- */ TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize ); TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize ); TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel ); TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples ); TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig ); TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric ); TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag ); TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat ); if( nBitsPerPixel < 8 ) { TIFFError( "TIFFBuildOverviews", "File `%s' has samples of %d bits per sample. Sample\n" "sizes of less than 8 bits per sample are not supported.\n", TIFFFileName(hTIFF), nBitsPerPixel ); return; } /* -------------------------------------------------------------------- */ /* Turn off warnings to avoid alot of repeated warnings while */ /* rereading directories. */ /* -------------------------------------------------------------------- */ pfnWarning = TIFFSetWarningHandler( NULL ); /* -------------------------------------------------------------------- */ /* Get the base raster block size. */ /* -------------------------------------------------------------------- */ if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) ) { nBlockXSize = nXSize; bTiled = FALSE; } else { TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize ); TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize ); bTiled = TRUE; } /* -------------------------------------------------------------------- */ /* Capture the pallette if there is one. */ /* -------------------------------------------------------------------- */ if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP, &panRedMap, &panGreenMap, &panBlueMap ) ) { uint16 *panRed2, *panGreen2, *panBlue2; panRed2 = (uint16 *) _TIFFmalloc(2*256); panGreen2 = (uint16 *) _TIFFmalloc(2*256); panBlue2 = (uint16 *) _TIFFmalloc(2*256); memcpy( panRed2, panRedMap, 512 ); memcpy( panGreen2, panGreenMap, 512 ); memcpy( panBlue2, panBlueMap, 512 ); panRedMap = panRed2; panGreenMap = panGreen2; panBlueMap = panBlue2; } else { panRedMap = panGreenMap = panBlueMap = NULL; } /* -------------------------------------------------------------------- */ /* Initialize overviews. */ /* -------------------------------------------------------------------- */ papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*)); for( i = 0; i < nOverviews; i++ ) { int nOXSize, nOYSize, nOBlockXSize, nOBlockYSize; uint32 nDirOffset; nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i]; nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i]; nOBlockXSize = MIN((int)nBlockXSize,nOXSize); nOBlockYSize = MIN((int)nBlockYSize,nOYSize); if( bTiled ) { if( (nOBlockXSize % 16) != 0 ) nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16); if( (nOBlockYSize % 16) != 0 ) nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16); } nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize, nBitsPerPixel, nSamples, nOBlockXSize, nOBlockYSize, bTiled, nCompressFlag, nPhotometric, nSampleFormat, panRedMap, panGreenMap, panBlueMap, bUseSubIFDs ); papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset ); } if( panRedMap != NULL ) { _TIFFfree( panRedMap ); _TIFFfree( panGreenMap ); _TIFFfree( panBlueMap ); } /* -------------------------------------------------------------------- */ /* Allocate a buffer to hold a source block. */ /* -------------------------------------------------------------------- */ if( bTiled ) pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF)); else pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF)); /* -------------------------------------------------------------------- */ /* Loop over the source raster, applying data to the */ /* destination raster. */ /* -------------------------------------------------------------------- */ for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize ) { for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize ) { /* * Read and resample into the various overview images. */ TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig, nOverviews, panOvList, nBitsPerPixel, nSamples, papoRawBIs, nSXOff, nSYOff, pabySrcTile, nBlockXSize, nBlockYSize, nSampleFormat, pszResampleMethod ); } } _TIFFfree( pabySrcTile ); /* -------------------------------------------------------------------- */ /* Cleanup the rawblockedimage files. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nOverviews; i++ ) { TIFFDestroyOvrCache( papoRawBIs[i] ); } if( papoRawBIs != NULL ) _TIFFfree( papoRawBIs ); TIFFSetWarningHandler( pfnWarning ); }
/////////////////////////////////////////////////////////////////////// // Function : appendLayer // Description : Append a layer of image into an image file // Return Value : - // Comments : static void appendLayer(TIFF *out,int dstart,int numSamples,int bitsperpixel,int tileSize,int width,int height,void *data) { int x,y; unsigned char *tileData; int pixelSize; TIFFSetField(out, TIFFTAG_IMAGEWIDTH, (unsigned long) width); TIFFSetField(out, TIFFTAG_IMAGELENGTH, (unsigned long) height); TIFFSetField(out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(out, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE); TIFFSetField(out, TIFFTAG_XRESOLUTION, 1.0f); TIFFSetField(out, TIFFTAG_YRESOLUTION, 1.0f); TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_LZW); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_JPEG); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PACKBITS); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_THUNDERSCAN); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PIXARFILM); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_PIXARLOG); //TIFFSetField(out, TIFFTAG_COMPRESSION, COMPRESSION_DEFLATE); TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (unsigned long) numSamples); TIFFSetField(out, TIFFTAG_TILEWIDTH, (unsigned long) tileSize); TIFFSetField(out, TIFFTAG_TILELENGTH, (unsigned long) tileSize); if (bitsperpixel == 8) { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(unsigned char)*8)); pixelSize = numSamples*sizeof(unsigned char); } else if (bitsperpixel == 16) { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(unsigned short)*8)); TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK); pixelSize = numSamples*sizeof(unsigned short); } else { TIFFSetField(out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (unsigned long) (sizeof(float)*8)); pixelSize = numSamples*sizeof(float); } memBegin(CRenderer::globalMemory); tileData = (unsigned char *) ralloc(pixelSize*tileSize*tileSize,CRenderer::globalMemory); assert(TIFFTileSize(out) == (tileSize*tileSize*pixelSize)); for (y=0;y<height;y+=tileSize) { for (x=0;x<width;x+=tileSize) { int ty; for (ty=0;ty<tileSize;ty++) { memcpy(&tileData[ty*tileSize*pixelSize],&((unsigned char *) data)[((y+ty)*width+x)*pixelSize],tileSize*pixelSize); } TIFFWriteTile(out,tileData,x,y,0,0); } } TIFFWriteDirectory(out); memEnd(CRenderer::globalMemory); }
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; } }
/* * Read the next TIFF directory from a file * and convert it to the internal format. * We read directories sequentially. */ int TIFFReadDirectory(TIFF* tif) { register TIFFDirEntry* dp; register int n; register TIFFDirectory* td; TIFFDirEntry* dir; int iv; long v; double dv; const TIFFFieldInfo* fip; int fix; uint16 dircount; toff_t nextdiroff; char* cp; int diroutoforderwarning = 0; tif->tif_diroff = tif->tif_nextdiroff; if (tif->tif_diroff == 0) /* no more directories */ return (0); /* * Cleanup any previous compression state. */ (*tif->tif_cleanup)(tif); tif->tif_curdir++; nextdiroff = 0; if (!isMapped(tif)) { if (!SeekOK(tif, tif->tif_diroff)) { TIFFError(tif->tif_name, "Seek error accessing TIFF directory"); return (0); } if (!ReadOK(tif, &dircount, sizeof (uint16))) { TIFFError(tif->tif_name, "Can not read TIFF directory count"); return (0); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)CheckMalloc(tif, dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (!ReadOK(tif, dir, dircount*sizeof (TIFFDirEntry))) { TIFFError(tif->tif_name, "Can not read TIFF directory"); goto bad; } /* * Read offset to next directory for sequential scans. */ (void) ReadOK(tif, &nextdiroff, sizeof (uint32)); } else { toff_t off = tif->tif_diroff; if (off + sizeof (uint16) > tif->tif_size) { TIFFError(tif->tif_name, "Can not read TIFF directory count"); return (0); } else _TIFFmemcpy(&dircount, tif->tif_base + off, sizeof (uint16)); off += sizeof (uint16); if (tif->tif_flags & TIFF_SWAB) TIFFSwabShort(&dircount); dir = (TIFFDirEntry *)CheckMalloc(tif, dircount * sizeof (TIFFDirEntry), "to read TIFF directory"); if (dir == NULL) return (0); if (off + dircount*sizeof (TIFFDirEntry) > tif->tif_size) { TIFFError(tif->tif_name, "Can not read TIFF directory"); goto bad; } else _TIFFmemcpy(dir, tif->tif_base + off, dircount*sizeof (TIFFDirEntry)); off += dircount* sizeof (TIFFDirEntry); if (off + sizeof (uint32) <= tif->tif_size) _TIFFmemcpy(&nextdiroff, tif->tif_base+off, sizeof (uint32)); } if (tif->tif_flags & TIFF_SWAB) TIFFSwabLong(&nextdiroff); tif->tif_nextdiroff = nextdiroff; tif->tif_flags &= ~TIFF_BEENWRITING; /* reset before new dir */ /* * Setup default value and then make a pass over * the fields to check type and tag information, * and to extract info required to size data * structures. A second pass is made afterwards * to read in everthing not taken in the first pass. */ td = &tif->tif_dir; /* free any old stuff and reinit */ TIFFFreeDirectory(tif); TIFFDefaultDirectory(tif); /* * Electronic Arts writes gray-scale TIFF files * without a PlanarConfiguration directory entry. * Thus we setup a default value here, even though * the TIFF spec says there is no default value. */ TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); /* * Sigh, we must make a separate pass through the * directory for the following reason: * * We must process the Compression tag in the first pass * in order to merge in codec-private tag definitions (otherwise * we may get complaints about unknown tags). However, the * Compression tag may be dependent on the SamplesPerPixel * tag value because older TIFF specs permited Compression * to be written as a SamplesPerPixel-count tag entry. * Thus if we don't first figure out the correct SamplesPerPixel * tag value then we may end up ignoring the Compression tag * value because it has an incorrect count value (if the * true value of SamplesPerPixel is not 1). * * It sure would have been nice if Aldus had really thought * this stuff through carefully. */ for (dp = dir, n = dircount; n > 0; n--, dp++) { if (tif->tif_flags & TIFF_SWAB) { TIFFSwabArrayOfShort(&dp->tdir_tag, 2); TIFFSwabArrayOfLong(&dp->tdir_count, 2); } if (dp->tdir_tag == TIFFTAG_SAMPLESPERPIXEL) { if (!TIFFFetchNormalTag(tif, dp)) goto bad; dp->tdir_tag = IGNORE; } } /* * First real pass over the directory. */ fix = 0; for (dp = dir, n = dircount; n > 0; n--, dp++) { /* * Find the field information entry for this tag. * Added check for tags to ignore ... [BFC] */ if( TIFFReassignTagToIgnore(TIS_EXTRACT, dp->tdir_tag) ) dp->tdir_tag = IGNORE; if (dp->tdir_tag == IGNORE) continue; /* * Silicon Beach (at least) writes unordered * directory tags (violating the spec). Handle * it here, but be obnoxious (maybe they'll fix it?). */ if (dp->tdir_tag < tif->tif_fieldinfo[fix]->field_tag) { if (!diroutoforderwarning) { TIFFWarning(tif->tif_name, "invalid TIFF directory; tags are not sorted in ascending order"); diroutoforderwarning = 1; } fix = 0; /* O(n^2) */ } while (fix < tif->tif_nfields && tif->tif_fieldinfo[fix]->field_tag < dp->tdir_tag) fix++; if (fix == tif->tif_nfields || tif->tif_fieldinfo[fix]->field_tag != dp->tdir_tag) { TIFFWarning(tif->tif_name, "unknown field with tag %d (0x%x) ignored", dp->tdir_tag, dp->tdir_tag); dp->tdir_tag = IGNORE; fix = 0; /* restart search */ continue; } /* * Null out old tags that we ignore. */ if (tif->tif_fieldinfo[fix]->field_bit == FIELD_IGNORE) { ignore: dp->tdir_tag = IGNORE; continue; } /* * Check data type. */ fip = tif->tif_fieldinfo[fix]; while (dp->tdir_type != (u_short) fip->field_type) { if (fip->field_type == TIFF_ANY) /* wildcard */ break; fip++, fix++; if (fix == tif->tif_nfields || fip->field_tag != dp->tdir_tag) { TIFFWarning(tif->tif_name, "wrong data type %d for \"%s\"; tag ignored", dp->tdir_type, fip[-1].field_name); goto ignore; } } /* * Check count if known in advance. */ if (fip->field_readcount != TIFF_VARIABLE) { uint32 expected = (fip->field_readcount == TIFF_SPP) ? (uint32) td->td_samplesperpixel : (uint32) fip->field_readcount; if (!CheckDirCount(tif, dp, expected)) goto ignore; } switch (dp->tdir_tag) { case TIFFTAG_COMPRESSION: /* * The 5.0 spec says the Compression tag has * one value, while earlier specs say it has * one value per sample. Because of this, we * accept the tag if one value is supplied. */ if (dp->tdir_count == 1) { v = TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); if (!TIFFSetField(tif, dp->tdir_tag, (int)v)) goto bad; break; } if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || !TIFFSetField(tif, dp->tdir_tag, iv)) goto bad; dp->tdir_tag = IGNORE; break; case TIFFTAG_STRIPOFFSETS: case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEOFFSETS: case TIFFTAG_TILEBYTECOUNTS: TIFFSetFieldBit(tif, fip->field_bit); break; case TIFFTAG_IMAGEWIDTH: case TIFFTAG_IMAGELENGTH: case TIFFTAG_IMAGEDEPTH: case TIFFTAG_TILELENGTH: case TIFFTAG_TILEWIDTH: case TIFFTAG_TILEDEPTH: case TIFFTAG_PLANARCONFIG: case TIFFTAG_ROWSPERSTRIP: if (!TIFFFetchNormalTag(tif, dp)) goto bad; dp->tdir_tag = IGNORE; break; case TIFFTAG_EXTRASAMPLES: (void) TIFFFetchExtraSamples(tif, dp); dp->tdir_tag = IGNORE; break; } } /* * Allocate directory structure and setup defaults. */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { MissingRequired(tif, "ImageLength"); goto bad; } if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { MissingRequired(tif, "PlanarConfiguration"); goto bad; } /* * Setup appropriate structures (by strip or by tile) */ if (!TIFFFieldSet(tif, FIELD_TILEDIMENSIONS)) { td->td_nstrips = TIFFNumberOfStrips(tif); td->td_tilewidth = td->td_imagewidth; td->td_tilelength = td->td_rowsperstrip; td->td_tiledepth = td->td_imagedepth; tif->tif_flags &= ~TIFF_ISTILED; } else { td->td_nstrips = TIFFNumberOfTiles(tif); tif->tif_flags |= TIFF_ISTILED; } td->td_stripsperimage = td->td_nstrips; if (td->td_planarconfig == PLANARCONFIG_SEPARATE) td->td_stripsperimage /= td->td_samplesperpixel; if (!TIFFFieldSet(tif, FIELD_STRIPOFFSETS)) { MissingRequired(tif, isTiled(tif) ? "TileOffsets" : "StripOffsets"); goto bad; } /* * Second pass: extract other information. */ for (dp = dir, n = dircount; n > 0; n--, dp++) { if (dp->tdir_tag == IGNORE) continue; switch (dp->tdir_tag) { case TIFFTAG_MINSAMPLEVALUE: case TIFFTAG_MAXSAMPLEVALUE: case TIFFTAG_BITSPERSAMPLE: /* * The 5.0 spec says the Compression tag has * one value, while earlier specs say it has * one value per sample. Because of this, we * accept the tag if one value is supplied. * * The MinSampleValue, MaxSampleValue and * BitsPerSample tags are supposed to be written * as one value/sample, but some vendors incorrectly * write one value only -- so we accept that * as well (yech). */ if (dp->tdir_count == 1) { v = TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset); if (!TIFFSetField(tif, dp->tdir_tag, (int)v)) goto bad; break; } /* fall thru... */ case TIFFTAG_DATATYPE: case TIFFTAG_SAMPLEFORMAT: if (!TIFFFetchPerSampleShorts(tif, dp, &iv) || !TIFFSetField(tif, dp->tdir_tag, iv)) goto bad; break; case TIFFTAG_SMINSAMPLEVALUE: case TIFFTAG_SMAXSAMPLEVALUE: if (!TIFFFetchPerSampleAnys(tif, dp, &dv) || !TIFFSetField(tif, dp->tdir_tag, dv)) goto bad; break; case TIFFTAG_STRIPOFFSETS: case TIFFTAG_TILEOFFSETS: if (!TIFFFetchStripThing(tif, dp, td->td_nstrips, &td->td_stripoffset)) goto bad; break; case TIFFTAG_STRIPBYTECOUNTS: case TIFFTAG_TILEBYTECOUNTS: if (!TIFFFetchStripThing(tif, dp, td->td_nstrips, &td->td_stripbytecount)) goto bad; break; case TIFFTAG_COLORMAP: case TIFFTAG_TRANSFERFUNCTION: /* * TransferFunction can have either 1x or 3x data * values; Colormap can have only 3x items. */ v = 1L<<td->td_bitspersample; if (dp->tdir_tag == TIFFTAG_COLORMAP || dp->tdir_count != (uint32) v) { if (!CheckDirCount(tif, dp, (uint32)(3*v))) break; } v *= sizeof (uint16); cp = CheckMalloc(tif, dp->tdir_count * sizeof (uint16), "to read \"TransferFunction\" tag"); if (cp != NULL) { if (TIFFFetchData(tif, dp, cp)) { /* * This deals with there being only * one array to apply to all samples. */ uint32 c = (uint32)1 << td->td_bitspersample; if (dp->tdir_count == c) v = 0; TIFFSetField(tif, dp->tdir_tag, cp, cp+v, cp+2*v); } _TIFFfree(cp); } break; case TIFFTAG_PAGENUMBER: case TIFFTAG_HALFTONEHINTS: case TIFFTAG_YCBCRSUBSAMPLING: case TIFFTAG_DOTRANGE: (void) TIFFFetchShortPair(tif, dp); break; #ifdef COLORIMETRY_SUPPORT case TIFFTAG_REFERENCEBLACKWHITE: (void) TIFFFetchRefBlackWhite(tif, dp); break; #endif /* BEGIN REV 4.0 COMPATIBILITY */ case TIFFTAG_OSUBFILETYPE: v = 0; switch (TIFFExtractData(tif, dp->tdir_type, dp->tdir_offset)) { case OFILETYPE_REDUCEDIMAGE: v = FILETYPE_REDUCEDIMAGE; break; case OFILETYPE_PAGE: v = FILETYPE_PAGE; break; } if (v) (void) TIFFSetField(tif, TIFFTAG_SUBFILETYPE, (int)v); break; /* END REV 4.0 COMPATIBILITY */ default: (void) TIFFFetchNormalTag(tif, dp); break; } } /* * Verify Palette image has a Colormap. */ if (td->td_photometric == PHOTOMETRIC_PALETTE && !TIFFFieldSet(tif, FIELD_COLORMAP)) { MissingRequired(tif, "Colormap"); goto bad; } /* * Attempt to deal with a missing StripByteCounts tag. */ if (!TIFFFieldSet(tif, FIELD_STRIPBYTECOUNTS)) { /* * Some manufacturers violate the spec by not giving * the size of the strips. In this case, assume there * is one uncompressed strip of data. */ if ((td->td_planarconfig == PLANARCONFIG_CONTIG && td->td_nstrips > 1) || (td->td_planarconfig == PLANARCONFIG_SEPARATE && td->td_nstrips != td->td_samplesperpixel)) { MissingRequired(tif, "StripByteCounts"); goto bad; } TIFFWarning(tif->tif_name, "TIFF directory is missing required \"%s\" field, calculating from imagelength", _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); EstimateStripByteCounts(tif, dir, dircount); #define BYTECOUNTLOOKSBAD \ ((td->td_stripbytecount[0] == 0 && td->td_stripoffset[0] != 0) || \ (td->td_compression == COMPRESSION_NONE && \ td->td_stripbytecount[0] > TIFFGetFileSize(tif) - td->td_stripoffset[0])) } else if (td->td_nstrips == 1 && BYTECOUNTLOOKSBAD) { /* * Plexus (and others) sometimes give a value * of zero for a tag when they don't know what * the correct value is! Try and handle the * simple case of estimating the size of a one * strip image. */ TIFFWarning(tif->tif_name, "Bogus \"%s\" field, ignoring and calculating from imagelength", _TIFFFieldWithTag(tif,TIFFTAG_STRIPBYTECOUNTS)->field_name); EstimateStripByteCounts(tif, dir, dircount); } if (dir) _TIFFfree((char *)dir); if (!TIFFFieldSet(tif, FIELD_MAXSAMPLEVALUE)) td->td_maxsamplevalue = (uint16)((1L<<td->td_bitspersample)-1); /* * Setup default compression scheme. */ if (!TIFFFieldSet(tif, FIELD_COMPRESSION)) TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE); /* * Some manufacturers make life difficult by writing * large amounts of uncompressed data as a single strip. * This is contrary to the recommendations of the spec. * The following makes an attempt at breaking such images * into strips closer to the recommended 8k bytes. A * side effect, however, is that the RowsPerStrip tag * value may be changed. */ if (td->td_nstrips == 1 && td->td_compression == COMPRESSION_NONE && (tif->tif_flags & (TIFF_STRIPCHOP|TIFF_ISTILED)) == TIFF_STRIPCHOP) ChopUpSingleUncompressedStrip(tif); /* * Reinitialize i/o since we are starting on a new directory. */ tif->tif_row = (uint32) -1; tif->tif_curstrip = (tstrip_t) -1; tif->tif_col = (uint32) -1; tif->tif_curtile = (ttile_t) -1; tif->tif_tilesize = TIFFTileSize(tif); tif->tif_scanlinesize = TIFFScanlineSize(tif); return (1); bad: if (dir) _TIFFfree(dir); return (0); }
int main(int argc, char **argv) { TIFF *tif; static const char *srcfilerel = "images/quad-tile.jpg.tiff"; char *srcdir = NULL; char srcfile[1024]; unsigned short h, v; int status; unsigned char *buffer; uint32 *rgba_buffer; tsize_t sz, szout; unsigned int pixel_status = 0; (void) argc; (void) argv; if ((srcdir = getenv("srcdir")) == NULL) { srcdir = "."; } printf("XXXXXXXX %s",srcdir); if ((strlen(srcdir) + 1 + strlen(srcfilerel)) >= sizeof(srcfile)) { fprintf( stderr, "srcdir too long %s\n", srcdir); exit( 1 ); } strcpy(srcfile,srcdir); strcat(srcfile,"/"); strcat(srcfile,srcfilerel); tif = TIFFOpen(srcfile,"r"); if ( tif == NULL ) { fprintf( stderr, "Could not open %s\n", srcfile); exit( 1 ); } status = TIFFGetField(tif,TIFFTAG_YCBCRSUBSAMPLING, &h, &v); if ( status == 0 || h != 2 || v != 2) { fprintf( stderr, "Could not retrieve subsampling tag.\n" ); exit(1); } /* * What is the appropriate size of a YCbCr encoded tile? */ sz = TIFFTileSize(tif); if( sz != 24576) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *) malloc(sz); /* * Read a tile in decompressed form, but still YCbCr subsampled. */ szout = TIFFReadEncodedTile(tif,9,buffer,sz); if (szout != sz) { fprintf( stderr, "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n", (int) szout, (int) sz ); return 1; } if( check_cluster( 0, buffer, cluster_0 ) || check_cluster( 64, buffer, cluster_64 ) || check_cluster( 128, buffer, cluster_128 ) ) { exit(1); } free(buffer); /* * Read a tile using the built-in conversion to RGB format provided by the JPEG library. */ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); sz = TIFFTileSize(tif); if( sz != 128*128*3) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *) malloc(sz); szout = TIFFReadEncodedTile(tif,9,buffer,sz); if (szout != sz) { fprintf( stderr, "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n", (int) szout, (int) sz ); return 1; } /* * JPEG decoding is inherently inexact, so we can't test for exact * pixel values. (Well, if we knew exactly which libjpeg version * we were using, and with what settings, we could expect specific * values ... but it's not worth the trouble to keep track of.) * Hence, use ranges of expected values. The ranges may need to be * widened over time as more versions of libjpeg appear. */ pixel_status |= check_rgb_pixel( 0, 15, 18, 0, 0, 18, 41, buffer ); pixel_status |= check_rgb_pixel( 64, 0, 0, 0, 0, 0, 2, buffer ); pixel_status |= check_rgb_pixel( 512, 5, 6, 34, 36, 182, 196, buffer ); free( buffer ); TIFFClose(tif); /* * Reopen and test reading using the RGBA interface. */ tif = TIFFOpen(srcfile,"r"); sz = 128 * 128 * sizeof(uint32); rgba_buffer = (uint32 *) malloc(sz); if (!TIFFReadRGBATile( tif, 1*128, 2*128, rgba_buffer )) { fprintf( stderr, "TIFFReadRGBATile() returned failure code.\n" ); return 1; } /* * Currently TIFFReadRGBATile() just uses JPEGCOLORMODE_RGB so this * trivally matches the last results. Eventually we should actually * accomplish it from the YCbCr subsampled buffer ourselves in which * case the results may be subtly different but similar. */ pixel_status |= check_rgba_pixel( 0, 15, 18, 0, 0, 18, 41, 255, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 64, 0, 0, 0, 0, 0, 2, 255, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 512, 5, 6, 34, 36, 182, 196, 255, 255, rgba_buffer ); free( rgba_buffer ); TIFFClose(tif); if (pixel_status) { exit(1); } exit( 0 ); }
TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset ) { TIFFOvrCache *psCache; uint32 nBaseDirOffset; psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache)); psCache->nDirOffset = nDirOffset; psCache->hTIFF = hTIFF; /* -------------------------------------------------------------------- */ /* Get definition of this raster from the TIFF file itself. */ /* -------------------------------------------------------------------- */ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); TIFFSetSubDirectory( hTIFF, nDirOffset ); TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) ); TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) ); TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) ); TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) ); TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(psCache->nPlanarConfig) ); if( !TIFFIsTiled( hTIFF ) ) { TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) ); psCache->nBlockXSize = psCache->nXSize; psCache->nBytesPerBlock = TIFFStripSize(hTIFF); psCache->bTiled = FALSE; } else { TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) ); TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) ); psCache->nBytesPerBlock = TIFFTileSize(hTIFF); psCache->bTiled = TRUE; } /* -------------------------------------------------------------------- */ /* Compute some values from this. */ /* -------------------------------------------------------------------- */ psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1) / psCache->nBlockXSize; psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1) / psCache->nBlockYSize; if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) psCache->nBytesPerRow = psCache->nBytesPerBlock * psCache->nBlocksPerRow * psCache->nSamples; else psCache->nBytesPerRow = psCache->nBytesPerBlock * psCache->nBlocksPerRow; /* -------------------------------------------------------------------- */ /* Allocate and initialize the data buffers. */ /* -------------------------------------------------------------------- */ psCache->pabyRow1Blocks = (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); psCache->pabyRow2Blocks = (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); if( psCache->pabyRow1Blocks == NULL || psCache->pabyRow2Blocks == NULL ) { TIFFErrorExt( hTIFF->tif_clientdata, hTIFF->tif_name, "Can't allocate memory for overview cache." ); /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ return NULL; } _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow ); _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow ); psCache->nBlockOffset = 0; TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); return psCache; }
/* * Get an tile-organized image that has * SamplesPerPixel > 1 * PlanarConfiguration separated * We assume that all such images are RGB. */ static int gtTileSeparate(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) { TIFF* tif = img->tif; tileSeparateRoutine put = img->put.separate; uint16 orientation; uint32 col, row, y; uint32 tw, th; u_char* buf; u_char* r; u_char* g; u_char* b; u_char* a; tsize_t tilesize; int32 fromskew, toskew; int alpha = img->alpha; uint32 nrow; tilesize = TIFFTileSize(tif); buf = (u_char*) _TIFFmalloc(4*tilesize); if (buf == 0) { TIFFError(TIFFFileName(tif), "No space for tile buffer"); return (0); } r = buf; g = r + tilesize; b = g + tilesize; a = b + tilesize; if (!alpha) memset(a, 0xff, tilesize); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(tif, TIFFTAG_TILELENGTH, &th); y = setorientation(img, h); orientation = img->orientation; toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? tw+w : tw-w); for (row = 0; row < h; row += th) { nrow = (row + th > h ? h - row : th); for (col = 0; col < w; col += tw) { if (TIFFReadTile(tif, r, col, row,0,0) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, g, col, row,0,1) < 0 && img->stoponerr) break; if (TIFFReadTile(tif, b, col, row,0,2) < 0 && img->stoponerr) break; if (alpha && TIFFReadTile(tif,a,col,row,0,3) < 0 && img->stoponerr) break; if (col + tw > w) { /* * Tile is clipped horizontally. Calculate * visible portion and skewing factors. */ uint32 npix = w - col; fromskew = tw - npix; (*put)(img, raster+y*w+col, col, y, npix, nrow, fromskew, toskew + fromskew, r, g, b, a); } else { (*put)(img, raster+y*w+col, col, y, tw, nrow, 0, toskew, r, g, b, a); } } y += (orientation == ORIENTATION_TOPLEFT ? -(int32) nrow : (int32) nrow); } _TIFFfree(buf); return (1); }
/* Copy a TIFF file ... we know we wrote it, so just copy the tags we know * we might have set. */ static int write_copy_tiff( Write *write, TIFF *out, TIFF *in ) { uint32 i32; uint16 i16; float f; tdata_t buf; ttile_t tile; ttile_t n; /* All the fields we might have set. */ CopyField( TIFFTAG_IMAGEWIDTH, i32 ); CopyField( TIFFTAG_IMAGELENGTH, i32 ); CopyField( TIFFTAG_PLANARCONFIG, i16 ); CopyField( TIFFTAG_ORIENTATION, i16 ); CopyField( TIFFTAG_XRESOLUTION, f ); CopyField( TIFFTAG_YRESOLUTION, f ); CopyField( TIFFTAG_RESOLUTIONUNIT, i16 ); CopyField( TIFFTAG_COMPRESSION, i16 ); CopyField( TIFFTAG_SAMPLESPERPIXEL, i16 ); CopyField( TIFFTAG_BITSPERSAMPLE, i16 ); CopyField( TIFFTAG_PHOTOMETRIC, i16 ); CopyField( TIFFTAG_ORIENTATION, i16 ); CopyField( TIFFTAG_TILEWIDTH, i32 ); CopyField( TIFFTAG_TILELENGTH, i32 ); CopyField( TIFFTAG_ROWSPERSTRIP, i32 ); CopyField( TIFFTAG_SUBFILETYPE, i32 ); if( write->predictor != VIPS_FOREIGN_TIFF_PREDICTOR_NONE ) TIFFSetField( out, TIFFTAG_PREDICTOR, write->predictor ); /* TIFFTAG_JPEGQUALITY is a pesudo-tag, so we can't copy it. * Set explicitly from Write. */ if( write->compression == COMPRESSION_JPEG ) { TIFFSetField( out, TIFFTAG_JPEGQUALITY, write->jpqual ); /* Only for three-band, 8-bit images. */ if( write->im->Bands == 3 && write->im->BandFmt == VIPS_FORMAT_UCHAR ) { /* Enable rgb->ycbcr conversion in the jpeg write. */ if( !write->rgbjpeg && write->jpqual < 90 ) TIFFSetField( out, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); /* And we want ycbcr expanded to rgb on read. Otherwise * TIFFTileSize() will give us the size of a chrominance * subsampled tile. */ TIFFSetField( in, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB ); } } /* We can't copy profiles or xmp :( Set again from Write. */ if( !write->strip ) if( write_embed_profile( write, out ) || write_embed_xmp( write, out ) || write_embed_ipct( write, out ) || write_embed_photoshop( write, out ) || write_embed_imagedescription( write, out ) ) return( -1 ); buf = vips_malloc( NULL, TIFFTileSize( in ) ); n = TIFFNumberOfTiles( in ); for( tile = 0; tile < n; tile++ ) { tsize_t len; /* It'd be good to use TIFFReadRawTile()/TIFFWriteRawTile() * here to save compression/decompression, but sadly it seems * not to work :-( investigate at some point. */ len = TIFFReadEncodedTile( in, tile, buf, -1 ); if( len < 0 || TIFFWriteEncodedTile( out, tile, buf, len ) < 0 ) { vips_free( buf ); return( -1 ); } } vips_free( buf ); return( 0 ); }
/* Make and init a Write. */ static Write * write_new( VipsImage *im, const char *filename, VipsForeignTiffCompression compression, int Q, VipsForeignTiffPredictor predictor, char *profile, gboolean tile, int tile_width, int tile_height, gboolean pyramid, gboolean squash, gboolean miniswhite, VipsForeignTiffResunit resunit, double xres, double yres, gboolean bigtiff, gboolean rgbjpeg, gboolean properties, gboolean strip ) { Write *write; if( !(write = VIPS_NEW( im, Write )) ) return( NULL ); write->im = im; write->filename = vips_strdup( VIPS_OBJECT( im ), filename ); write->layer = NULL; write->tbuf = NULL; write->compression = get_compression( compression ); write->jpqual = Q; write->predictor = predictor; write->tile = tile; write->tilew = tile_width; write->tileh = tile_height; write->pyramid = pyramid; write->onebit = squash; write->miniswhite = miniswhite; write->icc_profile = vips_strdup( NULL, profile ); write->bigtiff = bigtiff; write->rgbjpeg = rgbjpeg; write->properties = properties; write->strip = strip; write->resunit = get_resunit( resunit ); write->xres = xres; write->yres = yres; /* In strip mode we use tileh to set rowsperstrip, and that does not * have the multiple-of-16 restriction. */ if( tile ) { if( (write->tilew & 0xf) != 0 || (write->tileh & 0xf) != 0 ) { vips_error( "vips2tiff", "%s", _( "tile size not a multiple of 16" ) ); return( NULL ); } } /* We can only pyramid LABQ and non-complex images. */ if( write->pyramid ) { if( im->Coding == VIPS_CODING_NONE && vips_band_format_iscomplex( im->BandFmt ) ) { vips_error( "vips2tiff", "%s", _( "can only pyramid LABQ and " "non-complex images" ) ); return( NULL ); } } /* Only 1-bit-ize 8 bit mono images. */ if( write->onebit && (im->Coding != VIPS_CODING_NONE || im->BandFmt != VIPS_FORMAT_UCHAR || im->Bands != 1) ) { vips_warn( "vips2tiff", "%s", _( "can only squash 1 band uchar images -- " "disabling squash" ) ); write->onebit = 0; } if( write->onebit && write->compression == COMPRESSION_JPEG ) { vips_warn( "vips2tiff", "%s", _( "can't have 1-bit JPEG -- disabling JPEG" ) ); write->compression = COMPRESSION_NONE; } /* We can only MINISWHITE non-complex images of 1 or 2 bands. */ if( write->miniswhite && (im->Coding != VIPS_CODING_NONE || vips_band_format_iscomplex( im->BandFmt ) || im->Bands > 2) ) { vips_warn( "vips2tiff", "%s", _( "can only save non-complex greyscale images " "as miniswhite -- disabling miniswhite" ) ); write->miniswhite = FALSE; } /* Sizeof a line of bytes in the TIFF tile. */ if( im->Coding == VIPS_CODING_LABQ ) write->tls = write->tilew * 3; else if( write->onebit ) write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8; else write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew; /* Build the pyramid framework. */ write->layer = pyramid_new( write, NULL, im->Xsize, im->Ysize ); /* Fill all the layers. */ if( pyramid_fill( write ) ) { write_free( write ); return( NULL ); } if( tile ) write->tbuf = vips_malloc( NULL, TIFFTileSize( write->layer->tif ) ); else write->tbuf = vips_malloc( NULL, TIFFScanlineSize( write->layer->tif ) ); if( !write->tbuf ) { write_free( write ); return( NULL ); } return( write ); }
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 */ }
int main(int argc, char **argv) { TIFF *tif; static const char *srcfilerel = "images/quad-tile.jpg.tiff"; char *srcdir = NULL; char srcfile[1024]; unsigned short h, v; int status; unsigned char *buffer; uint32 *rgba_buffer; tsize_t sz, szout; unsigned int pixel_status = 0; (void) argc; (void) argv; if ((srcdir = getenv("srcdir")) == NULL) { srcdir = "."; } if ((strlen(srcdir) + 1 + strlen(srcfilerel)) >= sizeof(srcfile)) { fprintf( stderr, "srcdir too long %s\n", srcdir); exit( 1 ); } strcpy(srcfile,srcdir); strcat(srcfile,"/"); strcat(srcfile,srcfilerel); tif = TIFFOpen(srcfile,"r"); if ( tif == NULL ) { fprintf( stderr, "Could not open %s\n", srcfile); exit( 1 ); } status = TIFFGetField(tif,TIFFTAG_YCBCRSUBSAMPLING, &h, &v); if ( status == 0 || h != 2 || v != 2) { fprintf( stderr, "Could not retrieve subsampling tag.\n" ); exit(1); } /* * What is the appropriate size of a YCbCr encoded tile? */ sz = TIFFTileSize(tif); if( sz != 24576) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *) malloc(sz); /* * Read a tile in decompressed form, but still YCbCr subsampled. */ szout = TIFFReadEncodedTile(tif,9,buffer,sz); if (szout != sz) { fprintf( stderr, "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n", (int) szout, (int) sz ); return 1; } if( check_cluster( 0, buffer, cluster_0 ) || check_cluster( 64, buffer, cluster_64 ) || check_cluster( 128, buffer, cluster_128 ) ) { exit(1); } free(buffer); /* * Read a tile using the built-in conversion to RGB format provided by the JPEG library. */ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); sz = TIFFTileSize(tif); if( sz != 128*128*3) { fprintf(stderr, "tiles are %d bytes\n", (int)sz); exit(1); } buffer = (unsigned char *) malloc(sz); szout = TIFFReadEncodedTile(tif,9,buffer,sz); if (szout != sz) { fprintf( stderr, "Did not get expected result code from TIFFReadEncodedTile()(%d instead of %d)\n", (int) szout, (int) sz ); return 1; } #if JPEG_LIB_VERSION >= 70 pixel_status |= check_rgb_pixel( 0, 18, 0, 41, buffer ); pixel_status |= check_rgb_pixel( 64, 0, 0, 0, buffer ); pixel_status |= check_rgb_pixel( 512, 5, 34, 196, buffer ); #else pixel_status |= check_rgb_pixel( 0, 15, 0, 18, buffer ); pixel_status |= check_rgb_pixel( 64, 0, 0, 2, buffer ); pixel_status |= check_rgb_pixel( 512, 6, 36, 182, buffer ); #endif free( buffer ); TIFFClose(tif); /* * Reopen and test reading using the RGBA interface. */ tif = TIFFOpen(srcfile,"r"); sz = 128 * 128 * sizeof(uint32); rgba_buffer = (uint32 *) malloc(sz); if (!TIFFReadRGBATile( tif, 1*128, 2*128, rgba_buffer )) { fprintf( stderr, "TIFFReadRGBATile() returned failure code.\n" ); return 1; } /* * Currently TIFFReadRGBATile() just uses JPEGCOLORMODE_RGB so this * trivally matches the last results. Eventually we should actually * accomplish it from the YCbCr subsampled buffer ourselves in which * case the results may be subtly different but similar. */ #if JPEG_LIB_VERSION >= 70 pixel_status |= check_rgba_pixel( 0, 18, 0, 41, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 64, 0, 0, 0, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 512, 5, 34, 196, 255, rgba_buffer ); #else pixel_status |= check_rgba_pixel( 0, 15, 0, 18, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 64, 0, 0, 2, 255, rgba_buffer ); pixel_status |= check_rgba_pixel( 512, 6, 36, 182, 255, rgba_buffer ); #endif free( rgba_buffer ); TIFFClose(tif); if (pixel_status) { exit(1); } exit( 0 ); }
/* * Verify file is writable and that the directory * information is setup properly. In doing the latter * we also "freeze" the state of the directory so * that important information is not changed. */ int TIFFWriteCheck(TIFF* tif, int tiles, const char* module) { if (tif->tif_mode == O_RDONLY) { TIFFError(module, "%s: File not open for writing", tif->tif_name); return (0); } if (tiles ^ isTiled(tif)) { TIFFError(tif->tif_name, tiles ? "Can not write tiles to a stripped image" : "Can not write scanlines to a tiled image"); return (0); } /* * While we allow compressed TIFF files to be opened in update mode, * we don't allow writing any image blocks in an existing compressed * image. Eventually we could do so, by moving blocks that grow * to the end of the file, but we don't for now. */ if (tif->tif_dir.td_stripoffset != NULL && tif->tif_dir.td_compression != COMPRESSION_NONE ) { TIFFError( module, "%s:\n" "In place update to compressed TIFF images not " "supported.", tif->tif_name ); return (0); } /* * On the first write verify all the required information * has been setup and initialize any data structures that * had to wait until directory information was set. * Note that a lot of our work is assumed to remain valid * because we disallow any of the important parameters * from changing after we start writing (i.e. once * TIFF_BEENWRITING is set, TIFFSetField will only allow * the image's length to be changed). */ if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { TIFFError(module, "%s: Must set \"ImageWidth\" before writing data", tif->tif_name); return (0); } if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { TIFFError(module, "%s: Must set \"PlanarConfiguration\" before writing data", tif->tif_name); return (0); } if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { tif->tif_dir.td_nstrips = 0; TIFFError(module, "%s: No space for %s arrays", tif->tif_name, isTiled(tif) ? "tile" : "strip"); return (0); } tif->tif_tilesize = TIFFTileSize(tif); tif->tif_scanlinesize = TIFFScanlineSize(tif); tif->tif_flags |= TIFF_BEENWRITING; return (1); }