diff options
Diffstat (limited to 'contrib/addtiffo/tif_overview.c')
-rw-r--r-- | contrib/addtiffo/tif_overview.c | 362 |
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 ); } + + |