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 
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         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 
TIFFWriteOvrRow(TIFFOvrCache * psCache)134 static void TIFFWriteOvrRow( TIFFOvrCache * psCache )
135 
136 {
137     int		nRet, iTileX, iTileY = psCache->nBlockOffset;
138     unsigned char *pabyData;
139     toff_t	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 */
TIFFGetOvrBlock(TIFFOvrCache * psCache,int iTileX,int iTileY,int iSample)266 unsigned 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 
TIFFGetOvrBlock_Subsampled(TIFFOvrCache * psCache,int iTileX,int iTileY)298 unsigned 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 
TIFFDestroyOvrCache(TIFFOvrCache * psCache)325 void 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