New
This commit is contained in:
parent
eaad74ed60
commit
fb8149ec52
497
contrib/addtiffo/tif_overview.c
Normal file
497
contrib/addtiffo/tif_overview.c
Normal file
@ -0,0 +1,497 @@
|
||||
/******************************************************************************
|
||||
* $Id: tif_overview.c,v 1.1 2000-01-28 15:04:03 warmerda Exp $
|
||||
*
|
||||
* Project: TIFF Overview Builder
|
||||
* Purpose: Library function for building overviews in a TIFF file.
|
||||
* Author: Frank Warmerdam, warmerda@home.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.
|
||||
******************************************************************************
|
||||
*
|
||||
* $Log: tif_overview.c,v $
|
||||
* Revision 1.1 2000-01-28 15:04:03 warmerda
|
||||
* New
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.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( const char *, int, int *, int );
|
||||
|
||||
/************************************************************************/
|
||||
/* 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. */
|
||||
/********************************* ***************************************/
|
||||
|
||||
static
|
||||
uint32 TIFF_WriteOverview( TIFF *hTIFF, int nXSize, int nYSize,
|
||||
int nBitsPerPixel, 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 )
|
||||
|
||||
{
|
||||
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, PLANARCONFIG_SEPARATE );
|
||||
|
||||
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 );
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Write color table if one is present. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
if( panRed != NULL )
|
||||
{
|
||||
TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue );
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Write directory, and return byte offset. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
TIFFWriteCheck( hTIFF, bTiled, "TIFFBuildOverviews" );
|
||||
TIFFWriteDirectory( hTIFF );
|
||||
TIFFSetDirectory( hTIFF, TIFFNumberOfDirectories(hTIFF)-1 );
|
||||
|
||||
nOffset = TIFFCurrentDirOffset( hTIFF );
|
||||
|
||||
TIFFSetSubDirectory( hTIFF, nBaseDirOffset );
|
||||
|
||||
return nOffset;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* 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 i, j, k, nPixelBytes = (nBitsPerPixel) / 8;
|
||||
int nPixelGroupBytes = (nBitsPerPixel+nPixelSkewBits)/8;
|
||||
unsigned char *pabySrc, *pabyDst;
|
||||
|
||||
assert( nBitsPerPixel >= 8 );
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Handle case of one or more whole bytes per sample. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
for( j = 0; j*nOMult < nBlockYSize; j++ )
|
||||
{
|
||||
if( j + nTYOff >= nOBlockYSize )
|
||||
break;
|
||||
|
||||
pabySrc = pabySrcTile + j*nOMult*nBlockXSize * nPixelGroupBytes;
|
||||
pabyDst = pabyOTile
|
||||
+ ((j+nTYOff)*nOBlockXSize + nTXOff) * nPixelBytes;
|
||||
|
||||
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++) = pabySrc[k];
|
||||
}
|
||||
|
||||
pabySrc += nOMult * nPixelGroupBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* TIFF_ProcessFullResBlock() */
|
||||
/* */
|
||||
/* Process one block of full res data, downsampling into each */
|
||||
/* of the overviews. */
|
||||
/************************************************************************/
|
||||
|
||||
void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig,
|
||||
int nOverviews, int * panOvList,
|
||||
int nBitsPerPixel,
|
||||
int nSamples, TIFFOvrCache ** papoRawBIs,
|
||||
int nSXOff, int nSYOff,
|
||||
unsigned char *pabySrcTile,
|
||||
int nBlockXSize, int nBlockYSize )
|
||||
|
||||
{
|
||||
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, iSample ),
|
||||
pabySrcTile,
|
||||
TIFFTileSize(hTIFF));
|
||||
}
|
||||
else
|
||||
{
|
||||
TIFFReadEncodedStrip( hTIFF,
|
||||
TIFFComputeStrip(hTIFF, nSYOff, 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;
|
||||
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 );
|
||||
#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( const char * pszTIFFFilename,
|
||||
int nOverviews, int * panOvList,
|
||||
int bUseSubIFDs )
|
||||
|
||||
{
|
||||
TIFFOvrCache **papoRawBIs;
|
||||
uint32 nXSize, nYSize, nBlockXSize, nBlockYSize;
|
||||
uint16 nBitsPerPixel, nPhotometric, nCompressFlag, nSamples,
|
||||
nPlanarConfig, nSampleFormat;
|
||||
int bTiled, nSXOff, nSYOff, i;
|
||||
unsigned char *pabySrcTile;
|
||||
TIFF *hTIFF;
|
||||
uint16 *panRedMap, *panGreenMap, *panBlueMap;
|
||||
TIFFErrorHandler pfnWarning;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Get the base raster size. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
hTIFF = TIFFOpen( pszTIFFFilename, "r+" );
|
||||
if( hTIFF == NULL )
|
||||
{
|
||||
fprintf( stderr, "TIFFOpen(%s) failed.\n", pszTIFFFilename );
|
||||
exit( 1 );
|
||||
}
|
||||
|
||||
TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
|
||||
TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
|
||||
|
||||
TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerPixel );
|
||||
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( nBitsPerPixel < 8 )
|
||||
{
|
||||
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",
|
||||
pszTIFFFilename, nBitsPerPixel );
|
||||
return;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* 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;
|
||||
|
||||
panRed2 = (uint16 *) _TIFFmalloc(2*256);
|
||||
panGreen2 = (uint16 *) _TIFFmalloc(2*256);
|
||||
panBlue2 = (uint16 *) _TIFFmalloc(2*256);
|
||||
|
||||
memcpy( panRed2, panRedMap, 512 );
|
||||
memcpy( panGreen2, panGreenMap, 512 );
|
||||
memcpy( panBlue2, panBlueMap, 512 );
|
||||
|
||||
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, nSamples,
|
||||
nOBlockXSize, nOBlockYSize,
|
||||
bTiled, nCompressFlag, nPhotometric,
|
||||
nSampleFormat,
|
||||
panRedMap, panGreenMap, panBlueMap,
|
||||
bUseSubIFDs );
|
||||
|
||||
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,
|
||||
nOverviews, panOvList,
|
||||
nBitsPerPixel, nSamples, papoRawBIs,
|
||||
nSXOff, nSYOff, pabySrcTile,
|
||||
nBlockXSize, nBlockYSize );
|
||||
}
|
||||
}
|
||||
|
||||
_TIFFfree( pabySrcTile );
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Cleanup the rawblockedimage files. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
for( i = 0; i < nOverviews; i++ )
|
||||
{
|
||||
TIFFDestroyOvrCache( papoRawBIs[i] );
|
||||
}
|
||||
|
||||
if( papoRawBIs != NULL )
|
||||
_TIFFfree( papoRawBIs );
|
||||
|
||||
TIFFClose( hTIFF );
|
||||
|
||||
TIFFSetWarningHandler( pfnWarning );
|
||||
}
|
264
contrib/addtiffo/tif_ovrcache.c
Normal file
264
contrib/addtiffo/tif_ovrcache.c
Normal file
@ -0,0 +1,264 @@
|
||||
/******************************************************************************
|
||||
* $Id: tif_ovrcache.c,v 1.1 2000-01-28 15:03:44 warmerda Exp $
|
||||
*
|
||||
* Project: TIFF Overview Builder
|
||||
* Purpose: Library functions to maintain two rows of tiles or two strips
|
||||
* of data for output overviews as an output cache.
|
||||
* Author: Frank Warmerdam, warmerda@home.com
|
||||
*
|
||||
******************************************************************************
|
||||
* Copyright (c) 2000, 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.
|
||||
******************************************************************************
|
||||
*
|
||||
* $Log: tif_ovrcache.c,v $
|
||||
* Revision 1.1 2000-01-28 15:03:44 warmerda
|
||||
* New
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tiffiop.h"
|
||||
#include "tif_ovrcache.h"
|
||||
#include <assert.h>
|
||||
|
||||
/************************************************************************/
|
||||
/* TIFFCreateOvrCache() */
|
||||
/* */
|
||||
/* Create an overview cache to hold two rows of blocks from an */
|
||||
/* existing TIFF directory. */
|
||||
/************************************************************************/
|
||||
|
||||
TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset )
|
||||
|
||||
{
|
||||
TIFFOvrCache *psCache;
|
||||
int nBytesPerRow;
|
||||
uint32 nBaseDirOffset;
|
||||
|
||||
psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache));
|
||||
psCache->nDirOffset = nDirOffset;
|
||||
psCache->hTIFF = hTIFF;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Get definition of this raster from the TIFF file itself. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
|
||||
TIFFSetSubDirectory( hTIFF, nDirOffset );
|
||||
|
||||
TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) );
|
||||
TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) );
|
||||
|
||||
TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) );
|
||||
TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) );
|
||||
|
||||
if( !TIFFIsTiled( hTIFF ) )
|
||||
{
|
||||
TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) );
|
||||
psCache->nBlockXSize = psCache->nXSize;
|
||||
psCache->bTiled = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) );
|
||||
TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) );
|
||||
psCache->bTiled = TRUE;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Compute some values from this. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1)
|
||||
/ psCache->nBlockXSize;
|
||||
psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1)
|
||||
/ psCache->nBlockYSize;
|
||||
|
||||
psCache->nBytesPerBlock =
|
||||
(psCache->nBlockXSize*psCache->nBlockYSize*psCache->nBitsPerPixel + 7) / 8;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Allocate and initialize the data buffers. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
nBytesPerRow = psCache->nBytesPerBlock * psCache->nBlocksPerRow
|
||||
* psCache->nSamples;
|
||||
|
||||
psCache->pabyRow1Blocks = (unsigned char *) _TIFFmalloc(nBytesPerRow);
|
||||
psCache->pabyRow2Blocks = (unsigned char *) _TIFFmalloc(nBytesPerRow);
|
||||
|
||||
if( psCache->pabyRow1Blocks == NULL
|
||||
|| psCache->pabyRow2Blocks == NULL )
|
||||
{
|
||||
TIFFError( hTIFF->tif_name,
|
||||
"Can't allocate memory for overview cache." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_TIFFmemset( psCache->pabyRow1Blocks, 0, nBytesPerRow );
|
||||
_TIFFmemset( psCache->pabyRow2Blocks, 0, nBytesPerRow );
|
||||
|
||||
psCache->nBlockOffset = 0;
|
||||
|
||||
TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
|
||||
|
||||
return psCache;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* TIFFWriteOvrRow() */
|
||||
/* */
|
||||
/* Write one entire row of blocks (row 1) to the tiff file, and */
|
||||
/* then rotate the block buffers, essentially moving things */
|
||||
/* down by one block. */
|
||||
/************************************************************************/
|
||||
|
||||
static void TIFFWriteOvrRow( TIFFOvrCache * psCache )
|
||||
|
||||
{
|
||||
int nRet, iSample, iTileX, iTileY = psCache->nBlockOffset;
|
||||
unsigned char *pabyData;
|
||||
uint32 nBaseDirOffset;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* If the output cache is multi-byte per sample, and the file */
|
||||
/* being written to is of a different byte order than the current */
|
||||
/* platform, we will need to byte swap the data. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
if( TIFFIsByteSwapped(psCache->hTIFF) )
|
||||
{
|
||||
if( psCache->nBitsPerPixel == 16 )
|
||||
TIFFSwabArrayOfShort( (uint16 *) psCache->pabyRow1Blocks,
|
||||
(psCache->nBytesPerBlock * psCache->nSamples) / 2 );
|
||||
|
||||
else if( psCache->nBitsPerPixel == 32 )
|
||||
TIFFSwabArrayOfLong( (uint32 *) psCache->pabyRow1Blocks,
|
||||
(psCache->nBytesPerBlock * psCache->nSamples) / 4 );
|
||||
|
||||
else if( psCache->nBitsPerPixel == 64 )
|
||||
TIFFSwabArrayOfDouble( (double *) psCache->pabyRow1Blocks,
|
||||
(psCache->nBytesPerBlock * psCache->nSamples) / 8 );
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Record original directory position, so we can restore it at */
|
||||
/* end. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF );
|
||||
nRet = TIFFSetSubDirectory( psCache->hTIFF, psCache->nDirOffset );
|
||||
assert( nRet == 1 );
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Write blocks to TIFF file. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
for( iTileX = 0; iTileX < psCache->nBlocksPerRow; iTileX++ )
|
||||
{
|
||||
for( iSample = 0; iSample < psCache->nSamples; iSample++ )
|
||||
{
|
||||
int nTileID;
|
||||
|
||||
pabyData = TIFFGetOvrBlock( psCache, iTileX, iTileY, iSample );
|
||||
|
||||
if( psCache->bTiled )
|
||||
{
|
||||
nTileID =
|
||||
TIFFComputeTile(psCache->hTIFF,
|
||||
iTileX * psCache->nBlockXSize,
|
||||
iTileY * psCache->nBlockYSize,
|
||||
0, iSample );
|
||||
TIFFWriteEncodedTile( psCache->hTIFF, nTileID,
|
||||
pabyData,
|
||||
TIFFTileSize(psCache->hTIFF) );
|
||||
}
|
||||
else
|
||||
{
|
||||
nTileID =
|
||||
TIFFComputeStrip(psCache->hTIFF,
|
||||
iTileY * psCache->nBlockYSize,
|
||||
iSample);
|
||||
|
||||
TIFFWriteEncodedStrip( psCache->hTIFF, nTileID,
|
||||
pabyData,
|
||||
TIFFStripSize(psCache->hTIFF) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Rotate buffers. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
pabyData = psCache->pabyRow1Blocks;
|
||||
psCache->pabyRow1Blocks = psCache->pabyRow2Blocks;
|
||||
psCache->pabyRow2Blocks = pabyData;
|
||||
|
||||
_TIFFmemset( pabyData, 0,
|
||||
psCache->nBytesPerBlock * psCache->nSamples
|
||||
* psCache->nBlocksPerRow );
|
||||
|
||||
psCache->nBlockOffset++;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* Restore access to original directory. */
|
||||
/* -------------------------------------------------------------------- */
|
||||
TIFFFlush( psCache->hTIFF );
|
||||
|
||||
TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset );
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* TIFFGetOvrBlock() */
|
||||
/************************************************************************/
|
||||
|
||||
unsigned char *TIFFGetOvrBlock( TIFFOvrCache *psCache, int iTileX, int iTileY,
|
||||
int iSample )
|
||||
|
||||
{
|
||||
int nRowOffset;
|
||||
|
||||
if( iTileY > psCache->nBlockOffset + 1 )
|
||||
TIFFWriteOvrRow( psCache );
|
||||
|
||||
assert( iTileX >= 0 && iTileX < psCache->nBlocksPerRow );
|
||||
assert( iTileY >= 0 && iTileY < psCache->nBlocksPerColumn );
|
||||
assert( iTileY >= psCache->nBlockOffset
|
||||
&& iTileY < psCache->nBlockOffset+2 );
|
||||
assert( iSample >= 0 && iSample < psCache->nSamples );
|
||||
|
||||
nRowOffset = ((iTileX * psCache->nSamples) + iSample)
|
||||
* psCache->nBytesPerBlock;
|
||||
|
||||
if( iTileY == psCache->nBlockOffset )
|
||||
return psCache->pabyRow1Blocks + nRowOffset;
|
||||
else
|
||||
return psCache->pabyRow2Blocks + nRowOffset;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
/* TIFFDestroyOvrCache() */
|
||||
/************************************************************************/
|
||||
|
||||
void TIFFDestroyOvrCache( TIFFOvrCache * psCache )
|
||||
|
||||
{
|
||||
while( psCache->nBlockOffset < psCache->nBlocksPerColumn )
|
||||
TIFFWriteOvrRow( psCache );
|
||||
|
||||
_TIFFfree( psCache->pabyRow1Blocks );
|
||||
_TIFFfree( psCache->pabyRow2Blocks );
|
||||
_TIFFfree( psCache );
|
||||
}
|
72
contrib/addtiffo/tif_ovrcache.h
Normal file
72
contrib/addtiffo/tif_ovrcache.h
Normal file
@ -0,0 +1,72 @@
|
||||
/******************************************************************************
|
||||
* $Id: tif_ovrcache.h,v 1.1 2000-01-28 15:03:32 warmerda Exp $
|
||||
*
|
||||
* Project: TIFF Overview Builder
|
||||
* Purpose: Library functions to maintain two rows of tiles or two strips
|
||||
* of data for output overviews as an output cache.
|
||||
* Author: Frank Warmerdam, warmerda@home.com
|
||||
*
|
||||
* This code could potentially be used by other applications wanting to
|
||||
* manage a once-through write cache.
|
||||
*
|
||||
******************************************************************************
|
||||
* Copyright (c) 2000, 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.
|
||||
******************************************************************************
|
||||
*
|
||||
* $Log: tif_ovrcache.h,v $
|
||||
* Revision 1.1 2000-01-28 15:03:32 warmerda
|
||||
* New
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TIF_OVRCACHE_H_INCLUDED
|
||||
#define TIF_OVRCACHE_H_INCLUDED
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32 nXSize;
|
||||
uint32 nYSize;
|
||||
|
||||
uint32 nBlockXSize;
|
||||
uint32 nBlockYSize;
|
||||
uint16 nBitsPerPixel;
|
||||
uint16 nSamples;
|
||||
int nBytesPerBlock;
|
||||
|
||||
int nBlocksPerRow;
|
||||
int nBlocksPerColumn;
|
||||
|
||||
int nBlockOffset; /* what block is the first in papabyBlocks? */
|
||||
unsigned char *pabyRow1Blocks;
|
||||
unsigned char *pabyRow2Blocks;
|
||||
|
||||
int nDirOffset;
|
||||
TIFF *hTIFF;
|
||||
int bTiled;
|
||||
|
||||
} TIFFOvrCache;
|
||||
|
||||
TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset );
|
||||
unsigned char *TIFFGetOvrBlock( TIFFOvrCache *, int, int, int );
|
||||
void TIFFDestroyOvrCache( TIFFOvrCache * );
|
||||
|
||||
#endif /* ndef TIF_OVRCACHE_H_INCLUDED */
|
||||
|
Loading…
Reference in New Issue
Block a user