// 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); }
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; }
/* * Write and compress a tile of data. The * tile is selected by the (x,y,z,s) coordinates. */ tmsize_t TIFFWriteTile(TIFF* tif, void* buf, uint32 x, uint32 y, uint32 z, uint16 s) { if (!TIFFCheckTile(tif, x, y, z, s)) return ((tmsize_t)(-1)); /* * NB: A tile size of -1 is used instead of tif_tilesize knowing * that TIFFWriteEncodedTile will clamp this to the tile size. * This is done because the tile size may not be defined until * after the output buffer is setup in TIFFWriteBufferSetup. */ return (TIFFWriteEncodedTile(tif, TIFFComputeTile(tif, x, y, z, s), buf, (tmsize_t)(-1))); }
static int cvt_by_tile( TIFF *in, TIFF *out ) { uint32* raster; /* retrieve RGBA image */ uint32 width, height; /* image width & height */ uint32 tile_width, tile_height; uint32 row, col; uint32 *wrk_line; int ok = 1; TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height); if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width) || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) { TIFFError(TIFFFileName(in), "Source image not tiled"); return (0); } TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width ); TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height ); /* * Allocate tile buffer */ raster = (uint32*)_TIFFmalloc(tile_width * tile_height * sizeof (uint32)); if (raster == 0) { TIFFError(TIFFFileName(in), "No space for raster buffer"); return (0); } /* * Allocate a scanline buffer for swapping during the vertical * mirroring pass. */ wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32)); if (!wrk_line) { TIFFError(TIFFFileName(in), "No space for raster scanline buffer"); ok = 0; } /* * Loop over the tiles. */ for( row = 0; ok && row < height; row += tile_height ) { for( col = 0; ok && col < width; col += tile_width ) { uint32 i_row; /* Read the tile into an RGBA array */ if (!TIFFReadRGBATile(in, col, row, raster)) { ok = 0; break; } /* * For some reason the TIFFReadRGBATile() function chooses the * lower left corner as the origin. Vertically mirror scanlines. */ for( i_row = 0; i_row < tile_height / 2; i_row++ ) { uint32 *top_line, *bottom_line; top_line = raster + tile_width * i_row; bottom_line = raster + tile_width * (tile_height-i_row-1); _TIFFmemcpy(wrk_line, top_line, 4*tile_width); _TIFFmemcpy(top_line, bottom_line, 4*tile_width); _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width); } /* * Write out the result in a tile. */ if( TIFFWriteEncodedTile( out, TIFFComputeTile( out, col, row, 0, 0), raster, 4 * tile_width * tile_height ) == -1 ) { ok = 0; break; } } } _TIFFfree( raster ); _TIFFfree( wrk_line ); return ok; }
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 */ }
/* 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 ); }
static int cvt_by_tile( TIFF *in, TIFF *out ) { uint32* raster; /* retrieve RGBA image */ uint32 width, height; /* image width & height */ uint32 tile_width, tile_height; uint32 row, col; uint32 *wrk_line; tsize_t raster_size; int ok = 1; TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &height); if( !TIFFGetField(in, TIFFTAG_TILEWIDTH, &tile_width) || !TIFFGetField(in, TIFFTAG_TILELENGTH, &tile_height) ) { TIFFError(TIFFFileName(in), "Source image not tiled"); return (0); } TIFFSetField(out, TIFFTAG_TILEWIDTH, tile_width ); TIFFSetField(out, TIFFTAG_TILELENGTH, tile_height ); /* * Allocate tile buffer */ raster_size = multiply(multiply(tile_width, tile_height), sizeof (uint32)); if (!raster_size) { TIFFError(TIFFFileName(in), "Can't allocate buffer for raster of size %lux%lu", (unsigned long) tile_width, (unsigned long) tile_height); return (0); } raster = (uint32*)_TIFFmalloc(raster_size); if (raster == 0) { TIFFError(TIFFFileName(in), "No space for raster buffer"); return (0); } /* * Allocate a scanline buffer for swapping during the vertical * mirroring pass. (Request can't overflow given prior checks.) */ wrk_line = (uint32*)_TIFFmalloc(tile_width * sizeof (uint32)); if (!wrk_line) { TIFFError(TIFFFileName(in), "No space for raster scanline buffer"); ok = 0; } /* * Loop over the tiles. */ for( row = 0; ok && row < height; row += tile_height ) { for( col = 0; ok && col < width; col += tile_width ) { uint32 i_row; /* Read the tile into an RGBA array */ if (!TIFFReadRGBATile(in, col, row, raster)) { ok = 0; break; } /* * XXX: raster array has 4-byte unsigned integer type, that is why * we should rearrange it here. */ #if HOST_BIGENDIAN TIFFSwabArrayOfLong(raster, tile_width * tile_height); #endif /* * For some reason the TIFFReadRGBATile() function chooses the * lower left corner as the origin. Vertically mirror scanlines. */ for( i_row = 0; i_row < tile_height / 2; i_row++ ) { uint32 *top_line, *bottom_line; top_line = raster + tile_width * i_row; bottom_line = raster + tile_width * (tile_height-i_row-1); _TIFFmemcpy(wrk_line, top_line, 4*tile_width); _TIFFmemcpy(top_line, bottom_line, 4*tile_width); _TIFFmemcpy(bottom_line, wrk_line, 4*tile_width); } /* * Write out the result in a tile. */ if( TIFFWriteEncodedTile( out, TIFFComputeTile( out, col, row, 0, 0), raster, 4 * tile_width * tile_height ) == -1 ) { ok = 0; break; } } } _TIFFfree( raster ); _TIFFfree( wrk_line ); return ok; }
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 ); }