1/****************************************************************************** 2 * $Id: tif_ovrcache.c 276 2010-06-30 12:18:30Z nijtmans $ 3 * 4 * Project: TIFF Overview Builder 5 * Purpose: Library functions to maintain two rows of tiles or two strips 6 * of data for output overviews as an output cache. 7 * Author: Frank Warmerdam, warmerdam@pobox.com 8 * 9 ****************************************************************************** 10 * Copyright (c) 2000, Frank Warmerdam 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 * DEALINGS IN THE SOFTWARE. 29 ****************************************************************************** 30 */ 31 32#include "tiffiop.h" 33#include "tif_ovrcache.h" 34#include <assert.h> 35 36/************************************************************************/ 37/* TIFFCreateOvrCache() */ 38/* */ 39/* Create an overview cache to hold two rows of blocks from an */ 40/* existing TIFF directory. */ 41/************************************************************************/ 42 43TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset ) 44 45{ 46 TIFFOvrCache *psCache; 47 uint32 nBaseDirOffset; 48 49 psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache)); 50 psCache->nDirOffset = nDirOffset; 51 psCache->hTIFF = hTIFF; 52 53/* -------------------------------------------------------------------- */ 54/* Get definition of this raster from the TIFF file itself. */ 55/* -------------------------------------------------------------------- */ 56 nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); 57 TIFFSetSubDirectory( hTIFF, nDirOffset ); 58 59 TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) ); 60 TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) ); 61 62 TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) ); 63 TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) ); 64 TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(psCache->nPlanarConfig) ); 65 66 if( !TIFFIsTiled( hTIFF ) ) 67 { 68 TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) ); 69 psCache->nBlockXSize = psCache->nXSize; 70 psCache->nBytesPerBlock = TIFFStripSize(hTIFF); 71 psCache->bTiled = FALSE; 72 } 73 else 74 { 75 TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) ); 76 TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) ); 77 psCache->nBytesPerBlock = TIFFTileSize(hTIFF); 78 psCache->bTiled = TRUE; 79 } 80 81/* -------------------------------------------------------------------- */ 82/* Compute some values from this. */ 83/* -------------------------------------------------------------------- */ 84 85 psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1) 86 / psCache->nBlockXSize; 87 psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1) 88 / psCache->nBlockYSize; 89 90 if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) 91 psCache->nBytesPerRow = psCache->nBytesPerBlock 92 * psCache->nBlocksPerRow * psCache->nSamples; 93 else 94 psCache->nBytesPerRow = 95 psCache->nBytesPerBlock * psCache->nBlocksPerRow; 96 97 98/* -------------------------------------------------------------------- */ 99/* Allocate and initialize the data buffers. */ 100/* -------------------------------------------------------------------- */ 101 102 psCache->pabyRow1Blocks = 103 (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); 104 psCache->pabyRow2Blocks = 105 (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); 106 107 if( psCache->pabyRow1Blocks == NULL 108 || psCache->pabyRow2Blocks == NULL ) 109 { 110 TIFFErrorExt( hTIFF->tif_clientdata, hTIFF->tif_name, 111 "Can't allocate memory for overview cache." ); 112 /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ 113 return NULL; 114 } 115 116 _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow ); 117 _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow ); 118 119 psCache->nBlockOffset = 0; 120 121 TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); 122 123 return psCache; 124} 125 126/************************************************************************/ 127/* TIFFWriteOvrRow() */ 128/* */ 129/* Write one entire row of blocks (row 1) to the tiff file, and */ 130/* then rotate the block buffers, essentially moving things */ 131/* down by one block. */ 132/************************************************************************/ 133 134static void TIFFWriteOvrRow( TIFFOvrCache * psCache ) 135 136{ 137 int nRet, iTileX, iTileY = psCache->nBlockOffset; 138 unsigned char *pabyData; 139 uint32 nBaseDirOffset; 140 uint32 RowsInStrip; 141 142/* -------------------------------------------------------------------- */ 143/* If the output cache is multi-byte per sample, and the file */ 144/* being written to is of a different byte order than the current */ 145/* platform, we will need to byte swap the data. */ 146/* -------------------------------------------------------------------- */ 147 if( TIFFIsByteSwapped(psCache->hTIFF) ) 148 { 149 if( psCache->nBitsPerPixel == 16 ) 150 TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks, 151 (psCache->nBytesPerBlock * psCache->nSamples) / 2 ); 152 153 else if( psCache->nBitsPerPixel == 32 ) 154 TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks, 155 (psCache->nBytesPerBlock * psCache->nSamples) / 4 ); 156 157 else if( psCache->nBitsPerPixel == 64 ) 158 TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks, 159 (psCache->nBytesPerBlock * psCache->nSamples) / 8 ); 160 } 161 162/* -------------------------------------------------------------------- */ 163/* Record original directory position, so we can restore it at */ 164/* end. */ 165/* -------------------------------------------------------------------- */ 166 nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); 167 nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset ); 168 assert( nRet == 1 ); 169 170/* -------------------------------------------------------------------- */ 171/* Write blocks to TIFF file. */ 172/* -------------------------------------------------------------------- */ 173 for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ ) 174 { 175 int nTileID; 176 177 if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) 178 { 179 int iSample; 180 181 for( iSample = 0; iSample < psCache->nSamples; iSample++ ) 182 { 183 pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample ); 184 185 if( psCache->bTiled ) 186 { 187 nTileID = TIFFComputeTile( psCache->hTIFF, 188 iTileX * psCache->nBlockXSize, 189 iTileY * psCache->nBlockYSize, 190 0, (tsample_t) iSample ); 191 TIFFWriteEncodedTile( psCache->hTIFF, nTileID, 192 pabyData, 193 TIFFTileSize(psCache->hTIFF) ); 194 } 195 else 196 { 197 nTileID = TIFFComputeStrip( psCache->hTIFF, 198 iTileY * psCache->nBlockYSize, 199 (tsample_t) iSample ); 200 RowsInStrip=psCache->nBlockYSize; 201 if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) 202 RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; 203 TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, 204 pabyData, 205 TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); 206 } 207 } 208 209 } 210 else 211 { 212 pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 ); 213 214 if( psCache->bTiled ) 215 { 216 nTileID = TIFFComputeTile( psCache->hTIFF, 217 iTileX * psCache->nBlockXSize, 218 iTileY * psCache->nBlockYSize, 219 0, 0 ); 220 TIFFWriteEncodedTile( psCache->hTIFF, nTileID, 221 pabyData, 222 TIFFTileSize(psCache->hTIFF) ); 223 } 224 else 225 { 226 nTileID = TIFFComputeStrip( psCache->hTIFF, 227 iTileY * psCache->nBlockYSize, 228 0 ); 229 RowsInStrip=psCache->nBlockYSize; 230 if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize) 231 RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize; 232 TIFFWriteEncodedStrip( psCache->hTIFF, nTileID, 233 pabyData, 234 TIFFVStripSize(psCache->hTIFF,RowsInStrip) ); 235 } 236 } 237 } 238 /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */ 239 240/* -------------------------------------------------------------------- */ 241/* Rotate buffers. */ 242/* -------------------------------------------------------------------- */ 243 pabyData = psCache->pabyRow1Blocks; 244 psCache->pabyRow1Blocks = psCache->pabyRow2Blocks; 245 psCache->pabyRow2Blocks = pabyData; 246 247 _TIFFmemset( pabyData, 0, psCache->nBytesPerRow ); 248 249 psCache->nBlockOffset++; 250 251/* -------------------------------------------------------------------- */ 252/* Restore access to original directory. */ 253/* -------------------------------------------------------------------- */ 254 TIFFFlush( psCache->hTIFF ); 255 /* TODO: add checks on error status return of TIFFFlush */ 256 TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); 257 /* TODO: add checks on error status return of TIFFSetSubDirectory */ 258} 259 260/************************************************************************/ 261/* TIFFGetOvrBlock() */ 262/************************************************************************/ 263 264/* TODO: make TIFF_Downsample handle iSample offset, so that we can 265 * do with a single TIFFGetOvrBlock and no longer need TIFFGetOvrBlock_Subsampled */ 266unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY, 267 int iSample ) 268 269{ 270 int nRowOffset; 271 272 if( iTileY > psCache->nBlockOffset + 1 ) 273 TIFFWriteOvrRow( psCache ); 274 275 assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow ); 276 assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn ); 277 assert( iTileY >= psCache->nBlockOffset 278 && iTileY < psCache->nBlockOffset+2 ); 279 assert( iSample >= 0 && iSample < psCache->nSamples ); 280 281 if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) 282 nRowOffset = ((iTileX * psCache->nSamples) + iSample) 283 * psCache->nBytesPerBlock; 284 else 285 nRowOffset = iTileX * psCache->nBytesPerBlock + 286 (psCache->nBitsPerPixel + 7) / 8 * iSample; 287 288 if( iTileY == psCache->nBlockOffset ) 289 return psCache->pabyRow1Blocks + nRowOffset; 290 else 291 return psCache->pabyRow2Blocks + nRowOffset; 292} 293 294/************************************************************************/ 295/* TIFFGetOvrBlock_Subsampled() */ 296/************************************************************************/ 297 298unsigned char *TIFFGetOvrBlock_Subsampled( TIFFOvrCache *psCache, 299 int iTileX, int iTileY ) 300 301{ 302 int nRowOffset; 303 304 if( iTileY > psCache->nBlockOffset + 1 ) 305 TIFFWriteOvrRow( psCache ); 306 307 assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow ); 308 assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn ); 309 assert( iTileY >= psCache->nBlockOffset 310 && iTileY < psCache->nBlockOffset+2 ); 311 assert( psCache->nPlanarConfig != PLANARCONFIG_SEPARATE ); 312 313 nRowOffset = iTileX * psCache->nBytesPerBlock; 314 315 if( iTileY == psCache->nBlockOffset ) 316 return psCache->pabyRow1Blocks + nRowOffset; 317 else 318 return psCache->pabyRow2Blocks + nRowOffset; 319} 320 321/************************************************************************/ 322/* TIFFDestroyOvrCache() */ 323/************************************************************************/ 324 325void TIFFDestroyOvrCache( TIFFOvrCache * psCache ) 326 327{ 328 while( psCache->nBlockOffset < psCache->nBlocksPerColumn ) 329 TIFFWriteOvrRow( psCache ); 330 331 _TIFFfree( psCache->pabyRow1Blocks ); 332 _TIFFfree( psCache->pabyRow2Blocks ); 333 _TIFFfree( psCache ); 334} 335/* 336 * Local Variables: 337 * mode: c 338 * c-basic-offset: 8 339 * fill-column: 78 340 * End: 341 */ 342