tif_ovrcache.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /******************************************************************************
  2. * $Id: tif_ovrcache.c,v 1.9 2010-06-08 18:55:15 bfriesen Exp $
  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. #include "tiffiop.h"
  32. #include "tif_ovrcache.h"
  33. #include <assert.h>
  34. /************************************************************************/
  35. /* TIFFCreateOvrCache() */
  36. /* */
  37. /* Create an overview cache to hold two rows of blocks from an */
  38. /* existing TIFF directory. */
  39. /************************************************************************/
  40. TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, toff_t nDirOffset )
  41. {
  42. TIFFOvrCache *psCache;
  43. toff_t nBaseDirOffset;
  44. psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache));
  45. psCache->nDirOffset = nDirOffset;
  46. psCache->hTIFF = hTIFF;
  47. /* -------------------------------------------------------------------- */
  48. /* Get definition of this raster from the TIFF file itself. */
  49. /* -------------------------------------------------------------------- */
  50. nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
  51. TIFFSetSubDirectory( hTIFF, nDirOffset );
  52. TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) );
  53. TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) );
  54. TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) );
  55. TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) );
  56. TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(psCache->nPlanarConfig) );
  57. if( !TIFFIsTiled( hTIFF ) )
  58. {
  59. TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) );
  60. psCache->nBlockXSize = psCache->nXSize;
  61. psCache->nBytesPerBlock = TIFFStripSize(hTIFF);
  62. psCache->bTiled = FALSE;
  63. }
  64. else
  65. {
  66. TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) );
  67. TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) );
  68. psCache->nBytesPerBlock = TIFFTileSize(hTIFF);
  69. psCache->bTiled = TRUE;
  70. }
  71. /* -------------------------------------------------------------------- */
  72. /* Compute some values from this. */
  73. /* -------------------------------------------------------------------- */
  74. psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1)
  75. / psCache->nBlockXSize;
  76. psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1)
  77. / psCache->nBlockYSize;
  78. if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
  79. psCache->nBytesPerRow = psCache->nBytesPerBlock
  80. * psCache->nBlocksPerRow * psCache->nSamples;
  81. else
  82. psCache->nBytesPerRow =
  83. psCache->nBytesPerBlock * psCache->nBlocksPerRow;
  84. /* -------------------------------------------------------------------- */
  85. /* Allocate and initialize the data buffers. */
  86. /* -------------------------------------------------------------------- */
  87. psCache->pabyRow1Blocks =
  88. (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow);
  89. psCache->pabyRow2Blocks =
  90. (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow);
  91. if( psCache->pabyRow1Blocks == NULL
  92. || psCache->pabyRow2Blocks == NULL )
  93. {
  94. TIFFErrorExt( hTIFF->tif_clientdata, hTIFF->tif_name,
  95. "Can't allocate memory for overview cache." );
  96. /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
  97. return NULL;
  98. }
  99. _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow );
  100. _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow );
  101. psCache->nBlockOffset = 0;
  102. TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
  103. return psCache;
  104. }
  105. /************************************************************************/
  106. /* TIFFWriteOvrRow() */
  107. /* */
  108. /* Write one entire row of blocks (row 1) to the tiff file, and */
  109. /* then rotate the block buffers, essentially moving things */
  110. /* down by one block. */
  111. /************************************************************************/
  112. static void TIFFWriteOvrRow( TIFFOvrCache * psCache )
  113. {
  114. int nRet, iTileX, iTileY = psCache->nBlockOffset;
  115. unsigned char *pabyData;
  116. toff_t nBaseDirOffset;
  117. uint32 RowsInStrip;
  118. /* -------------------------------------------------------------------- */
  119. /* If the output cache is multi-byte per sample, and the file */
  120. /* being written to is of a different byte order than the current */
  121. /* platform, we will need to byte swap the data. */
  122. /* -------------------------------------------------------------------- */
  123. if( TIFFIsByteSwapped(psCache->hTIFF) )
  124. {
  125. if( psCache->nBitsPerPixel == 16 )
  126. TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks,
  127. (psCache->nBytesPerBlock * psCache->nSamples) / 2 );
  128. else if( psCache->nBitsPerPixel == 32 )
  129. TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks,
  130. (psCache->nBytesPerBlock * psCache->nSamples) / 4 );
  131. else if( psCache->nBitsPerPixel == 64 )
  132. TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks,
  133. (psCache->nBytesPerBlock * psCache->nSamples) / 8 );
  134. }
  135. /* -------------------------------------------------------------------- */
  136. /* Record original directory position, so we can restore it at */
  137. /* end. */
  138. /* -------------------------------------------------------------------- */
  139. nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
  140. nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset );
  141. assert( nRet == 1 );
  142. /* -------------------------------------------------------------------- */
  143. /* Write blocks to TIFF file. */
  144. /* -------------------------------------------------------------------- */
  145. for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ )
  146. {
  147. int nTileID;
  148. if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
  149. {
  150. int iSample;
  151. for( iSample = 0; iSample < psCache->nSamples; iSample++ )
  152. {
  153. pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample );
  154. if( psCache->bTiled )
  155. {
  156. nTileID = TIFFComputeTile( psCache->hTIFF,
  157. iTileX * psCache->nBlockXSize,
  158. iTileY * psCache->nBlockYSize,
  159. 0, (tsample_t) iSample );
  160. TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
  161. pabyData,
  162. TIFFTileSize(psCache->hTIFF) );
  163. }
  164. else
  165. {
  166. nTileID = TIFFComputeStrip( psCache->hTIFF,
  167. iTileY * psCache->nBlockYSize,
  168. (tsample_t) iSample );
  169. RowsInStrip=psCache->nBlockYSize;
  170. if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
  171. RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
  172. TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
  173. pabyData,
  174. TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
  175. }
  176. }
  177. }
  178. else
  179. {
  180. pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 );
  181. if( psCache->bTiled )
  182. {
  183. nTileID = TIFFComputeTile( psCache->hTIFF,
  184. iTileX * psCache->nBlockXSize,
  185. iTileY * psCache->nBlockYSize,
  186. 0, 0 );
  187. TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
  188. pabyData,
  189. TIFFTileSize(psCache->hTIFF) );
  190. }
  191. else
  192. {
  193. nTileID = TIFFComputeStrip( psCache->hTIFF,
  194. iTileY * psCache->nBlockYSize,
  195. 0 );
  196. RowsInStrip=psCache->nBlockYSize;
  197. if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
  198. RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
  199. TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
  200. pabyData,
  201. TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
  202. }
  203. }
  204. }
  205. /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */
  206. /* -------------------------------------------------------------------- */
  207. /* Rotate buffers. */
  208. /* -------------------------------------------------------------------- */
  209. pabyData = psCache->pabyRow1Blocks;
  210. psCache->pabyRow1Blocks = psCache->pabyRow2Blocks;
  211. psCache->pabyRow2Blocks = pabyData;
  212. _TIFFmemset( pabyData, 0, psCache->nBytesPerRow );
  213. psCache->nBlockOffset++;
  214. /* -------------------------------------------------------------------- */
  215. /* Restore access to original directory. */
  216. /* -------------------------------------------------------------------- */
  217. TIFFFlush( psCache->hTIFF );
  218. /* TODO: add checks on error status return of TIFFFlush */
  219. TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
  220. /* TODO: add checks on error status return of TIFFSetSubDirectory */
  221. }
  222. /************************************************************************/
  223. /* TIFFGetOvrBlock() */
  224. /************************************************************************/
  225. /* TODO: make TIFF_Downsample handle iSample offset, so that we can
  226. * do with a single TIFFGetOvrBlock and no longer need TIFFGetOvrBlock_Subsampled */
  227. unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY,
  228. int iSample )
  229. {
  230. int nRowOffset;
  231. if( iTileY > psCache->nBlockOffset + 1 )
  232. TIFFWriteOvrRow( psCache );
  233. assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
  234. assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
  235. assert( iTileY >= psCache->nBlockOffset
  236. && iTileY < psCache->nBlockOffset+2 );
  237. assert( iSample >= 0 && iSample < psCache->nSamples );
  238. if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
  239. nRowOffset = ((iTileX * psCache->nSamples) + iSample)
  240. * psCache->nBytesPerBlock;
  241. else
  242. nRowOffset = iTileX * psCache->nBytesPerBlock +
  243. (psCache->nBitsPerPixel + 7) / 8 * iSample;
  244. if( iTileY == psCache->nBlockOffset )
  245. return psCache->pabyRow1Blocks + nRowOffset;
  246. else
  247. return psCache->pabyRow2Blocks + nRowOffset;
  248. }
  249. /************************************************************************/
  250. /* TIFFGetOvrBlock_Subsampled() */
  251. /************************************************************************/
  252. unsigned char *TIFFGetOvrBlock_Subsampled( TIFFOvrCache *psCache,
  253. int iTileX, int iTileY )
  254. {
  255. int nRowOffset;
  256. if( iTileY > psCache->nBlockOffset + 1 )
  257. TIFFWriteOvrRow( psCache );
  258. assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
  259. assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
  260. assert( iTileY >= psCache->nBlockOffset
  261. && iTileY < psCache->nBlockOffset+2 );
  262. assert( psCache->nPlanarConfig != PLANARCONFIG_SEPARATE );
  263. nRowOffset = iTileX * psCache->nBytesPerBlock;
  264. if( iTileY == psCache->nBlockOffset )
  265. return psCache->pabyRow1Blocks + nRowOffset;
  266. else
  267. return psCache->pabyRow2Blocks + nRowOffset;
  268. }
  269. /************************************************************************/
  270. /* TIFFDestroyOvrCache() */
  271. /************************************************************************/
  272. void TIFFDestroyOvrCache( TIFFOvrCache * psCache )
  273. {
  274. while( psCache->nBlockOffset < psCache->nBlocksPerColumn )
  275. TIFFWriteOvrRow( psCache );
  276. _TIFFfree( psCache->pabyRow1Blocks );
  277. _TIFFfree( psCache->pabyRow2Blocks );
  278. _TIFFfree( psCache );
  279. }
  280. /*
  281. * Local Variables:
  282. * mode: c
  283. * c-basic-offset: 8
  284. * fill-column: 78
  285. * End:
  286. */