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