summaryrefslogtreecommitdiff
path: root/contrib/addtiffo/tif_overview.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/addtiffo/tif_overview.c')
-rw-r--r--contrib/addtiffo/tif_overview.c362
1 files changed, 309 insertions, 53 deletions
diff --git a/contrib/addtiffo/tif_overview.c b/contrib/addtiffo/tif_overview.c
index 1423d875..b8c2c9f6 100644
--- a/contrib/addtiffo/tif_overview.c
+++ b/contrib/addtiffo/tif_overview.c
@@ -45,6 +45,8 @@
******************************************************************************
*/
+/* TODO: update notes in header above */
+
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
@@ -83,7 +85,8 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
unsigned short *panRed,
unsigned short *panGreen,
unsigned short *panBlue,
- int bUseSubIFDs )
+ int bUseSubIFDs,
+ int nHorSubsampling, int nVerSubsampling )
{
uint32 nBaseDirOffset;
@@ -92,7 +95,7 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
nBaseDirOffset = TIFFCurrentDirOffset( hTIFF );
TIFFCreateDirectory( hTIFF );
-
+
/* -------------------------------------------------------------------- */
/* Setup TIFF fields. */
/* -------------------------------------------------------------------- */
@@ -118,7 +121,15 @@ uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
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. */
/* -------------------------------------------------------------------- */
@@ -270,7 +281,7 @@ void TIFF_DownSample( unsigned char *pabySrcTile,
{
if( j + nTYOff >= nOBlockYSize )
break;
-
+
pabyDst = pabyOTile + ((j+nTYOff)*nOBlockXSize + nTXOff)
* nPixelBytes * nPixelGroupBytes;
@@ -305,7 +316,7 @@ void TIFF_DownSample( unsigned char *pabySrcTile,
/* 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
+ else if( strncmp(pszResampling,"averag",6) == 0
|| strncmp(pszResampling,"AVERAG",6) == 0 )
{
pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
@@ -322,12 +333,12 @@ void TIFF_DownSample( unsigned char *pabySrcTile,
nXSize = MIN(nOMult,nBlockXSize-i);
nYSize = MIN(nOMult,nBlockYSize-j);
- TIFF_GetSourceSamples( padfSamples, pabySrc,
- nPixelBytes, nSampleFormat,
- nXSize, nYSize,
- nPixelGroupBytes,
+ TIFF_GetSourceSamples( padfSamples, pabySrc,
+ nPixelBytes, nSampleFormat,
+ nXSize, nYSize,
+ nPixelGroupBytes,
nPixelGroupBytes * nBlockXSize );
-
+
dfTotal = 0;
for( iSample = 0; iSample < nXSize*nYSize; iSample++ )
{
@@ -346,6 +357,187 @@ void TIFF_DownSample( unsigned char *pabySrcTile,
free( padfSamples );
}
+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 )
+ {
+#ifdef NOOPTIMIZATION
+ /*
+ * This version is not optimized, and should not be used except as documentation and as more clear
+ * starting point for bug fixes (hope not) and extension
+ */
+ for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++)
+ {
+ for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
+ {
+ * ( 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
+ for( nSourceY = 0, nDestY = nTYOff; nSourceY < nBlockYSize; nSourceY += nOMult, nDestY ++)
+ {
+ pSourceBase = pabySrcTile + ( nSourceY / nVerSubsampling ) * nSourceSampleRowSize
+ + ( nSourceY % nVerSubsampling ) * nHorSubsampling;
+ pDestBase = pabyOTile + ( nDestY / nVerSubsampling ) * nDestSampleRowSize
+ + ( nDestY % nVerSubsampling ) * nHorSubsampling;
+ for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
+ {
+ * ( pDestBase + ( nDestX / nHorSubsampling ) * nSampleBlockSize
+ + ( nDestX % nHorSubsampling ) ) =
+ * ( pSourceBase + ( nSourceX / nHorSubsampling ) * nSampleBlockSize
+ + ( nSourceX % nHorSubsampling ) );
+ }
+ }
+#endif
+ }
+ else
+ {
+#ifdef NOOPTIMIZATION
+ /*
+ * This version is not optimized, and should not be used except as documentation and as more clear
+ * starting point for bug fixes (hope not) and extension
+ */
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling );
+ nSourceY += nOMult, nDestY ++)
+ {
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ * ( pabyOTile + nDestY * nDestSampleRowSize
+ + nDestX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock ) =
+ * ( pabySrcTile + nSourceY * nSourceSampleRowSize
+ + nSourceX * nSampleBlockSize
+ + nSampleOffsetInSampleBlock );
+ }
+ }
+#else
+ nSampleOffsetInSampleBlock = nHorSubsampling * nVerSubsampling + nSample - 1;
+ nSourceBaseInc = nOMult * nSampleBlockSize;
+ for( nSourceY = 0, nDestY = ( nTYOff / nVerSubsampling ); nSourceY < ( nBlockYSize / nVerSubsampling);
+ nSourceY += nOMult, nDestY ++)
+ {
+ pSourceBase = pabySrcTile + nSourceY * nSourceSampleRowSize
+ + nSampleOffsetInSampleBlock;
+ pSourceBaseEnd = pSourceBase + ( ( ( nBlockXSize / nHorSubsampling ) + nOMult - 1 ) / nOMult ) * nSourceBaseInc;
+ pDestBase = pabyOTile + nDestY * nDestSampleRowSize
+ + ( nTXOff / nHorSubsampling ) * nSampleBlockSize
+ + nSampleOffsetInSampleBlock;
+ for( ; pSourceBase < pSourceBaseEnd; pSourceBase += nSourceBaseInc, pDestBase += nSampleBlockSize)
+ * pDestBase = * pSourceBase;
+ }
+#endif
+ }
+ }
+ 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 ++)
+ {
+ for( nSourceX = 0, nDestX = nTXOff; nSourceX < nBlockXSize; nSourceX += nOMult, nDestX ++)
+ {
+ 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 ++)
+ {
+ for( nSourceX = 0, nDestX = ( nTXOff / nHorSubsampling ); nSourceX < ( nBlockXSize / nHorSubsampling );
+ nSourceX += nOMult, nDestX ++)
+ {
+ 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() */
/* */
@@ -354,8 +546,9 @@ void TIFF_DownSample( unsigned char *pabySrcTile,
/************************************************************************/
void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
+ int bSubsampled, int nHorSubsampling, int nVerSubsampling,
int nOverviews, int * panOvList,
- int nBitsPerPixel,
+ int nBitsPerPixel,
int nSamples, TIFFOvrCache ** papoRawBIs,
int nSXOff, int nSYOff,
unsigned char *pabySrcTile,
@@ -410,46 +603,78 @@ void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
nOMult = panOvList[iOverview];
nOXOff = (nSXOff/nOMult) / nOBlockXSize;
nOYOff = (nSYOff/nOMult) / nOBlockYSize;
- 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 )
+ if( bSubsampled )
{
- nSkewBits = 0;
- nSampleByteOffset = 0;
+ 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
{
- nSkewBits = nBitsPerPixel * (nSamples-1);
- nSampleByteOffset = (nBitsPerPixel/8) * iSample;
- }
-
- /*
- * Perform the downsampling.
- */
+
+ 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 );
+ malloc_chain_check( 1 );
#endif
- TIFF_DownSample( pabySrcTile + nSampleByteOffset,
- nBlockXSize, nBlockYSize,
- nSkewBits, nBitsPerPixel, pabyOTile,
- poRBI->nBlockXSize, poRBI->nBlockYSize,
- nTXOff, nTYOff,
- nOMult, nSampleFormat, pszResampling );
+ 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
+ malloc_chain_check( 1 );
+#endif
+ }
}
}
}
@@ -474,6 +699,8 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
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;
@@ -486,6 +713,7 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
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 );
@@ -493,15 +721,39 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
TIFFGetFieldDefaulted( hTIFF, TIFFTAG_COMPRESSION, &nCompressFlag );
TIFFGetFieldDefaulted( hTIFF, TIFFTAG_SAMPLEFORMAT, &nSampleFormat );
- if( nBitsPerPixel < 8 )
+ if( nPhotometric == PHOTOMETRIC_YCBCR || nPhotometric == PHOTOMETRIC_ITULAB )
{
- TIFFError( "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;
+ if( nBitsPerPixel != 8 || nSamples != 3 || nPlanarConfig != PLANARCONFIG_CONTIG ||
+ nSampleFormat != SAMPLEFORMAT_UINT)
+ {
+ TIFFError( NULL, "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 )
+ {
+ TIFFError( NULL, "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. */
@@ -548,7 +800,7 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
{
panRedMap = panGreenMap = panBlueMap = NULL;
}
-
+
/* -------------------------------------------------------------------- */
/* Initialize overviews. */
/* -------------------------------------------------------------------- */
@@ -569,7 +821,7 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
{
if( (nOBlockXSize % 16) != 0 )
nOBlockXSize = nOBlockXSize + 16 - (nOBlockXSize % 16);
-
+
if( (nOBlockYSize % 16) != 0 )
nOBlockYSize = nOBlockYSize + 16 - (nOBlockYSize % 16);
}
@@ -580,7 +832,8 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
bTiled, nCompressFlag, nPhotometric,
nSampleFormat,
panRedMap, panGreenMap, panBlueMap,
- bUseSubIFDs );
+ bUseSubIFDs,
+ nHorSubsampling, nVerSubsampling );
papoRawBIs[i] = TIFFCreateOvrCache( hTIFF, nDirOffset );
}
@@ -613,6 +866,7 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
*/
TIFF_ProcessFullResBlock( hTIFF, nPlanarConfig,
+ bSubsampled,nHorSubsampling,nVerSubsampling,
nOverviews, panOvList,
nBitsPerPixel, nSamples, papoRawBIs,
nSXOff, nSYOff, pabySrcTile,
@@ -636,3 +890,5 @@ void TIFFBuildOverviews( TIFF *hTIFF, int nOverviews, int * panOvList,
TIFFSetWarningHandler( pfnWarning );
}
+
+