1 /******************************************************************************
2 * $Id: tif_ovrcache.c,v 1.11 2015-05-29 03:08:19 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
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
TIFFCreateOvrCache(TIFF * hTIFF,toff_t nDirOffset)43 TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, toff_t nDirOffset )
44
45 {
46 TIFFOvrCache *psCache;
47 toff_t 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 if (psCache->pabyRow1Blocks) _TIFFfree(psCache->pabyRow1Blocks);
114 if (psCache->pabyRow2Blocks) _TIFFfree(psCache->pabyRow2Blocks);
115 _TIFFfree( psCache );
116 return NULL;
117 }
118
119 _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow );
120 _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow );
121
122 psCache->nBlockOffset = 0;
123
124 TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
125
126 return psCache;
127 }
128
129 /************************************************************************/
130 /* TIFFWriteOvrRow() */
131 /* */
132 /* Write one entire row of blocks (row 1) to the tiff file, and */
133 /* then rotate the block buffers, essentially moving things */
134 /* down by one block. */
135 /************************************************************************/
136
TIFFWriteOvrRow(TIFFOvrCache * psCache)137 static void TIFFWriteOvrRow( TIFFOvrCache * psCache )
138
139 {
140 int nRet, iTileX, iTileY = psCache->nBlockOffset;
141 unsigned char *pabyData;
142 toff_t nBaseDirOffset;
143 uint32 RowsInStrip;
144
145 /* -------------------------------------------------------------------- */
146 /* If the output cache is multi-byte per sample, and the file */
147 /* being written to is of a different byte order than the current */
148 /* platform, we will need to byte swap the data. */
149 /* -------------------------------------------------------------------- */
150 if( TIFFIsByteSwapped(psCache->hTIFF) )
151 {
152 if( psCache->nBitsPerPixel == 16 )
153 TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks,
154 (psCache->nBytesPerBlock * psCache->nSamples) / 2 );
155
156 else if( psCache->nBitsPerPixel == 32 )
157 TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks,
158 (psCache->nBytesPerBlock * psCache->nSamples) / 4 );
159
160 else if( psCache->nBitsPerPixel == 64 )
161 TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks,
162 (psCache->nBytesPerBlock * psCache->nSamples) / 8 );
163 }
164
165 /* -------------------------------------------------------------------- */
166 /* Record original directory position, so we can restore it at */
167 /* end. */
168 /* -------------------------------------------------------------------- */
169 nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
170 nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset );
171 assert( nRet == 1 );
172
173 /* -------------------------------------------------------------------- */
174 /* Write blocks to TIFF file. */
175 /* -------------------------------------------------------------------- */
176 for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ )
177 {
178 int nTileID;
179
180 if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
181 {
182 int iSample;
183
184 for( iSample = 0; iSample < psCache->nSamples; iSample++ )
185 {
186 pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample );
187
188 if( psCache->bTiled )
189 {
190 nTileID = TIFFComputeTile( psCache->hTIFF,
191 iTileX * psCache->nBlockXSize,
192 iTileY * psCache->nBlockYSize,
193 0, (tsample_t) iSample );
194 TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
195 pabyData,
196 TIFFTileSize(psCache->hTIFF) );
197 }
198 else
199 {
200 nTileID = TIFFComputeStrip( psCache->hTIFF,
201 iTileY * psCache->nBlockYSize,
202 (tsample_t) iSample );
203 RowsInStrip=psCache->nBlockYSize;
204 if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
205 RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
206 TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
207 pabyData,
208 TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
209 }
210 }
211
212 }
213 else
214 {
215 pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, 0 );
216
217 if( psCache->bTiled )
218 {
219 nTileID = TIFFComputeTile( psCache->hTIFF,
220 iTileX * psCache->nBlockXSize,
221 iTileY * psCache->nBlockYSize,
222 0, 0 );
223 TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
224 pabyData,
225 TIFFTileSize(psCache->hTIFF) );
226 }
227 else
228 {
229 nTileID = TIFFComputeStrip( psCache->hTIFF,
230 iTileY * psCache->nBlockYSize,
231 0 );
232 RowsInStrip=psCache->nBlockYSize;
233 if ((iTileY+1)*psCache->nBlockYSize>psCache->nYSize)
234 RowsInStrip=psCache->nYSize-iTileY*psCache->nBlockYSize;
235 TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
236 pabyData,
237 TIFFVStripSize(psCache->hTIFF,RowsInStrip) );
238 }
239 }
240 }
241 /* TODO: add checks on error status return of TIFFWriteEncodedTile and TIFFWriteEncodedStrip */
242
243 /* -------------------------------------------------------------------- */
244 /* Rotate buffers. */
245 /* -------------------------------------------------------------------- */
246 pabyData = psCache->pabyRow1Blocks;
247 psCache->pabyRow1Blocks = psCache->pabyRow2Blocks;
248 psCache->pabyRow2Blocks = pabyData;
249
250 _TIFFmemset( pabyData, 0, psCache->nBytesPerRow );
251
252 psCache->nBlockOffset++;
253
254 /* -------------------------------------------------------------------- */
255 /* Restore access to original directory. */
256 /* -------------------------------------------------------------------- */
257 TIFFFlush( psCache->hTIFF );
258 /* TODO: add checks on error status return of TIFFFlush */
259 TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
260 /* TODO: add checks on error status return of TIFFSetSubDirectory */
261 }
262
263 /************************************************************************/
264 /* TIFFGetOvrBlock() */
265 /************************************************************************/
266
267 /* TODO: make TIFF_Downsample handle iSample offset, so that we can
268 * do with a single TIFFGetOvrBlock and no longer need TIFFGetOvrBlock_Subsampled */
TIFFGetOvrBlock(TIFFOvrCache * psCache,int iTileX,int iTileY,int iSample)269 unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY,
270 int iSample )
271
272 {
273 long nRowOffset;
274
275 if ( iTileY > psCache->nBlockOffset + 1 )
276 TIFFWriteOvrRow( psCache );
277
278 assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
279 assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
280 assert( iTileY >= psCache->nBlockOffset
281 && iTileY < psCache->nBlockOffset+2 );
282 assert( iSample >= 0 && iSample < psCache->nSamples );
283
284 if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE)
285 nRowOffset = ((((toff_t) iTileX * psCache->nSamples) + iSample)
286 * psCache->nBytesPerBlock);
287 else
288 nRowOffset = iTileX * psCache->nBytesPerBlock +
289 (psCache->nBitsPerPixel + 7) / 8 * iSample;
290
291 if ( iTileY == psCache->nBlockOffset )
292 return psCache->pabyRow1Blocks + nRowOffset;
293 else
294 return psCache->pabyRow2Blocks + nRowOffset;
295 }
296
297 /************************************************************************/
298 /* TIFFGetOvrBlock_Subsampled() */
299 /************************************************************************/
300
TIFFGetOvrBlock_Subsampled(TIFFOvrCache * psCache,int iTileX,int iTileY)301 unsigned char *TIFFGetOvrBlock_Subsampled( TIFFOvrCache *psCache,
302 int iTileX, int iTileY )
303
304 {
305 int nRowOffset;
306
307 if( iTileY > psCache->nBlockOffset + 1 )
308 TIFFWriteOvrRow( psCache );
309
310 assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
311 assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
312 assert( iTileY >= psCache->nBlockOffset
313 && iTileY < psCache->nBlockOffset+2 );
314 assert( psCache->nPlanarConfig != PLANARCONFIG_SEPARATE );
315
316 nRowOffset = iTileX * psCache->nBytesPerBlock;
317
318 if( iTileY == psCache->nBlockOffset )
319 return psCache->pabyRow1Blocks + nRowOffset;
320 else
321 return psCache->pabyRow2Blocks + nRowOffset;
322 }
323
324 /************************************************************************/
325 /* TIFFDestroyOvrCache() */
326 /************************************************************************/
327
TIFFDestroyOvrCache(TIFFOvrCache * psCache)328 void TIFFDestroyOvrCache( TIFFOvrCache * psCache )
329
330 {
331 while( psCache->nBlockOffset < psCache->nBlocksPerColumn )
332 TIFFWriteOvrRow( psCache );
333
334 _TIFFfree( psCache->pabyRow1Blocks );
335 _TIFFfree( psCache->pabyRow2Blocks );
336 _TIFFfree( psCache );
337 }
338 /*
339 * Local Variables:
340 * mode: c
341 * c-basic-offset: 4
342 * fill-column: 78
343 * End:
344 */
345