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