summaryrefslogtreecommitdiff
path: root/tiff/contrib/addtiffo/tif_overview.c
diff options
context:
space:
mode:
Diffstat (limited to 'tiff/contrib/addtiffo/tif_overview.c')
-rw-r--r--tiff/contrib/addtiffo/tif_overview.c896
1 files changed, 896 insertions, 0 deletions
diff --git a/tiff/contrib/addtiffo/tif_overview.c b/tiff/contrib/addtiffo/tif_overview.c
new file mode 100644
index 0000000..994451c
--- /dev/null
+++ b/tiff/contrib/addtiffo/tif_overview.c
@@ -0,0 +1,896 @@
+/******************************************************************************
+ * tif_overview.c,v 1.9 2005/05/25 09:03:16 dron Exp
+ *
+ * Project: TIFF Overview Builder
+ * Purpose: Library function for building overviews in a TIFF file.
+ * Author: Frank Warmerdam, warmerdam@pobox.com
+ *
+ * Notes:
+ * o Currently only images with bits_per_sample of a multiple of eight
+ * will work.
+ *
+ * o The downsampler currently just takes the top left pixel from the
+ * source rectangle. Eventually sampling options of averaging, mode, and
+ * ``center pixel'' should be offered.
+ *
+ * o The code will attempt to use the same kind of compression,
+ * photometric interpretation, and organization as the source image, but
+ * it doesn't copy geotiff tags to the reduced resolution images.
+ *
+ * o Reduced resolution overviews for multi-sample files will currently
+ * always be generated as PLANARCONFIG_SEPARATE. This could be fixed
+ * reasonable easily if needed to improve compatibility with other
+ * packages. Many don't properly support PLANARCONFIG_SEPARATE.
+ *
+ ******************************************************************************
+ * Copyright (c) 1999, Frank Warmerdam
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************
+ */
+
+/* TODO: update notes in header above */
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tiffio.h"
+#include "tif_ovrcache.h"
+
+#ifndef FALSE
+# define FALSE 0
+# define TRUE 1
+#endif
+
+#ifndef MAX
+# define MIN(a,b) ((a<b) ? a : b)
+# define MAX(a,b) ((a>b) ? a : b)
+#endif
+
+void TIFFBuildOverviews( TIFF *, int, int *, int, const char *,
+ int (*)(double,void*), void * );
+
+/************************************************************************/
+/* TIFF_WriteOverview() */
+/* */
+/* Create a new directory, without any image data for an overview. */
+/* Returns offset of newly created overview directory, but the */
+/* current directory is reset to be the one in used when this */
+/* function is called. */
+/************************************************************************/
+
+uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
+ int nBitsPerPixel, int nPlanarConfig, int nSamples,
+ int nBlockXSize, int nBlockYSize,
+ int bTiled, int nCompressFlag, int nPhotometric,
+ int nSampleFormat,
+ unsigned short *panRed,
+ unsigned short *panGreen,
+ unsigned short *panBlue,
+ int bUseSubIFDs,
+ int nHorSubsampling, int nVerSubsampling )
+
+{
+ uint32 nBaseDirOffset;
+ uint32 nOffset;
+
+ nBaseDirOffset = TIFFCurrentDirOffset( hTIFF );
+
+ TIFFCreateDirectory( hTIFF );
+
+/* -------------------------------------------------------------------- */
+/* Setup TIFF fields. */
+/* -------------------------------------------------------------------- */
+ TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
+ TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
+ if( nSamples == 1 )
+ TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
+ else
+ TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig );
+
+ TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel );
+ TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples );
+ TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag );
+ TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric );
+ TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
+
+ if( bTiled )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize );
+ TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize );
+ }
+ else
+ TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize );
+
+ TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, FILETYPE_REDUCEDIMAGE );
+
+ if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, nHorSubsampling, nVerSubsampling);
+ /* TODO: also write YCbCrPositioning and YCbCrCoefficients tag identical to source IFD */
+ }
+ /* TODO: add command-line parameter for selecting jpeg compression quality
+ * that gets ignored when compression isn't jpeg */
+
+/* -------------------------------------------------------------------- */
+/* Write color table if one is present. */
+/* -------------------------------------------------------------------- */
+ if( panRed != NULL )
+ {
+ TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Write directory, and return byte offset. */
+/* -------------------------------------------------------------------- */
+ if( TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" ) == 0 )
+ return 0;
+
+ TIFFWriteDirectory( hTIFF );
+ TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) );
+
+ nOffset = TIFFCurrentDirOffset( hTIFF );
+
+ TIFFSetSubDirectory( hTIFF, nBaseDirOffset );
+
+ return nOffset;
+}
+
+/************************************************************************/
+/* TIFF_GetSourceSamples() */
+/************************************************************************/
+
+static void
+TIFF_GetSourceSamples( double * padfSamples, unsigned char *pabySrc,
+ int nPixelBytes, int nSampleFormat,
+ int nXSize, int nYSize,
+ int nPixelOffset, int nLineOffset )
+{
+ int iXOff, iYOff, iSample;
+
+ iSample = 0;
+
+ for( iYOff = 0; iYOff < nYSize; iYOff++ )
+ {
+ for( iXOff = 0; iXOff < nXSize; iXOff++ )
+ {
+ unsigned char *pabyData;
+
+ pabyData = pabySrc + iYOff * nLineOffset + iXOff * nPixelOffset;
+
+ if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 )
+ {
+ padfSamples[iSample++] = *pabyData;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 )
+ {
+ padfSamples[iSample++] = ((uint16 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 )
+ {
+ padfSamples[iSample++] = ((uint32 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 )
+ {
+ padfSamples[iSample++] = ((int16 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 )
+ {
+ padfSamples[iSample++] = ((int32 *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 )
+ {
+ padfSamples[iSample++] = ((float *) pabyData)[0];
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 )
+ {
+ padfSamples[iSample++] = ((double *) pabyData)[0];
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_SetSample() */
+/************************************************************************/
+
+static void
+TIFF_SetSample( unsigned char * pabyData, int nPixelBytes, int nSampleFormat,
+ double dfValue )
+
+{
+ if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 1 )
+ {
+ *pabyData = (unsigned char) MAX(0,MIN(255,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 2 )
+ {
+ *((uint16 *)pabyData) = (uint16) MAX(0,MIN(65535,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_UINT && nPixelBytes == 4 )
+ {
+ *((uint32 *)pabyData) = (uint32) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 2 )
+ {
+ *((int16 *)pabyData) = (int16) MAX(-32768,MIN(32767,dfValue));
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_INT && nPixelBytes == 32 )
+ {
+ *((int32 *)pabyData) = (int32) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 4 )
+ {
+ *((float *)pabyData) = (float) dfValue;
+ }
+ else if( nSampleFormat == SAMPLEFORMAT_IEEEFP && nPixelBytes == 8 )
+ {
+ *((double *)pabyData) = dfValue;
+ }
+}
+
+/************************************************************************/
+/* TIFF_DownSample() */
+/* */
+/* Down sample a tile of full res data into a window of a tile */
+/* of downsampled data. */
+/************************************************************************/
+
+static
+void TIFF_DownSample( unsigned char *pabySrcTile,
+ int nBlockXSize, int nBlockYSize,
+ int nPixelSkewBits, int nBitsPerPixel,
+ unsigned char * pabyOTile,
+ int nOBlockXSize, int nOBlockYSize,
+ int nTXOff, int nTYOff, int nOMult,
+ int nSampleFormat, const char * pszResampling )
+
+{
+ int i, j, k, nPixelBytes = (nBitsPerPixel) / 8;
+ int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8;
+ unsigned char *pabySrc, *pabyDst;
+ double *padfSamples;
+
+ assert( nBitsPerPixel >= 8 );
+
+ padfSamples = (double *) malloc(sizeof(double) * nOMult * nOMult);
+
+/* ==================================================================== */
+/* Loop over scanline chunks to process, establishing where the */
+/* data is going. */
+/* ==================================================================== */
+ for( j = 0; j*nOMult < nBlockYSize; j++ )
+ {
+ if( j + nTYOff >= nOBlockYSize )
+ break;
+
+ pabyDst = pabyOTile + ((j+nTYOff)*nOBlockXSize + nTXOff)
+ * nPixelBytes * nPixelGroupBytes;
+
+/* -------------------------------------------------------------------- */
+/* Handler nearest resampling ... we don't even care about the */
+/* data type, we just do a bytewise copy. */
+/* -------------------------------------------------------------------- */
+ if( strncmp(pszResampling,"nearest",4) == 0
+ || strncmp(pszResampling,"NEAR",4) == 0 )
+ {
+ pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
+
+ for( i = 0; i*nOMult < nBlockXSize; i++ )
+ {
+ if( i + nTXOff >= nOBlockXSize )
+ break;
+
+ /*
+ * For now use simple subsampling, from the top left corner
+ * of the source block of pixels.
+ */
+
+ for( k = 0; k < nPixelBytes; k++ )
+ pabyDst[k] = pabySrc[k];
+
+ pabyDst += nPixelBytes * nPixelGroupBytes;
+ pabySrc += nOMult * nPixelGroupBytes;
+ }
+ }
+
+/* -------------------------------------------------------------------- */
+/* Handle the case of averaging. For this we also have to */
+/* handle each sample format we are concerned with. */
+/* -------------------------------------------------------------------- */
+ else if( strncmp(pszResampling,"averag",6) == 0
+ || strncmp(pszResampling,"AVERAG",6) == 0 )
+ {
+ pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
+
+ for( i = 0; i*nOMult < nBlockXSize; i++ )
+ {
+ double dfTotal;
+ int iSample;
+ int nXSize, nYSize;
+
+ if( i + nTXOff >= nOBlockXSize )
+ break;
+
+ nXSize = MIN(nOMult,nBlockXSize-i);
+ nYSize = MIN(nOMult,nBlockYSize-j);
+
+ TIFF_GetSourceSamples( padfSamples, pabySrc,
+ nPixelBytes, nSampleFormat,
+ nXSize, nYSize,
+ nPixelGroupBytes,
+ nPixelGroupBytes * nBlockXSize );
+
+ dfTotal = 0;
+ for( iSample = 0; iSample < nXSize*nYSize; iSample++ )
+ {
+ dfTotal += padfSamples[iSample];
+ }
+
+ TIFF_SetSample( pabyDst, nPixelBytes, nSampleFormat,
+ dfTotal / (nXSize*nYSize) );
+
+ pabySrc += nOMult * nPixelGroupBytes;
+ pabyDst += nPixelBytes;
+ }
+ }
+ }
+
+ free( padfSamples );
+}
+
+/************************************************************************/
+/* TIFF_DownSample_Subsampled() */
+/************************************************************************/
+static
+void TIFF_DownSample_Subsampled( unsigned char *pabySrcTile, int nSample,
+ int nBlockXSize, int nBlockYSize,
+ unsigned char * pabyOTile,
+ int nOBlockXSize, int nOBlockYSize,
+ int nTXOff, int nTYOff, int nOMult,
+ const char * pszResampling,
+ int nHorSubsampling, int nVerSubsampling )
+{
+ /* TODO: test with variety of subsampling values, and incovinient tile/strip sizes */
+ int nSampleBlockSize;
+ int nSourceSampleRowSize;
+ int nDestSampleRowSize;
+ int nSourceX, nSourceY;
+ int nSourceXSec, nSourceYSec;
+ int nSourceXSecEnd, nSourceYSecEnd;
+ int nDestX, nDestY;
+ int nSampleOffsetInSampleBlock;
+ unsigned char * pSourceBase;
+ unsigned char * pDestBase;
+ int nSourceBaseInc;
+ unsigned char * pSourceBaseEnd;
+ unsigned int nCummulator;
+ unsigned int nCummulatorCount;
+
+ nSampleBlockSize = nHorSubsampling * nVerSubsampling + 2;
+ nSourceSampleRowSize =
+ ( ( nBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
+ nDestSampleRowSize =
+ ( ( nOBlockXSize + nHorSubsampling - 1 ) / nHorSubsampling ) * nSampleBlockSize;
+
+ if( strncmp(pszResampling,"nearest",4) == 0
+ || strncmp(pszResampling,"NEAR",4) == 0 )
+ {
+ if( nSample == 0 )
+ {
+ for( nSourceY = 0, nDestY = nTYOff;
+ nSourceY < nBlockYSize;
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = nTXOff;
+ nSourceX < nBlockXSize;
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX >= nOBlockXSize )
+ break;
+
+ * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
+ + ( nDestY % nVerSubsampling ) * nHorSubsampling
+ + ( nDestX / nHorSubsampling ) * nSampleBlockSize
+ + ( nDestX % nHorSubsampling ) ) =
+ * ( pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize
+ + ( nSourceY % nVerSubsampling ) * nHorSubsampling
+ + ( nSourceX / nHorSubsampling ) * nSampleBlockSize
+ + ( nSourceX % nHorSubsampling ) );
+ }
+ }
+ }
+ else
+ {
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling );
+ nSourceY < ( nBlockYSize / nVerSubsampling );
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY*nVerSubsampling >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling );
+ nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX*nHorSubsampling >= nOBlockXSize )
+ break;
+
+ * ( pabyOTile + nDestY * nDestSampleRowSize
+ + nDestX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock ) =
+ * ( pabySrcTile + nSourceY * nSourceSampleRowSize
+ + nSourceX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock );
+ }
+ }
+ }
+ }
+ else if( strncmp(pszResampling,"averag",6) == 0
+ || strncmp(pszResampling,"AVERAG",6) == 0 )
+ {
+ if( nSample == 0 )
+ {
+ for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX >= nOBlockXSize )
+ break;
+
+ nSourceXSecEnd = nSourceX + nOMult;
+ if( nSourceXSecEnd > nBlockXSize )
+ nSourceXSecEnd = nBlockXSize;
+ nSourceYSecEnd = nSourceY + nOMult;
+ if( nSourceYSecEnd > nBlockYSize )
+ nSourceYSecEnd = nBlockYSize;
+ nCummulator = 0;
+ for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
+ {
+ for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
+ {
+ nCummulator += * ( pabySrcTile + ( nSourceYSec / nVerSubsampling ) * nSourceSampleRowSize
+ + ( nSourceYSec % nVerSubsampling ) * nHorSubsampling
+ + ( nSourceXSec / nHorSubsampling ) * nSampleBlockSize
+ + ( nSourceXSec % nHorSubsampling ) );
+ }
+ }
+ nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
+ * ( pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
+ + ( nDestY % nVerSubsampling ) * nHorSubsampling
+ + ( nDestX / nHorSubsampling ) * nSampleBlockSize
+ + ( nDestX % nHorSubsampling ) ) =
+ ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
+ }
+ }
+ }
+ else
+ {
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling );
+ nSourceY += nOMult, nDestY ++)
+ {
+ if( nDestY*nVerSubsampling >= nOBlockYSize )
+ break;
+
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ if( nDestX*nHorSubsampling >= nOBlockXSize )
+ break;
+
+ nSourceXSecEnd = nSourceX + nOMult;
+ if( nSourceXSecEnd > ( nBlockXSize / nHorSubsampling ) )
+ nSourceXSecEnd = ( nBlockXSize / nHorSubsampling );
+ nSourceYSecEnd = nSourceY + nOMult;
+ if( nSourceYSecEnd > ( nBlockYSize / nVerSubsampling ) )
+ nSourceYSecEnd = ( nBlockYSize / nVerSubsampling );
+ nCummulator = 0;
+ for( nSourceYSec = nSourceY; nSourceYSec < nSourceYSecEnd; nSourceYSec ++)
+ {
+ for( nSourceXSec = nSourceX; nSourceXSec < nSourceXSecEnd; nSourceXSec ++)
+ {
+ nCummulator += * ( pabySrcTile + nSourceYSec * nSourceSampleRowSize
+ + nSourceXSec * nSampleBlockSize
+ + nSampleOffsetInSampleBlock );
+ }
+ }
+ nCummulatorCount = ( nSourceXSecEnd - nSourceX ) * ( nSourceYSecEnd - nSourceY );
+ * ( pabyOTile + nDestY * nDestSampleRowSize
+ + nDestX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock ) =
+ ( ( nCummulator + ( nCummulatorCount >> 1 ) ) / nCummulatorCount );
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_ProcessFullResBlock() */
+/* */
+/* Process one block of full res data, downsampling into each */
+/* of the overviews. */
+/************************************************************************/
+
+void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
+ int bSubsampled, int nHorSubsampling, int nVerSubsampling,
+ int nOverviews, int * panOvList,
+ int nBitsPerPixel,
+ int nSamples, TIFFOvrCache ** papoRawBIs,
+ int nSXOff, int nSYOff,
+ unsigned char *pabySrcTile,
+ int nBlockXSize, int nBlockYSize,
+ int nSampleFormat, const char * pszResampling )
+
+{
+ int iOverview, iSample;
+
+ for( iSample = 0; iSample < nSamples; iSample++ )
+ {
+ /*
+ * We have to read a tile/strip for each sample for
+ * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples
+ * at once when handling the first sample.
+ */
+ if( nPlanarConfig == PLANARCONFIG_SEPARATE || iSample == 0 )
+ {
+ if( TIFFIsTiled(hTIFF) )
+ {
+ TIFFReadEncodedTile( hTIFF,
+ TIFFComputeTile(hTIFF, nSXOff, nSYOff,
+ 0, (tsample_t)iSample ),
+ pabySrcTile,
+ TIFFTileSize(hTIFF));
+ }
+ else
+ {
+ TIFFReadEncodedStrip( hTIFF,
+ TIFFComputeStrip(hTIFF, nSYOff,
+ (tsample_t) iSample),
+ pabySrcTile,
+ TIFFStripSize(hTIFF) );
+ }
+ }
+
+ /*
+ * Loop over destination overview layers
+ */
+ for( iOverview = 0; iOverview < nOverviews; iOverview++ )
+ {
+ TIFFOvrCache *poRBI = papoRawBIs[iOverview];
+ unsigned char *pabyOTile;
+ int nTXOff, nTYOff, nOXOff, nOYOff, nOMult;
+ int nOBlockXSize = poRBI->nBlockXSize;
+ int nOBlockYSize = poRBI->nBlockYSize;
+ int nSkewBits, nSampleByteOffset;
+
+ /*
+ * Fetch the destination overview tile
+ */
+ nOMult = panOvList[iOverview];
+ nOXOff = (nSXOff/nOMult) / nOBlockXSize;
+ nOYOff = (nSYOff/nOMult) / nOBlockYSize;
+
+ if( bSubsampled )
+ {
+ pabyOTile = TIFFGetOvrBlock_Subsampled( poRBI, nOXOff, nOYOff );
+
+ /*
+ * Establish the offset into this tile at which we should
+ * start placing data.
+ */
+ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
+ nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
+
+
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ TIFF_DownSample_Subsampled( pabySrcTile, iSample,
+ nBlockXSize, nBlockYSize,
+ pabyOTile,
+ poRBI->nBlockXSize, poRBI->nBlockYSize,
+ nTXOff, nTYOff,
+ nOMult, pszResampling,
+ nHorSubsampling, nVerSubsampling );
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+
+ }
+ else
+ {
+
+ pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample );
+
+ /*
+ * Establish the offset into this tile at which we should
+ * start placing data.
+ */
+ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult;
+ nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult;
+
+ /*
+ * Figure out the skew (extra space between ``our samples'') and
+ * the byte offset to the first sample.
+ */
+ assert( (nBitsPerPixel % 8) == 0 );
+ if( nPlanarConfig == PLANARCONFIG_SEPARATE )
+ {
+ nSkewBits = 0;
+ nSampleByteOffset = 0;
+ }
+ else
+ {
+ nSkewBits = nBitsPerPixel * (nSamples-1);
+ nSampleByteOffset = (nBitsPerPixel/8) * iSample;
+ }
+
+ /*
+ * Perform the downsampling.
+ */
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ TIFF_DownSample( pabySrcTile + nSampleByteOffset,
+ nBlockXSize, nBlockYSize,
+ nSkewBits, nBitsPerPixel, pabyOTile,
+ poRBI->nBlockXSize, poRBI->nBlockYSize,
+ nTXOff, nTYOff,
+ nOMult, nSampleFormat, pszResampling );
+#ifdef DBMALLOC
+ malloc_chain_check( 1 );
+#endif
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* TIFF_BuildOverviews() */
+/* */
+/* Build the requested list of overviews. Overviews are */
+/* maintained in a bunch of temporary files and then these are */
+/* written back to the TIFF file. Only one pass through the */
+/* source TIFF file is made for any number of output */
+/* overviews. */
+/************************************************************************/
+
+void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
+ int bUseSubIFDs, const char *pszResampleMethod,
+ int (*pfnProgress)( double, void * ),
+ void * pProgressData )
+
+{
+ TIFFOvrCache **papoRawBIs;
+ uint32 nXSize, nYSize, nBlockXSize, nBlockYSize;
+ uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples,
+ nPlanarConfig, nSampleFormat;
+ int bSubsampled;
+ uint16 nHorSubsampling, nVerSubsampling;
+ int bTiled, nSXOff, nSYOff, i;
+ unsigned char *pabySrcTile;
+ uint16 *panRedMap, *panGreenMap, *panBlueMap;
+ TIFFErrorHandler pfnWarning;
+
+/* -------------------------------------------------------------------- */
+/* Get the base raster size. */
+/* -------------------------------------------------------------------- */
+ TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
+ TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
+
+ TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel );
+ /* TODO: nBitsPerPixel seems misnomer and may need renaming to nBitsPerSample */
+ TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamples );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
+
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_PHOTOMETRIC, &nPhotometric );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag );
+ TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat );
+
+ if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
+ {
+ if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG ||
+ nSampleFormat != SAMPLEFORMAT_UINT)
+ {
+ /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
+ TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
+ "File `%s' has an unsupported subsampling configuration.\n",
+ TIFFFileName(hTIFF) );
+ /* If you need support for this particular flavor, please contact either
+ * Frank Warmerdam warmerdam@pobox.com
+ * Joris Van Damme info@awaresystems.be
+ */
+ return;
+ }
+ bSubsampled = 1;
+ TIFFGetField( hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nHorSubsampling, &nVerSubsampling );
+ /* TODO: find out if maybe TIFFGetFieldDefaulted is better choice for YCbCrSubsampling tag */
+ }
+ else
+ {
+ if( nBitsPerPixel < 8 )
+ {
+ /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */
+ TIFFErrorExt( TIFFClientdata(hTIFF), "TIFFBuildOverviews",
+ "File `%s' has samples of %d bits per sample. Sample\n"
+ "sizes of less than 8 bits per sample are not supported.\n",
+ TIFFFileName(hTIFF), nBitsPerPixel );
+ return;
+ }
+ bSubsampled = 0;
+ nHorSubsampling = 1;
+ nVerSubsampling = 1;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Turn off warnings to avoid alot of repeated warnings while */
+/* rereading directories. */
+/* -------------------------------------------------------------------- */
+ pfnWarning = TIFFSetWarningHandler( NULL );
+
+/* -------------------------------------------------------------------- */
+/* Get the base raster block size. */
+/* -------------------------------------------------------------------- */
+ if( TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nBlockYSize) ) )
+ {
+ nBlockXSize = nXSize;
+ bTiled = FALSE;
+ }
+ else
+ {
+ TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &nBlockXSize );
+ TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &nBlockYSize );
+ bTiled = TRUE;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Capture the pallette if there is one. */
+/* -------------------------------------------------------------------- */
+ if( TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
+ &panRedMap, &panGreenMap, &panBlueMap ) )
+ {
+ uint16 *panRed2, *panGreen2, *panBlue2;
+ int nColorCount = 1 << nBitsPerPixel;
+
+ panRed2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+ panGreen2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+ panBlue2 = (uint16 *) _TIFFmalloc(2*nColorCount);
+
+ memcpy( panRed2, panRedMap, 2 * nColorCount );
+ memcpy( panGreen2, panGreenMap, 2 * nColorCount );
+ memcpy( panBlue2, panBlueMap, 2 * nColorCount );
+
+ panRedMap = panRed2;
+ panGreenMap = panGreen2;
+ panBlueMap = panBlue2;
+ }
+ else
+ {
+ panRedMap = panGreenMap = panBlueMap = NULL;
+ }
+
+/* -------------------------------------------------------------------- */
+/* Initialize overviews. */
+/* -------------------------------------------------------------------- */
+ papoRawBIs = (TIFFOvrCache **) _TIFFmalloc(nOverviews*sizeof(void*));
+
+ for( i = 0; i < nOverviews; i++ )
+ {
+ int nOXSize, nOYSize, nOBlockXSize, nOBlockYSize;
+ uint32 nDirOffset;
+
+ nOXSize = (nXSize + panOvList[i] - 1) / panOvList[i];
+ nOYSize = (nYSize + panOvList[i] - 1) / panOvList[i];
+
+ nOBlockXSize = MIN((int)nBlockXSize,nOXSize);
+ nOBlockYSize = MIN((int)nBlockYSize,nOYSize);
+
+ if( bTiled )
+ {
+ if( (nOBlockXSize % 16) != 0 )
+ nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16);
+
+ if( (nOBlockYSize % 16) != 0 )
+ nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16);
+ }
+
+ nDirOffset = TIFF_WriteOverview( hTIFF, nOXSize, nOYSize,
+ nBitsPerPixel, nPlanarConfig,
+ nSamples, nOBlockXSize, nOBlockYSize,
+ bTiled, nCompressFlag, nPhotometric,
+ nSampleFormat,
+ panRedMap, panGreenMap, panBlueMap,
+ bUseSubIFDs,
+ nHorSubsampling, nVerSubsampling );
+
+ papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset );
+ }
+
+ if( panRedMap != NULL )
+ {
+ _TIFFfree( panRedMap );
+ _TIFFfree( panGreenMap );
+ _TIFFfree( panBlueMap );
+ }
+
+/* -------------------------------------------------------------------- */
+/* Allocate a buffer to hold a source block. */
+/* -------------------------------------------------------------------- */
+ if( bTiled )
+ pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFTileSize(hTIFF));
+ else
+ pabySrcTile = (unsigned char *) _TIFFmalloc(TIFFStripSize(hTIFF));
+
+/* -------------------------------------------------------------------- */
+/* Loop over the source raster, applying data to the */
+/* destination raster. */
+/* -------------------------------------------------------------------- */
+ for( nSYOff = 0; nSYOff < (int) nYSize; nSYOff += nBlockYSize )
+ {
+ for( nSXOff = 0; nSXOff < (int) nXSize; nSXOff += nBlockXSize )
+ {
+ /*
+ * Read and resample into the various overview images.
+ */
+
+ TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig,
+ bSubsampled,nHorSubsampling,nVerSubsampling,
+ nOverviews, panOvList,
+ nBitsPerPixel, nSamples, papoRawBIs,
+ nSXOff, nSYOff, pabySrcTile,
+ nBlockXSize, nBlockYSize,
+ nSampleFormat, pszResampleMethod );
+ }
+ }
+
+ _TIFFfree( pabySrcTile );
+
+/* -------------------------------------------------------------------- */
+/* Cleanup the rawblockedimage files. */
+/* -------------------------------------------------------------------- */
+ for( i = 0; i < nOverviews; i++ )
+ {
+ TIFFDestroyOvrCache( papoRawBIs[i] );
+ }
+
+ if( papoRawBIs != NULL )
+ _TIFFfree( papoRawBIs );
+
+ TIFFSetWarningHandler( pfnWarning );
+}
+
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 8
+ * fill-column: 78
+ * End:
+ */