/****************************************************************************** * $Id: gdalrasterband.cpp 12426 2007-10-15 03:29:04Z warmerdam $ * * Project: GDAL Core * Purpose: Base class for format specific band class implementation. This * base class provides default implementation for many methods. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 1998, 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. ****************************************************************************/ #include "gdal_priv.h" #include "gdal_rat.h" #include "cpl_string.h" #define SUBBLOCK_SIZE 64 #define TO_SUBBLOCK(x) ((x) >> 6) #define WITHIN_SUBBLOCK(x) ((x) & 0x3f) CPL_CVSID("$Id: gdalrasterband.cpp 12426 2007-10-15 03:29:04Z warmerdam $"); /************************************************************************/ /* GDALRasterBand() */ /************************************************************************/ /*! Constructor. Applications should never create GDALRasterBands directly. */ GDALRasterBand::GDALRasterBand() { poDS = NULL; nBand = 0; eAccess = GA_ReadOnly; nBlockXSize = nBlockYSize = -1; eDataType = GDT_Byte; nSubBlocksPerRow = nBlocksPerRow = 0; nSubBlocksPerColumn = nBlocksPerColumn = 0; bSubBlockingActive = FALSE; papoBlocks = NULL; nBlockReads = 0; bForceCachedIO = CSLTestBoolean( CPLGetConfigOption( "GDAL_FORCE_CACHING", "NO") ); } /************************************************************************/ /* ~GDALRasterBand() */ /************************************************************************/ /*! Destructor. Applications should never destroy GDALRasterBands directly, instead destroy the GDALDataset. */ GDALRasterBand::~GDALRasterBand() { FlushCache(); CPLFree( papoBlocks ); if( nBlockReads > nBlocksPerRow * nBlocksPerColumn && nBand == 1 && poDS != NULL ) { CPLDebug( "GDAL", "%d block reads on %d block band 1 of %s.", nBlockReads, nBlocksPerRow * nBlocksPerColumn, poDS->GetDescription() ); } } /************************************************************************/ /* RasterIO() */ /************************************************************************/ /** * Read/write a region of image data for this band. * * This method allows reading a region of a GDALRasterBand into a buffer, * or writing data from a buffer into a region of a GDALRasterBand. It * automatically takes care of data type translation if the data type * (eBufType) of the buffer is different than that of the GDALRasterBand. * The method also takes care of image decimation / replication if the * buffer size (nBufXSize x nBufYSize) is different than the size of the * region being accessed (nXSize x nYSize). * * The nPixelSpace and nLineSpace parameters allow reading into or * writing from unusually organized buffers. This is primarily used * for buffers containing more than one bands raster data in interleaved * format. * * Some formats may efficiently implement decimation into a buffer by * reading from lower resolution overview images. * * For highest performance full resolution data access, read and write * on "block boundaries" as returned by GetBlockSize(), or use the * ReadBlock() and WriteBlock() methods. * * This method is the same as the C GDALRasterIO() function. * * @param eRWFlag Either GF_Read to read a region of data, or GF_Write to * write a region of data. * * @param nXOff The pixel offset to the top left corner of the region * of the band to be accessed. This would be zero to start from the left side. * * @param nYOff The line offset to the top left corner of the region * of the band to be accessed. This would be zero to start from the top. * * @param nXSize The width of the region of the band to be accessed in pixels. * * @param nYSize The height of the region of the band to be accessed in lines. * * @param pData The buffer into which the data should be read, or from which * it should be written. This buffer must contain at least nBufXSize * * nBufYSize words of type eBufType. It is organized in left to right, * top to bottom pixel order. Spacing is controlled by the nPixelSpace, * and nLineSpace parameters. * * @param nBufXSize the width of the buffer image into which the desired region is * to be read, or from which it is to be written. * * @param nBufYSize the height of the buffer image into which the desired region is * to be read, or from which it is to be written. * * @param eBufType the type of the pixel values in the pData data buffer. The * pixel values will automatically be translated to/from the GDALRasterBand * data type as needed. * * @param nPixelSpace The byte offset from the start of one pixel value in * pData to the start of the next pixel value within a scanline. If defaulted * (0) the size of the datatype eBufType is used. * * @param nLineSpace The byte offset from the start of one scanline in * pData to the start of the next. If defaulted the size of the datatype * eBufType * nBufXSize is used. * * @return CE_Failure if the access fails, otherwise CE_None. */ CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nPixelSpace, int nLineSpace ) { /* -------------------------------------------------------------------- */ /* Some size values are "noop". Lets just return to avoid */ /* stressing lower level functions. */ /* -------------------------------------------------------------------- */ if( nXSize < 1 || nYSize < 1 || nBufXSize < 1 || nBufYSize < 1 ) { CPLDebug( "GDAL", "RasterIO() skipped for odd window or buffer size.\n" " Window = (%d,%d)x%dx%d\n" " Buffer = %dx%d\n", nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize ); return CE_None; } /* -------------------------------------------------------------------- */ /* If pixel and line spaceing are defaulted assign reasonable */ /* value assuming a packed buffer. */ /* -------------------------------------------------------------------- */ if( nPixelSpace == 0 ) nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8; if( nLineSpace == 0 ) nLineSpace = nPixelSpace * nBufXSize; /* -------------------------------------------------------------------- */ /* Do some validation of parameters. */ /* -------------------------------------------------------------------- */ if( nXOff < 0 || nXOff + nXSize > nRasterXSize || nYOff < 0 || nYOff + nYSize > nRasterYSize ) { CPLError( CE_Failure, CPLE_IllegalArg, "Access window out of range in RasterIO(). Requested\n" "(%d,%d) of size %dx%d on raster of %dx%d.", nXOff, nYOff, nXSize, nYSize, nRasterXSize, nRasterYSize ); return CE_Failure; } if( eRWFlag != GF_Read && eRWFlag != GF_Write ) { CPLError( CE_Failure, CPLE_IllegalArg, "eRWFlag = %d, only GF_Read (0) and GF_Write (1) are legal.", eRWFlag ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Call the format specific function. */ /* -------------------------------------------------------------------- */ if( bForceCachedIO ) return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace ); else return IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace ) ; } /************************************************************************/ /* GDALRasterIO() */ /************************************************************************/ /** * @see GDALRasterBand::Rasterio() */ CPLErr CPL_STDCALL GDALRasterIO( GDALRasterBandH hBand, GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nPixelSpace, int nLineSpace ) { GDALRasterBand *poBand = (GDALRasterBand *) hBand; return( poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace ) ); } /************************************************************************/ /* ReadBlock() */ /************************************************************************/ /** * Read a block of image data efficiently. * * This method accesses a "natural" block from the raster band without * resampling, or data type conversion. For a more generalized, but * potentially less efficient access use RasterIO(). * * This method is the same as the C GDALReadBlock() function. * * See the GetLockedBlockRef() method for a way of accessing internally cached * block oriented data without an extra copy into an application buffer. * * @param nXBlockOff the horizontal block offset, with zero indicating * the left most block, 1 the next block and so forth. * * @param nYBlockOff the vertical block offset, with zero indicating * the left most block, 1 the next block and so forth. * * @param pImage the buffer into which the data will be read. The buffer * must be large enough to hold GetBlockXSize()*GetBlockYSize() words * of type GetRasterDataType(). * * @return CE_None on success or CE_Failure on an error. * * The following code would efficiently compute a histogram of eight bit * raster data. Note that the final block may be partial ... data beyond * the edge of the underlying raster band in these edge blocks is of an * undermined value. *
CPLErr GetHistogram( GDALRasterBand *poBand, int *panHistogram )
{
int nXBlocks, nYBlocks, nXBlockSize, nYBlockSize;
int iXBlock, iYBlock;
GByte *pabyData;
memset( panHistogram, 0, sizeof(int) * 256 );
CPLAssert( poBand->GetRasterDataType() == GDT_Byte );
poBand->GetBlockSize( &nXBlockSize, &nYBlockSize );
nXBlocks = (poBand->GetXSize() + nXBlockSize - 1) / nXBlockSize;
nYBlocks = (poBand->GetYSize() + nYBlockSize - 1) / nYBlockSize;
pabyData = (GByte *) CPLMalloc(nXBlockSize * nYBlockSize);
for( iYBlock = 0; iYBlock < nYBlocks; iYBlock++ )
{
for( iXBlock = 0; iXBlock < nXBlocks; iXBlock++ )
{
int nXValid, nYValid;
poBand->ReadBlock( iXBlock, iYBlock, pabyData );
// Compute the portion of the block that is valid
// for partial edge blocks.
if( (iXBlock+1) * nXBlockSize > poBand->GetXSize() )
nXValid = poBand->GetXSize() - iXBlock * nXBlockSize;
else
nXValid = nXBlockSize;
if( (iYBlock+1) * nYBlockSize > poBand->GetYSize() )
nYValid = poBand->GetYSize() - iYBlock * nYBlockSize;
else
nYValid = nYBlockSize;
// Collect the histogram counts.
for( int iY = 0; iY < nYValid; iY++ )
{
for( int iX = 0; iX < nXValid; iX++ )
{
panHistogram[pabyData[iX + iY * nXBlockSize]] += 1;
}
}
}
}
}
*/
CPLErr GDALRasterBand::ReadBlock( int nXBlockOff, int nYBlockOff,
void * pImage )
{
/* -------------------------------------------------------------------- */
/* Validate arguments. */
/* -------------------------------------------------------------------- */
CPLAssert( pImage != NULL );
if( nXBlockOff < 0
|| nXBlockOff*nBlockXSize >= nRasterXSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nXBlockOff value (%d) in "
"GDALRasterBand::ReadBlock()\n",
nXBlockOff );
return( CE_Failure );
}
if( nYBlockOff < 0
|| nYBlockOff*nBlockYSize >= nRasterYSize )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nYBlockOff value (%d) in "
"GDALRasterBand::ReadBlock()\n",
nYBlockOff );
return( CE_Failure );
}
if( !InitBlockInfo() )
return CE_Failure;
/* -------------------------------------------------------------------- */
/* Invoke underlying implementation method. */
/* -------------------------------------------------------------------- */
return( IReadBlock( nXBlockOff, nYBlockOff, pImage ) );
}
/************************************************************************/
/* GDALReadBlock() */
/************************************************************************/
/**
* @see GDALRasterBand::ReadBlock()
*/
CPLErr CPL_STDCALL GDALReadBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
void * pData )
{
GDALRasterBand *poBand = (GDALRasterBand *) hBand;
return( poBand->ReadBlock( nXOff, nYOff, pData ) );
}
/************************************************************************/
/* IWriteBlock() */
/* */
/* Default internal implementation ... to be overriden by */
/* subclasses that support writing. */
/************************************************************************/
CPLErr GDALRasterBand::IWriteBlock( int, int, void * )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"WriteBlock() not supported for this dataset." );
return( CE_Failure );
}
/************************************************************************/
/* WriteBlock() */
/************************************************************************/
/**
* Write a block of image data efficiently.
*
* This method accesses a "natural" block from the raster band without
* resampling, or data type conversion. For a more generalized, but
* potentially less efficient access use RasterIO().
*
* This method is the same as the C GDALWriteBlock() function.
*
* See ReadBlock() for an example of block oriented data access.
*
* @param nXBlockOff the horizontal block offset, with zero indicating
* the left most block, 1 the next block and so forth.
*
* @param nYBlockOff the vertical block offset, with zero indicating
* the left most block, 1 the next block and so forth.
*
* @param pImage the buffer from which the data will be written. The buffer
* must be large enough to hold GetBlockXSize()*GetBlockYSize() words
* of type GetRasterDataType().
*
* @return CE_None on success or CE_Failure on an error.
*
* The following code would efficiently compute a histogram of eight bit
* raster data. Note that the final block may be partial ... data beyond
* the edge of the underlying raster band in these edge blocks is of an
* undermined value.
*
*/
CPLErr GDALRasterBand::WriteBlock( int nXBlockOff, int nYBlockOff,
void * pImage )
{
/* -------------------------------------------------------------------- */
/* Validate arguments. */
/* -------------------------------------------------------------------- */
CPLAssert( pImage != NULL );
if( nXBlockOff < 0
|| nXBlockOff*nBlockXSize >= GetXSize() )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nXBlockOff value (%d) in "
"GDALRasterBand::WriteBlock()\n",
nXBlockOff );
return( CE_Failure );
}
if( nYBlockOff < 0
|| nYBlockOff*nBlockYSize >= GetYSize() )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nYBlockOff value (%d) in "
"GDALRasterBand::WriteBlock()\n",
nYBlockOff );
return( CE_Failure );
}
if( eAccess == GA_ReadOnly )
{
CPLError( CE_Failure, CPLE_NoWriteAccess,
"Attempt to write to read only dataset in"
"GDALRasterBand::WriteBlock().\n" );
return( CE_Failure );
}
if( !InitBlockInfo() )
return CE_Failure;
/* -------------------------------------------------------------------- */
/* Invoke underlying implementation method. */
/* -------------------------------------------------------------------- */
return( IWriteBlock( nXBlockOff, nYBlockOff, pImage ) );
}
/************************************************************************/
/* GDALWriteBlock() */
/************************************************************************/
/**
* @see GDALRasterBand::WriteBlock()
*/
CPLErr CPL_STDCALL GDALWriteBlock( GDALRasterBandH hBand, int nXOff, int nYOff,
void * pData )
{
GDALRasterBand *poBand = (GDALRasterBand *) hBand;
return( poBand->WriteBlock( nXOff, nYOff, pData ) );
}
/************************************************************************/
/* GetRasterDataType() */
/************************************************************************/
/**
* Fetch the pixel data type for this band.
*
* @return the data type of pixels for this band.
*/
GDALDataType GDALRasterBand::GetRasterDataType()
{
return eDataType;
}
/************************************************************************/
/* GDALGetRasterDataType() */
/************************************************************************/
/**
* @see GDALRasterBand::GetRasterDataType()
*/
GDALDataType CPL_STDCALL GDALGetRasterDataType( GDALRasterBandH hBand )
{
return( ((GDALRasterBand *) hBand)->GetRasterDataType() );
}
/************************************************************************/
/* GetBlockSize() */
/************************************************************************/
/**
* Fetch the "natural" block size of this band.
*
* GDAL contains a concept of the natural block size of rasters so that
* applications can organized data access efficiently for some file formats.
* The natural block size is the block size that is most efficient for
* accessing the format. For many formats this is simple a whole scanline
* in which case *pnXSize is set to GetXSize(), and *pnYSize is set to 1.
*
* However, for tiled images this will typically be the tile size.
*
* Note that the X and Y block sizes don't have to divide the image size
* evenly, meaning that right and bottom edge blocks may be incomplete.
* See ReadBlock() for an example of code dealing with these issues.
*
* @param pnXSize integer to put the X block size into or NULL.
*
* @param pnYSize integer to put the Y block size into or NULL.
*/
void GDALRasterBand::GetBlockSize( int * pnXSize, int *pnYSize )
{
CPLAssert( nBlockXSize > 0 && nBlockYSize > 0 );
if( pnXSize != NULL )
*pnXSize = nBlockXSize;
if( pnYSize != NULL )
*pnYSize = nBlockYSize;
}
/************************************************************************/
/* GDALGetBlockSize() */
/************************************************************************/
/**
* @see GDALRasterBand::GetBlockSize()
*/
void CPL_STDCALL
GDALGetBlockSize( GDALRasterBandH hBand, int * pnXSize, int * pnYSize )
{
GDALRasterBand *poBand = (GDALRasterBand *) hBand;
poBand->GetBlockSize( pnXSize, pnYSize );
}
/************************************************************************/
/* InitBlockInfo() */
/************************************************************************/
int GDALRasterBand::InitBlockInfo()
{
if( papoBlocks != NULL )
return TRUE;
CPLAssert( nBlockXSize > 0 && nBlockYSize > 0 );
nBlocksPerRow = (nRasterXSize+nBlockXSize-1) / nBlockXSize;
nBlocksPerColumn = (nRasterYSize+nBlockYSize-1) / nBlockYSize;
if( nBlocksPerRow < SUBBLOCK_SIZE/2 )
{
bSubBlockingActive = FALSE;
papoBlocks = (GDALRasterBlock **)
VSICalloc( sizeof(void*), nBlocksPerRow * nBlocksPerColumn );
}
else
{
bSubBlockingActive = TRUE;
nSubBlocksPerRow = (nBlocksPerRow + SUBBLOCK_SIZE + 1)/SUBBLOCK_SIZE;
nSubBlocksPerColumn = (nBlocksPerColumn + SUBBLOCK_SIZE + 1)/SUBBLOCK_SIZE;
papoBlocks = (GDALRasterBlock **)
VSICalloc( sizeof(void*), nSubBlocksPerRow * nSubBlocksPerColumn );
}
if( papoBlocks == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory in InitBlockInfo()." );
return FALSE;
}
return TRUE;
}
/************************************************************************/
/* AdoptBlock() */
/* */
/* Add a block to the raster band's block matrix. If this */
/* exceeds our maximum blocks for this layer, flush the oldest */
/* block out. */
/* */
/* This method is protected. */
/************************************************************************/
CPLErr GDALRasterBand::AdoptBlock( int nXBlockOff, int nYBlockOff,
GDALRasterBlock * poBlock )
{
int nBlockIndex;
InitBlockInfo();
/* -------------------------------------------------------------------- */
/* Simple case without subblocking. */
/* -------------------------------------------------------------------- */
if( !bSubBlockingActive )
{
nBlockIndex = nXBlockOff + nYBlockOff * nBlocksPerRow;
if( papoBlocks[nBlockIndex] == poBlock )
return( CE_None );
if( papoBlocks[nBlockIndex] != NULL )
FlushBlock( nXBlockOff, nYBlockOff );
papoBlocks[nBlockIndex] = poBlock;
poBlock->Touch();
return( CE_None );
}
/* -------------------------------------------------------------------- */
/* Identify the subblock in which our target occurs, and create */
/* it if necessary. */
/* -------------------------------------------------------------------- */
int nSubBlock = TO_SUBBLOCK(nXBlockOff)
+ TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
if( papoBlocks[nSubBlock] == NULL )
{
int nSubGridSize =
sizeof(GDALRasterBlock*) * SUBBLOCK_SIZE * SUBBLOCK_SIZE;
papoBlocks[nSubBlock] = (GDALRasterBlock *) VSIMalloc(nSubGridSize);
if( papoBlocks[nSubBlock] == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory in AdoptBlock()." );
return CE_Failure;
}
memset( papoBlocks[nSubBlock], 0, nSubGridSize );
}
/* -------------------------------------------------------------------- */
/* Check within subblock. */
/* -------------------------------------------------------------------- */
GDALRasterBlock **papoSubBlockGrid =
(GDALRasterBlock **) papoBlocks[nSubBlock];
int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
+ WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
if( papoSubBlockGrid[nBlockInSubBlock] == poBlock )
return CE_None;
if( papoSubBlockGrid[nBlockInSubBlock] != NULL )
FlushBlock( nXBlockOff, nYBlockOff );
papoSubBlockGrid[nBlockInSubBlock] = poBlock;
poBlock->Touch();
return CE_None;
}
/************************************************************************/
/* FlushCache() */
/************************************************************************/
/**
* Flush raster data cache.
*
* This call will recover memory used to cache data blocks for this raster
* band, and ensure that new requests are referred to the underlying driver.
*
* This method is the same as the C function GDALFlushRasterCache().
*
* @return CE_None on success.
*/
CPLErr GDALRasterBand::FlushCache()
{
/* -------------------------------------------------------------------- */
/* Flush all blocks in memory ... this case is without subblocking.*/
/* -------------------------------------------------------------------- */
if( !bSubBlockingActive )
{
for( int iY = 0; iY < nBlocksPerColumn; iY++ )
{
for( int iX = 0; iX < nBlocksPerRow; iX++ )
{
if( papoBlocks[iX + iY*nBlocksPerRow] != NULL )
{
CPLErr eErr;
eErr = FlushBlock( iX, iY );
if( eErr != CE_None )
return eErr;
}
}
}
return CE_None;
}
/* -------------------------------------------------------------------- */
/* With subblocking. We can short circuit missing subblocks. */
/* -------------------------------------------------------------------- */
int iSBX, iSBY;
for( iSBY = 0; iSBY < nSubBlocksPerColumn; iSBY++ )
{
for( iSBX = 0; iSBX < nSubBlocksPerRow; iSBX++ )
{
int nSubBlock = iSBX + iSBY * nSubBlocksPerRow;
GDALRasterBlock **papoSubBlockGrid =
(GDALRasterBlock **) papoBlocks[nSubBlock];
if( papoSubBlockGrid == NULL )
continue;
for( int iY = 0; iY < SUBBLOCK_SIZE; iY++ )
{
for( int iX = 0; iX < SUBBLOCK_SIZE; iX++ )
{
if( papoSubBlockGrid[iX + iY * SUBBLOCK_SIZE] != NULL )
{
CPLErr eErr;
eErr = FlushBlock( iX + iSBX * SUBBLOCK_SIZE,
iY + iSBY * SUBBLOCK_SIZE );
if( eErr != CE_None )
return eErr;
}
}
}
// We might as well get rid of this grid chunk since we know
// it is now empty.
papoBlocks[nSubBlock] = NULL;
CPLFree( papoSubBlockGrid );
}
}
return( CE_None );
}
/************************************************************************/
/* GDALFlushRasterCache() */
/************************************************************************/
/**
* @see GDALRasterBand::FlushCache()
*/
CPLErr CPL_STDCALL GDALFlushRasterCache( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->FlushCache();
}
/************************************************************************/
/* FlushBlock() */
/* */
/* Flush a block out of the block cache. If it has been */
/* modified write it to disk. If no specific tile is */
/* indicated, write the oldest tile. */
/* */
/* Protected method. */
/************************************************************************/
CPLErr GDALRasterBand::FlushBlock( int nXBlockOff, int nYBlockOff )
{
int nBlockIndex;
GDALRasterBlock *poBlock;
if( !papoBlocks )
return CE_None;
/* -------------------------------------------------------------------- */
/* Validate the request */
/* -------------------------------------------------------------------- */
if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nBlockXOff value (%d) in "
"GDALRasterBand::FlushBlock()\n",
nXBlockOff );
return( CE_Failure );
}
if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nBlockYOff value (%d) in "
"GDALRasterBand::FlushBlock()\n",
nYBlockOff );
return( CE_Failure );
}
/* -------------------------------------------------------------------- */
/* Simple case for single level caches. */
/* -------------------------------------------------------------------- */
if( !bSubBlockingActive )
{
nBlockIndex = nXBlockOff + nYBlockOff * nBlocksPerRow;
GDALRasterBlock::SafeLockBlock( papoBlocks + nBlockIndex );
poBlock = papoBlocks[nBlockIndex];
papoBlocks[nBlockIndex] = NULL;
}
/* -------------------------------------------------------------------- */
/* Identify our subblock. */
/* -------------------------------------------------------------------- */
else
{
int nSubBlock = TO_SUBBLOCK(nXBlockOff)
+ TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
if( papoBlocks[nSubBlock] == NULL )
return CE_None;
/* -------------------------------------------------------------------- */
/* Check within subblock. */
/* -------------------------------------------------------------------- */
GDALRasterBlock **papoSubBlockGrid =
(GDALRasterBlock **) papoBlocks[nSubBlock];
int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
+ WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
GDALRasterBlock::SafeLockBlock( papoSubBlockGrid + nBlockInSubBlock );
poBlock = papoSubBlockGrid[nBlockInSubBlock];
papoSubBlockGrid[nBlockInSubBlock] = NULL;
}
/* -------------------------------------------------------------------- */
/* Is the target block dirty? If so we need to write it. */
/* -------------------------------------------------------------------- */
if( poBlock == NULL )
return CE_None;
poBlock->Detach();
if( poBlock->GetDirty() )
poBlock->Write();
/* -------------------------------------------------------------------- */
/* Deallocate the block; */
/* -------------------------------------------------------------------- */
poBlock->DropLock();
delete poBlock;
return( CE_None );
}
/************************************************************************/
/* TryGetLockedBlockRef() */
/************************************************************************/
/**
* Try fetching block ref.
*
* This method will returned the requested block (locked) if it is already
* in the block cache for the layer. If not, NULL is returned.
*
* If a non-NULL value is returned, then a lock for the block will have been
* acquired on behalf of the caller. It is absolutely imperative that the
* caller release this lock (with GDALRasterBlock::DropLock()) or else
* severe problems may result.
*
* @param nBlockXOff the horizontal block offset, with zero indicating
* the left most block, 1 the next block and so forth.
*
* @param nYBlockOff the vertical block offset, with zero indicating
* the top most block, 1 the next block and so forth.
*
* @return NULL if block not available, or locked block pointer.
*/
GDALRasterBlock *GDALRasterBand::TryGetLockedBlockRef( int nXBlockOff,
int nYBlockOff )
{
int nBlockIndex;
InitBlockInfo();
/* -------------------------------------------------------------------- */
/* Validate the request */
/* -------------------------------------------------------------------- */
if( nXBlockOff < 0 || nXBlockOff >= nBlocksPerRow )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nBlockXOff value (%d) in "
"GDALRasterBand::TryGetLockedBlockRef()\n",
nXBlockOff );
return( NULL );
}
if( nYBlockOff < 0 || nYBlockOff >= nBlocksPerColumn )
{
CPLError( CE_Failure, CPLE_IllegalArg,
"Illegal nBlockYOff value (%d) in "
"GDALRasterBand::TryGetLockedBlockRef()\n",
nYBlockOff );
return( NULL );
}
/* -------------------------------------------------------------------- */
/* Simple case for single level caches. */
/* -------------------------------------------------------------------- */
if( !bSubBlockingActive )
{
nBlockIndex = nXBlockOff + nYBlockOff * nBlocksPerRow;
GDALRasterBlock::SafeLockBlock( papoBlocks + nBlockIndex );
return papoBlocks[nBlockIndex];
}
/* -------------------------------------------------------------------- */
/* Identify our subblock. */
/* -------------------------------------------------------------------- */
int nSubBlock = TO_SUBBLOCK(nXBlockOff)
+ TO_SUBBLOCK(nYBlockOff) * nSubBlocksPerRow;
if( papoBlocks[nSubBlock] == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Check within subblock. */
/* -------------------------------------------------------------------- */
GDALRasterBlock **papoSubBlockGrid =
(GDALRasterBlock **) papoBlocks[nSubBlock];
int nBlockInSubBlock = WITHIN_SUBBLOCK(nXBlockOff)
+ WITHIN_SUBBLOCK(nYBlockOff) * SUBBLOCK_SIZE;
GDALRasterBlock::SafeLockBlock( papoSubBlockGrid + nBlockInSubBlock );
return papoSubBlockGrid[nBlockInSubBlock];
}
/************************************************************************/
/* GetLockedBlockRef() */
/************************************************************************/
/**
* Fetch a pointer to an internally cached raster block.
*
* This method will returned the requested block (locked) if it is already
* in the block cache for the layer. If not, the block will be read from
* the driver, and placed in the layer block cached, then returned. If an
* error occurs reading the block from the driver, a NULL value will be
* returned.
*
* If a non-NULL value is returned, then a lock for the block will have been
* acquired on behalf of the caller. It is absolutely imperative that the
* caller release this lock (with GDALRasterBlock::DropLock()) or else
* severe problems may result.
*
* Note that calling GetLockedBlockRef() on a previously uncached band will
* enable caching.
*
* @param nBlockXOff the horizontal block offset, with zero indicating
* the left most block, 1 the next block and so forth.
*
* @param nYBlockOff the vertical block offset, with zero indicating
* the top most block, 1 the next block and so forth.
*
* @param bJustInitialize If TRUE the block will be allocated and initialized,
* but not actually read from the source. This is useful when it will just
* be completely set and written back.
*
* @return pointer to the block object, or NULL on failure.
*/
GDALRasterBlock * GDALRasterBand::GetLockedBlockRef( int nXBlockOff,
int nYBlockOff,
int bJustInitialize )
{
GDALRasterBlock *poBlock;
/* -------------------------------------------------------------------- */
/* Try and fetch from cache. */
/* -------------------------------------------------------------------- */
poBlock = TryGetLockedBlockRef( nXBlockOff, nYBlockOff );
/* -------------------------------------------------------------------- */
/* If we didn't find it in our memory cache, instantiate a */
/* block (potentially load from disk) and "adopt" it into the */
/* cache. */
/* -------------------------------------------------------------------- */
if( poBlock == NULL )
{
poBlock = new GDALRasterBlock( this, nXBlockOff, nYBlockOff );
poBlock->AddLock();
/* allocate data space */
if( poBlock->Internalize() != CE_None )
{
poBlock->DropLock();
delete poBlock;
return( NULL );
}
AdoptBlock( nXBlockOff, nYBlockOff, poBlock );
if( !bJustInitialize
&& IReadBlock(nXBlockOff,nYBlockOff,poBlock->GetDataRef()) != CE_None)
{
poBlock->DropLock();
FlushBlock( nXBlockOff, nYBlockOff );
CPLError( CE_Failure, CPLE_AppDefined,
"IReadBlock failed at X offset %d, Y offset %d",
nXBlockOff, nYBlockOff );
return( NULL );
}
if( !bJustInitialize )
{
nBlockReads++;
if( nBlockReads == nBlocksPerRow * nBlocksPerColumn + 1
&& nBand == 1 && poDS != NULL )
{
CPLDebug( "GDAL", "Potential thrashing on band %d of %s.",
nBand, poDS->GetDescription() );
}
}
}
return poBlock;
}
/************************************************************************/
/* Fill() */
/************************************************************************/
/**
* Fill this band with a constant value. GDAL makes no guarantees
* about what values pixels in newly created files are set to, so this
* method can be used to clear a band to a specified "default" value.
* The fill value is passed in as a double but this will be converted
* to the underlying type before writing to the file. An optional
* second argument allows the imaginary component of a complex
* constant value to be specified.
*
* @param dfRealvalue Real component of fill value
* @param dfImaginaryValue Imaginary component of fill value, defaults to zero
*
* @return CE_Failure if the write fails, otherwise CE_None
*/
CPLErr GDALRasterBand::Fill(double dfRealValue, double dfImaginaryValue) {
// General approach is to construct a source block of the file's
// native type containing the appropriate value and then copy this
// to each block in the image via the the RasterBlock cache. Using
// the cache means we avoid file I/O if it's not necessary, at the
// expense of some extra memcpy's (since we write to the
// RasterBlock cache, which is then at some point written to the
// underlying file, rather than simply directly to the underlying
// file.)
// Check we can write to the file
if( eAccess == GA_ReadOnly ) {
CPLError(CE_Failure, CPLE_NoWriteAccess,
"Attempt to write to read only dataset in"
"GDALRasterBand::Fill().\n" );
return CE_Failure;
}
// Make sure block parameters are set
InitBlockInfo();
// Allocate the source block
int blockSize = nBlockXSize * nBlockYSize;
int elementSize = GDALGetDataTypeSize(eDataType) / 8;
int blockByteSize = blockSize * elementSize;
unsigned char* srcBlock = (unsigned char*) VSIMalloc(blockByteSize);
if (srcBlock == NULL) {
CPLError(CE_Failure, CPLE_OutOfMemory,
"GDALRasterBand::Fill(): Out of memory "
"allocating %d bytes.\n", blockByteSize);
return CE_Failure;
}
// Initialize the first element of the block, doing type conversion
double complexSrc[2] = { dfRealValue, dfImaginaryValue };
GDALCopyWords(complexSrc, GDT_CFloat64, 0, srcBlock, eDataType, 0, 1);
// Copy first element to the rest of the block
for (unsigned char* blockPtr = srcBlock + elementSize;
blockPtr < srcBlock + blockByteSize; blockPtr += elementSize) {
memcpy(blockPtr, srcBlock, elementSize);
}
// Write block to block cache
for (int j = 0; j < nBlocksPerColumn; ++j) {
for (int i = 0; i < nBlocksPerRow; ++i) {
GDALRasterBlock* destBlock = GetLockedBlockRef(i, j, TRUE);
if (destBlock == NULL) {
CPLError(CE_Failure, CPLE_OutOfMemory,
"GDALRasterBand::Fill(): Error "
"while retrieving cache block.\n");
return CE_Failure;
}
memcpy(destBlock->GetDataRef(), srcBlock, blockByteSize);
destBlock->MarkDirty();
destBlock->DropLock();
}
}
// Free up the source block
VSIFree(srcBlock);
return CE_None;
}
/************************************************************************/
/* GDALFillRaster() */
/************************************************************************/
/**
* Fill this band with a constant value. Set \a dfImaginaryValue to
* zero non-complex rasters.
*
* @param dfRealvalue Real component of fill value
* @param dfImaginaryValue Imaginary component of fill value
*
* @see GDALRasterBand::Fill()
*
* @return CE_Failure if the write fails, otherwise CE_None
*/
CPLErr CPL_STDCALL GDALFillRaster(GDALRasterBandH hBand, double dfRealValue,
double dfImaginaryValue) {
return ((GDALRasterBand*) hBand)->Fill(dfRealValue, dfImaginaryValue);
}
/************************************************************************/
/* GetAccess() */
/************************************************************************/
/**
* Find out if we have update permission for this band.
*
* This method is the same as the C function GDALGetRasterAccess().
*
* @return Either GA_Update or GA_ReadOnly.
*/
GDALAccess GDALRasterBand::GetAccess()
{
return eAccess;
}
/************************************************************************/
/* GDALGetRasterAccess() */
/************************************************************************/
/**
* @see GDALRasterBand::GetAccess()
*/
GDALAccess CPL_STDCALL GDALGetRasterAccess( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetAccess();
}
/************************************************************************/
/* GetCategoryNames() */
/************************************************************************/
/**
* Fetch the list of category names for this raster.
*
* The return list is a "StringList" in the sense of the CPL functions.
* That is a NULL terminated array of strings. Raster values without
* associated names will have an empty string in the returned list. The
* first entry in the list is for raster values of zero, and so on.
*
* The returned stringlist should not be altered or freed by the application.
* It may change on the next GDAL call, so please copy it if it is needed
* for any period of time.
*
* @return list of names, or NULL if none.
*/
char **GDALRasterBand::GetCategoryNames()
{
return NULL;
}
/************************************************************************/
/* GDALGetRasterCategoryNames() */
/************************************************************************/
/**
* @see GDALRasterBand::GetCategoryNames()
*/
char ** CPL_STDCALL GDALGetRasterCategoryNames( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetCategoryNames();
}
/************************************************************************/
/* SetCategoryNames() */
/************************************************************************/
/**
* Set the category names for this band.
*
* See the GetCategoryNames() method for more on the interpretation of
* category names.
*
* This method is the same as the C function GDALSetRasterCategoryNames().
*
* @param papszNames the NULL terminated StringList of category names. May
* be NULL to just clear the existing list.
*
* @return CE_None on success of CE_Failure on failure. If unsupported
* by the driver CE_Failure is returned, but no error message is reported.
*/
CPLErr GDALRasterBand::SetCategoryNames( char ** )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetCategoryNames() not supported for this dataset." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetCategoryNames() */
/************************************************************************/
/**
* @see GDALRasterBand::SetCategoryNames()
*/
CPLErr CPL_STDCALL
GDALSetRasterCategoryNames( GDALRasterBandH hBand, char ** papszNames )
{
return ((GDALRasterBand *) hBand)->SetCategoryNames( papszNames );
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
/**
* Fetch the no data value for this band.
*
* If there is no out of data value, an out of range value will generally
* be returned. The no data value for a band is generally a special marker
* value used to mark pixels that are not valid data. Such pixels should
* generally not be displayed, nor contribute to analysis operations.
*
* This method is the same as the C function GDALGetRasterNoDataValue().
*
* @param pbSuccess pointer to a boolean to use to indicate if a value
* is actually associated with this layer. May be NULL (default).
*
* @return the nodata value for this band.
*/
double GDALRasterBand::GetNoDataValue( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = FALSE;
return -1e10;
}
/************************************************************************/
/* GDALGetRasterNoDataValue() */
/************************************************************************/
/**
* @see GDALRasterBand::GetNoDataValue()
*/
double CPL_STDCALL
GDALGetRasterNoDataValue( GDALRasterBandH hBand, int *pbSuccess )
{
return ((GDALRasterBand *) hBand)->GetNoDataValue( pbSuccess );
}
/************************************************************************/
/* SetNoDataValue() */
/************************************************************************/
/**
* Set the no data value for this band.
*
* To clear the nodata value, just set it with an "out of range" value.
* Complex band no data values must have an imagery component of zero.
*
* This method is the same as the C function GDALSetRasterNoDataValue().
*
* @param dfNoData the value to set.
*
* @return CE_None on success, or CE_Failure on failure. If unsupported
* by the driver, CE_Failure is returned by no error message will have
* been emitted.
*/
CPLErr GDALRasterBand::SetNoDataValue( double )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetNoDataValue() not supported for this dataset." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetRasterNoDataValue() */
/************************************************************************/
/**
* @see GDALRasterBand::SetNoDataValue()
*/
CPLErr CPL_STDCALL
GDALSetRasterNoDataValue( GDALRasterBandH hBand, double dfValue )
{
return ((GDALRasterBand *) hBand)->SetNoDataValue( dfValue );
}
/************************************************************************/
/* GetMaximum() */
/************************************************************************/
/**
* Fetch the maximum value for this band.
*
* For file formats that don't know this intrinsically, the maximum supported
* value for the data type will generally be returned.
*
* This method is the same as the C function GDALGetRasterMaximum().
*
* @param pbSuccess pointer to a boolean to use to indicate if the
* returned value is a tight maximum or not. May be NULL (default).
*
* @return the maximum raster value (excluding no data pixels)
*/
double GDALRasterBand::GetMaximum( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = FALSE;
switch( eDataType )
{
case GDT_Byte:
return 255;
case GDT_UInt16:
return 65535;
case GDT_Int16:
case GDT_CInt16:
return 32767;
case GDT_Int32:
case GDT_CInt32:
return 2147483647.0;
case GDT_UInt32:
return 4294967295.0;
case GDT_Float32:
case GDT_CFloat32:
return 4294967295.0; /* not actually accurate */
case GDT_Float64:
case GDT_CFloat64:
return 4294967295.0; /* not actually accurate */
default:
return 4294967295.0; /* not actually accurate */
}
}
/************************************************************************/
/* GDALGetRasterMaximum() */
/************************************************************************/
/**
* @see GDALRasterBand::GetMaximum()
*/
double CPL_STDCALL
GDALGetRasterMaximum( GDALRasterBandH hBand, int *pbSuccess )
{
return ((GDALRasterBand *) hBand)->GetMaximum( pbSuccess );
}
/************************************************************************/
/* GetMinimum() */
/************************************************************************/
/**
* Fetch the minimum value for this band.
*
* For file formats that don't know this intrinsically, the minimum supported
* value for the data type will generally be returned.
*
* This method is the same as the C function GDALGetRasterMinimum().
*
* @param pbSuccess pointer to a boolean to use to indicate if the
* returned value is a tight minimum or not. May be NULL (default).
*
* @return the minimum raster value (excluding no data pixels)
*/
double GDALRasterBand::GetMinimum( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = FALSE;
switch( eDataType )
{
case GDT_Byte:
return 0;
case GDT_UInt16:
return 0;
case GDT_Int16:
return -32768;
case GDT_Int32:
return -2147483648.0;
case GDT_UInt32:
return 0;
case GDT_Float32:
return -4294967295.0; /* not actually accurate */
case GDT_Float64:
return -4294967295.0; /* not actually accurate */
default:
return -4294967295.0; /* not actually accurate */
}
}
/************************************************************************/
/* GDALGetRasterMinimum() */
/************************************************************************/
/**
* @see GDALRasterBand::GetMinimum()
*/
double CPL_STDCALL
GDALGetRasterMinimum( GDALRasterBandH hBand, int *pbSuccess )
{
return ((GDALRasterBand *) hBand)->GetMinimum( pbSuccess );
}
/************************************************************************/
/* GetColorInterpretation() */
/************************************************************************/
/**
* How should this band be interpreted as color?
*
* CV_Undefined is returned when the format doesn't know anything
* about the color interpretation.
*
* This method is the same as the C function
* GDALGetRasterColorInterpretation().
*
* @return color interpretation value for band.
*/
GDALColorInterp GDALRasterBand::GetColorInterpretation()
{
return GCI_Undefined;
}
/************************************************************************/
/* GDALGetRasterColorInterpretation() */
/************************************************************************/
/**
* @see GDALRasterBand::GetColorInterpretation()
*/
GDALColorInterp CPL_STDCALL
GDALGetRasterColorInterpretation( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetColorInterpretation();
}
/************************************************************************/
/* SetColorInterpretation() */
/************************************************************************/
/**
* Set color interpretation of a band.
*
* @param eColorInterp the new color interpretation to apply to this band.
*
* @return CE_None on success or CE_Failure if method is unsupported by format.
*/
CPLErr GDALRasterBand::SetColorInterpretation( GDALColorInterp eColorInterp)
{
(void) eColorInterp;
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetColorInterpretation() not supported for this dataset." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetRasterColorInterpretation() */
/************************************************************************/
/**
* @see GDALRasterBand::SetColorInterpretation()
*/
CPLErr CPL_STDCALL
GDALSetRasterColorInterpretation( GDALRasterBandH hBand,
GDALColorInterp eColorInterp )
{
return ((GDALRasterBand *) hBand)->SetColorInterpretation(eColorInterp);
}
/************************************************************************/
/* GetColorTable() */
/************************************************************************/
/**
* Fetch the color table associated with band.
*
* If there is no associated color table, the return result is NULL. The
* returned color table remains owned by the GDALRasterBand, and can't
* be depended on for long, nor should it ever be modified by the caller.
*
* This method is the same as the C function GDALGetRasterColorTable().
*
* @return internal color table, or NULL.
*/
GDALColorTable *GDALRasterBand::GetColorTable()
{
return NULL;
}
/************************************************************************/
/* GDALGetRasterColorTable() */
/************************************************************************/
/**
* @see GDALRasterBand::GetColorTable()
*/
GDALColorTableH CPL_STDCALL GDALGetRasterColorTable( GDALRasterBandH hBand )
{
return (GDALColorTableH) ((GDALRasterBand *) hBand)->GetColorTable();
}
/************************************************************************/
/* SetColorTable() */
/************************************************************************/
/**
* Set the raster color table.
*
* The driver will make a copy of all desired data in the colortable. It
* remains owned by the caller after the call.
*
* This method is the same as the C function GDALSetRasterColorTable().
*
* @param poCT the color table to apply.
*
* @return CE_None on success, or CE_Failure on failure. If the action is
* unsupported by the driver, a value of CE_Failure is returned, but no
* error is issued.
*/
CPLErr GDALRasterBand::SetColorTable( GDALColorTable * poCT )
{
(void) poCT;
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetColorTable() not supported for this dataset." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetRasterColorTable() */
/************************************************************************/
/**
* @see GDALRasterBand::SetColorTable()
*/
CPLErr CPL_STDCALL
GDALSetRasterColorTable( GDALRasterBandH hBand, GDALColorTableH hCT )
{
return ((GDALRasterBand *) hBand)->SetColorTable( (GDALColorTable *) hCT );
}
/************************************************************************/
/* HasArbitraryOverviews() */
/************************************************************************/
/**
* Check for arbitrary overviews.
*
* This returns TRUE if the underlying datastore can compute arbitrary
* overviews efficiently, such as is the case with OGDI over a network.
* Datastores with arbitrary overviews don't generally have any fixed
* overviews, but the RasterIO() method can be used in downsampling mode
* to get overview data efficiently.
*
* This method is the same as the C function GDALHasArbitraryOverviews(),
*
* @return TRUE if arbitrary overviews available (efficiently), otherwise
* FALSE.
*/
int GDALRasterBand::HasArbitraryOverviews()
{
return FALSE;
}
/************************************************************************/
/* GDALHasArbitraryOverviews() */
/************************************************************************/
/**
* @see GDALRasterBand::HasArbitraryOverviews()
*/
int CPL_STDCALL GDALHasArbitraryOverviews( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->HasArbitraryOverviews();
}
/************************************************************************/
/* GetOverviewCount() */
/************************************************************************/
/**
* Return the number of overview layers available.
*
* This method is the same as the C function GDALGetOverviewCount();
*
* @return overview count, zero if none.
*/
int GDALRasterBand::GetOverviewCount()
{
if( poDS != NULL && poDS->oOvManager.IsInitialized() )
return poDS->oOvManager.GetOverviewCount( nBand );
else
return 0;
}
/************************************************************************/
/* GDALGetOverviewCount() */
/************************************************************************/
/**
* @see GDALRasterBand::GetOverviewCount()
*/
int CPL_STDCALL GDALGetOverviewCount( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetOverviewCount();
}
/************************************************************************/
/* GetOverview() */
/************************************************************************/
/**
* Fetch overview raster band object.
*
* This method is the same as the C function GDALGetOverview().
*
* @param i overview index between 0 and GetOverviewCount()-1.
*
* @return overview GDALRasterBand.
*/
GDALRasterBand * GDALRasterBand::GetOverview( int i )
{
if( poDS != NULL && poDS->oOvManager.IsInitialized() )
return poDS->oOvManager.GetOverview( nBand, i );
else
return NULL;
}
/************************************************************************/
/* GDALGetOverview() */
/************************************************************************/
/**
* @see GDALRasterBand::GetOverview()
*/
GDALRasterBandH CPL_STDCALL GDALGetOverview( GDALRasterBandH hBand, int i )
{
return (GDALRasterBandH) ((GDALRasterBand *) hBand)->GetOverview(i);
}
/************************************************************************/
/* BuildOverviews() */
/************************************************************************/
/**
* Build raster overview(s)
*
* If the operation is unsupported for the indicated dataset, then
* CE_Failure is returned, and CPLGetLastErrorNo() will return
* CPLE_NotSupported.
*
* WARNING: It is not possible to build overviews for a single band in
* TIFF format, and thus this method does not work for TIFF format, or any
* formats that use the default overview building in TIFF format. Instead
* it is necessary to build overviews on the dataset as a whole using
* GDALDataset::BuildOverviews(). That makes this method pretty useless
* from a practical point of view.
*
* @param pszResampling one of "NEAREST", "AVERAGE" or "MODE" controlling
* the downsampling method applied.
* @param nOverviews number of overviews to build.
* @param panOverviewList the list of overview decimation factors to build.
* @param pfnProgress a function to call to report progress, or NULL.
* @param pProgressData application data to pass to the progress function.
*
* @return CE_None on success or CE_Failure if the operation doesn't work.
*/
CPLErr GDALRasterBand::BuildOverviews( const char * pszResampling,
int nOverviews,
int * panOverviewList,
GDALProgressFunc pfnProgress,
void * pProgressData )
{
(void) pszResampling;
(void) nOverviews;
(void) panOverviewList;
(void) pfnProgress;
(void) pProgressData;
CPLError( CE_Failure, CPLE_NotSupported,
"BuildOverviews() not supported for this dataset." );
return( CE_Failure );
}
/************************************************************************/
/* GetOffset() */
/************************************************************************/
/**
* Fetch the raster value offset.
*
* This value (in combination with the GetScale() value) is used to
* transform raw pixel values into the units returned by GetUnits().
* For example this might be used to store elevations in GUInt16 bands
* with a precision of 0.1, and starting from -100.
*
* Units value = (raw value * scale) + offset
*
* For file formats that don't know this intrinsically a value of zero
* is returned.
*
* This method is the same as the C function GDALGetRasterOffset().
*
* @param pbSuccess pointer to a boolean to use to indicate if the
* returned value is meaningful or not. May be NULL (default).
*
* @return the raster offset.
*/
double GDALRasterBand::GetOffset( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = FALSE;
return 0.0;
}
/************************************************************************/
/* GDALGetRasterOffset() */
/************************************************************************/
double CPL_STDCALL GDALGetRasterOffset( GDALRasterBandH hBand, int *pbSuccess )
{
return ((GDALRasterBand *) hBand)->GetOffset( pbSuccess );
}
/************************************************************************/
/* SetOffset() */
/************************************************************************/
/**
* Set scaling offset.
*
* Very few formats implement this method. When not implemented it will
* issue a CPLE_NotSupported error and return CE_Failure.
*
* @param dfNewOffset the new offset.
*
* @return CE_None or success or CE_Failure on failure.
*/
CPLErr GDALRasterBand::SetOffset( double dfNewOffset )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetOffset() not supported on this raster band." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetRasterOffset() */
/************************************************************************/
CPLErr CPL_STDCALL
GDALSetRasterOffset( GDALRasterBandH hBand, double dfNewOffset )
{
return ((GDALRasterBand *) hBand)->SetOffset( dfNewOffset );
}
/************************************************************************/
/* GetScale() */
/************************************************************************/
/**
* Fetch the raster value scale.
*
* This value (in combination with the GetOffset() value) is used to
* transform raw pixel values into the units returned by GetUnits().
* For example this might be used to store elevations in GUInt16 bands
* with a precision of 0.1, and starting from -100.
*
* Units value = (raw value * scale) + offset
*
* For file formats that don't know this intrinsically a value of one
* is returned.
*
* This method is the same as the C function GDALGetRasterScale().
*
* @param pbSuccess pointer to a boolean to use to indicate if the
* returned value is meaningful or not. May be NULL (default).
*
* @return the raster scale.
*/
double GDALRasterBand::GetScale( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = FALSE;
return 1.0;
}
/************************************************************************/
/* GDALGetRasterScale() */
/************************************************************************/
double CPL_STDCALL GDALGetRasterScale( GDALRasterBandH hBand, int *pbSuccess )
{
return ((GDALRasterBand *) hBand)->GetScale( pbSuccess );
}
/************************************************************************/
/* SetScale() */
/************************************************************************/
/**
* Set scaling ratio.
*
* Very few formats implement this method. When not implemented it will
* issue a CPLE_NotSupported error and return CE_Failure.
*
* @param dfNewScale the new scale.
*
* @return CE_None or success or CE_Failure on failure.
*/
CPLErr GDALRasterBand::SetScale( double dfNewScale )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetScale() not supported on this raster band." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetRasterScale() */
/************************************************************************/
CPLErr CPL_STDCALL
GDALSetRasterScale( GDALRasterBandH hBand, double dfNewOffset )
{
return ((GDALRasterBand *) hBand)->SetScale( dfNewOffset );
}
/************************************************************************/
/* GetUnitType() */
/************************************************************************/
/**
* Return raster unit type.
*
* Return a name for the units of this raster's values. For instance, it
* might be "m" for an elevation model in meters, or "ft" for feet. If no
* units are available, a value of "" will be returned. The returned string
* should not be modified, nor freed by the calling application.
*
* This method is the same as the C function GDALGetRasterUnitType().
*
* @return unit name string.
*/
const char *GDALRasterBand::GetUnitType()
{
return "";
}
/************************************************************************/
/* GDALGetRasterUnitType() */
/************************************************************************/
/**
* @see GDALRasterBand::GetUnitType()
*/
const char * CPL_STDCALL GDALGetRasterUnitType( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetUnitType();
}
/************************************************************************/
/* SetUnitType() */
/************************************************************************/
/**
* Set unit type.
*
* Set the unit type for a raster band. Values should be one of
* "" (the default indicating it is unknown), "m" indicating meters,
* or "ft" indicating feet, though other nonstandard values are allowed.
*
* @param pszNewValue the new unit type value.
*
* @return CE_None on success or CE_Failure if not succuessful, or
* unsupported.
*/
CPLErr GDALRasterBand::SetUnitType( const char *pszNewValue )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetUnitType() not supported on this raster band." );
return CE_Failure;
}
/************************************************************************/
/* GetXSize() */
/************************************************************************/
/**
* Fetch XSize of raster.
*
* This method is the same as the C function GDALGetRasterBandXSize().
*
* @return the width in pixels of this band.
*/
int GDALRasterBand::GetXSize()
{
return nRasterXSize;
}
/************************************************************************/
/* GDALGetRasterBandXSize() */
/************************************************************************/
/**
* @see GDALRasterBand::GetXSize()
*/
int CPL_STDCALL GDALGetRasterBandXSize( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetXSize();
}
/************************************************************************/
/* GetYSize() */
/************************************************************************/
/**
* Fetch YSize of raster.
*
* This method is the same as the C function GDALGetRasterBandYSize().
*
* @return the height in pixels of this band.
*/
int GDALRasterBand::GetYSize()
{
return nRasterYSize;
}
/************************************************************************/
/* GDALGetRasterBandYSize() */
/************************************************************************/
/**
* @see GDALRasterBand::GetYSize()
*/
int CPL_STDCALL GDALGetRasterBandYSize( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetYSize();
}
/************************************************************************/
/* GetBand() */
/************************************************************************/
/**
* Fetch the band number.
*
* This method returns the band that this GDALRasterBand objects represents
* within it's dataset. This method may return a value of 0 to indicate
* GDALRasterBand objects without an apparently relationship to a dataset,
* such as GDALRasterBands serving as overviews.
*
* This method is the same as the C function GDALGetBandNumber().
*
* @return band number (1+) or 0 if the band number isn't known.
*/
int GDALRasterBand::GetBand()
{
return nBand;
}
/************************************************************************/
/* GDALGetBandNumber() */
/************************************************************************/
/**
* @see GDALRasterBand::GetBand()
*/
int CPL_STDCALL GDALGetBandNumber( GDALRasterBandH hBand )
{
return ((GDALRasterBand *) hBand)->GetBand();
}
/************************************************************************/
/* GetDataset() */
/************************************************************************/
/**
* Fetch the owning dataset handle.
*
* Note that some GDALRasterBands are not considered to be a part of a dataset,
* such as overviews or other "freestanding" bands.
*
* There is currently no C analog to this method.
*
* @return the pointer to the GDALDataset to which this band belongs, or
* NULL if this cannot be determined.
*/
GDALDataset *GDALRasterBand::GetDataset()
{
return poDS;
}
/************************************************************************/
/* GDALGetBandDataset() */
/************************************************************************/
/**
* @see GDALRasterBand::GetDataset()
*/
GDALDatasetH CPL_STDCALL GDALGetBandDataset( GDALRasterBandH hBand )
{
return (GDALDatasetH) ((GDALRasterBand *) hBand)->GetDataset();
}
/************************************************************************/
/* GetHistogram() */
/************************************************************************/
/**
* Compute raster histogram.
*
* Note that the bucket size is (dfMax-dfMin) / nBuckets.
*
* For example to compute a simple 256 entry histogram of eight bit data,
* the following would be suitable. The unusual bounds are to ensure that
* bucket boundaries don't fall right on integer values causing possible errors
* due to rounding after scaling.
int anHistogram[256];
poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
GDALDummyProgress, NULL );
*
* Note that setting bApproxOK will generally result in a subsampling of the
* file, and will utilize overviews if available. It should generally
* produce a representative histogram for the data that is suitable for use
* in generating histogram based luts for instance. Generally bApproxOK is
* much faster than an exactly computed histogram.
*
* @param dfMin the lower bound of the histogram.
* @param dfMax the upper bound of the histogram.
* @param nBuckets the number of buckets in panHistogram.
* @param panHistogram array into which the histogram totals are placed.
* @param bIncludeOutOfRange if TRUE values below the histogram range will
* mapped into panHistogram[0], and values above will be mapped into
* panHistogram[nBuckets-1] otherwise out of range values are discarded.
* @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
* @param pfnProgress function to report progress to completion.
* @param pProgressData application data to pass to pfnProgress.
*
* @return CE_None on success, or CE_Failure if something goes wrong.
*/
CPLErr GDALRasterBand::GetHistogram( double dfMin, double dfMax,
int nBuckets, int *panHistogram,
int bIncludeOutOfRange, int bApproxOK,
GDALProgressFunc pfnProgress,
void *pProgressData )
{
CPLAssert( pfnProgress != NULL );
/* -------------------------------------------------------------------- */
/* If we have overviews, use them for the histogram. */
/* -------------------------------------------------------------------- */
if( bApproxOK && GetOverviewCount() > 0 )
{
double dfBestPixels = GetXSize() * GetYSize();
GDALRasterBand *poBestOverview = NULL;
for( int i = 0; i < GetOverviewCount(); i++ )
{
GDALRasterBand *poOverview = GetOverview(i);
double dfPixels;
dfPixels = poOverview->GetXSize() * poOverview->GetYSize();
if( dfPixels < dfBestPixels )
{
dfBestPixels = dfPixels;
poBestOverview = poOverview;
}
if( poBestOverview != NULL )
return poBestOverview->
GetHistogram( dfMin, dfMax, nBuckets, panHistogram,
bIncludeOutOfRange, bApproxOK,
pfnProgress, pProgressData );
}
}
/* -------------------------------------------------------------------- */
/* Figure out the ratio of blocks we will read to get an */
/* approximate value. */
/* -------------------------------------------------------------------- */
int nSampleRate;
double dfScale;
InitBlockInfo();
if( bApproxOK )
nSampleRate =
(int) MAX(1,sqrt((double) nBlocksPerRow * nBlocksPerColumn));
else
nSampleRate = 1;
dfScale = nBuckets / (dfMax - dfMin);
/* -------------------------------------------------------------------- */
/* Read the blocks, and add to histogram. */
/* -------------------------------------------------------------------- */
memset( panHistogram, 0, sizeof(int) * nBuckets );
for( int iSampleBlock = 0;
iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
iSampleBlock += nSampleRate )
{
double dfValue = 0.0, dfReal, dfImag;
int iXBlock, iYBlock, nXCheck, nYCheck;
GDALRasterBlock *poBlock;
if( !pfnProgress(iSampleBlock/((double)nBlocksPerRow*nBlocksPerColumn),
NULL, pProgressData ) )
return CE_Failure;
iYBlock = iSampleBlock / nBlocksPerRow;
iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
poBlock = GetLockedBlockRef( iXBlock, iYBlock );
if( poBlock == NULL )
return CE_Failure;
if( (iXBlock+1) * nBlockXSize > GetXSize() )
nXCheck = GetXSize() - iXBlock * nBlockXSize;
else
nXCheck = nBlockXSize;
if( (iYBlock+1) * nBlockYSize > GetYSize() )
nYCheck = GetYSize() - iYBlock * nBlockYSize;
else
nYCheck = nBlockYSize;
/* this is a special case for a common situation */
if( poBlock->GetDataType() == GDT_Byte
&& dfScale == 1.0 && (dfMin >= -0.5 && dfMin <= 0.5)
&& nYCheck == nBlockYSize && nXCheck == nBlockXSize
&& nBuckets == 256 )
{
int nPixels = nXCheck * nYCheck;
GByte *pabyData = (GByte *) poBlock->GetDataRef();
for( int i = 0; i < nPixels; i++ )
panHistogram[pabyData[i]]++;
poBlock->DropLock();
continue; /* to next sample block */
}
/* this isn't the fastest way to do this, but is easier for now */
for( int iY = 0; iY < nYCheck; iY++ )
{
for( int iX = 0; iX < nXCheck; iX++ )
{
int iOffset = iX + iY * nBlockXSize;
int nIndex;
switch( poBlock->GetDataType() )
{
case GDT_Byte:
dfValue = ((GByte *) poBlock->GetDataRef())[iOffset];
break;
case GDT_UInt16:
dfValue = ((GUInt16 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Int16:
dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_UInt32:
dfValue = ((GUInt32 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Int32:
dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Float32:
dfValue = ((float *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Float64:
dfValue = ((double *) poBlock->GetDataRef())[iOffset];
break;
case GDT_CInt16:
dfReal = ((GInt16 *) poBlock->GetDataRef())[iOffset*2];
dfImag = ((GInt16 *) poBlock->GetDataRef())[iOffset*2+1];
dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
break;
case GDT_CInt32:
dfReal = ((GInt32 *) poBlock->GetDataRef())[iOffset*2];
dfImag = ((GInt32 *) poBlock->GetDataRef())[iOffset*2+1];
dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
break;
case GDT_CFloat32:
dfReal = ((float *) poBlock->GetDataRef())[iOffset*2];
dfImag = ((float *) poBlock->GetDataRef())[iOffset*2+1];
dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
break;
case GDT_CFloat64:
dfReal = ((double *) poBlock->GetDataRef())[iOffset*2];
dfImag = ((double *) poBlock->GetDataRef())[iOffset*2+1];
dfValue = sqrt( dfReal * dfReal + dfImag * dfImag );
break;
default:
CPLAssert( FALSE );
return CE_Failure;
}
nIndex = (int) floor((dfValue - dfMin) * dfScale);
if( nIndex < 0 )
{
if( bIncludeOutOfRange )
panHistogram[0]++;
}
else if( nIndex >= nBuckets )
{
if( bIncludeOutOfRange )
panHistogram[nBuckets-1]++;
}
else
{
panHistogram[nIndex]++;
}
}
}
poBlock->DropLock();
}
pfnProgress( 1.0, NULL, pProgressData );
return CE_None;
}
/************************************************************************/
/* GDALGetRasterHistogram() */
/************************************************************************/
/**
* @see GDALRasterBand::GetHistogram()
*/
CPLErr CPL_STDCALL
GDALGetRasterHistogram( GDALRasterBandH hBand,
double dfMin, double dfMax,
int nBuckets, int *panHistogram,
int bIncludeOutOfRange, int bApproxOK,
GDALProgressFunc pfnProgress,
void *pProgressData )
{
return ((GDALRasterBand *) hBand)->
GetHistogram( dfMin, dfMax, nBuckets, panHistogram,
bIncludeOutOfRange, bApproxOK,
pfnProgress, pProgressData );
}
/************************************************************************/
/* GetHistogram() */
/************************************************************************/
/**
* Fetch default raster histogram.
*
* Note that the bucket size is (dfMax-dfMin) / nBuckets.
*
* For example to compute a simple 256 entry histogram of eight bit data,
* the following would be suitable. The unusual bounds are to ensure that
* bucket boundaries don't fall right on integer values causing possible errors
* due to rounding after scaling.
int anHistogram[256];
poBand->GetHistogram( -0.5, 255.5, 256, anHistogram, FALSE, FALSE,
GDALDummyProgress, NULL );
*
* Note that setting bApproxOK will generally result in a subsampling of the
* file, and will utilize overviews if available. It should generally
* produce a representative histogram for the data that is suitable for use
* in generating histogram based luts for instance. Generally bApproxOK is
* much faster than an exactly computed histogram.
*
* @param dfMin the lower bound of the histogram.
* @param dfMax the upper bound of the histogram.
* @param nBuckets the number of buckets in panHistogram.
* @param panHistogram array into which the histogram totals are placed.
* @param bIncludeOutOfRange if TRUE values below the histogram range will
* mapped into panHistogram[0], and values above will be mapped into
* panHistogram[nBuckets-1] otherwise out of range values are discarded.
* @param bApproxOK TRUE if an approximate, or incomplete histogram OK.
* @param pfnProgress function to report progress to completion.
* @param pProgressData application data to pass to pfnProgress.
*
* @return CE_None on success, CE_Failure if something goes wrong, or
* CE_Warning if no default histogram is available.
*/
CPLErr
GDALRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
int *pnBuckets, int **ppanHistogram,
int bForce,
GDALProgressFunc pfnProgress,
void *pProgressData )
{
if( !bForce )
return CE_Warning;
*pnBuckets = 256;
if( GetRasterDataType() == GDT_Byte )
{
*pdfMin = -0.5;
*pdfMax = 255.5;
}
else
{
CPLErr eErr;
double dfHalfBucket;
eErr = GetStatistics( TRUE, TRUE, pdfMin, pdfMax, NULL, NULL );
dfHalfBucket = (*pdfMax - *pdfMin) / (2 * *pnBuckets);
*pdfMin -= dfHalfBucket;
*pdfMax += dfHalfBucket;
if( eErr != CE_None )
return eErr;
}
*ppanHistogram = (int *) VSICalloc(sizeof(int),*pnBuckets);
if( *ppanHistogram == NULL )
{
CPLError( CE_Failure, CPLE_OutOfMemory,
"Out of memory in InitBlockInfo()." );
return CE_Failure;
}
return GetHistogram( *pdfMin, *pdfMax, *pnBuckets, *ppanHistogram,
TRUE, FALSE, pfnProgress, pProgressData );
}
/************************************************************************/
/* GDALGetDefaultHistogram() */
/************************************************************************/
CPLErr CPL_STDCALL GDALGetDefaultHistogram( GDALRasterBandH hBand,
double *pdfMin, double *pdfMax,
int *pnBuckets, int **ppanHistogram,
int bForce,
GDALProgressFunc pfnProgress,
void *pProgressData )
{
return ((GDALRasterBand *) hBand)->GetDefaultHistogram(
pdfMin, pdfMax, pnBuckets, ppanHistogram, bForce,
pfnProgress, pProgressData );
}
/************************************************************************/
/* AdviseRead() */
/************************************************************************/
/**
* Advise driver of upcoming read requests.
*
* Some GDAL drivers operate more efficiently if they know in advance what
* set of upcoming read requests will be made. The AdviseRead() method allows
* an application to notify the driver of the region of interest,
* and at what resolution the region will be read.
*
* Many drivers just ignore the AdviseRead() call, but it can dramatically
* accelerate access via some drivers.
*
* @param nXOff The pixel offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the left side.
*
* @param nYOff The line offset to the top left corner of the region
* of the band to be accessed. This would be zero to start from the top.
*
* @param nXSize The width of the region of the band to be accessed in pixels.
*
* @param nYSize The height of the region of the band to be accessed in lines.
*
* @param nBufXSize the width of the buffer image into which the desired region
* is to be read, or from which it is to be written.
*
* @param nBufYSize the height of the buffer image into which the desired
* region is to be read, or from which it is to be written.
*
* @param eBufType the type of the pixel values in the pData data buffer. The
* pixel values will automatically be translated to/from the GDALRasterBand
* data type as needed.
*
* @param papszOptions a list of name=value strings with special control
* options. Normally this is NULL.
*
* @return CE_Failure if the request is invalid and CE_None if it works or
* is ignored.
*/
CPLErr GDALRasterBand::AdviseRead(
int nXOff, int nYOff, int nXSize, int nYSize,
int nBufXSize, int nBufYSize, GDALDataType eDT, char **papszOptions )
{
return CE_None;
}
/************************************************************************/
/* GDALRasterAdviseRead() */
/************************************************************************/
CPLErr CPL_STDCALL
GDALRasterAdviseRead( GDALRasterBandH hRB,
int nXOff, int nYOff, int nXSize, int nYSize,
int nBufXSize, int nBufYSize,
GDALDataType eDT, char **papszOptions )
{
return ((GDALRasterBand *) hRB)->AdviseRead( nXOff, nYOff, nXSize, nYSize,
nBufXSize, nBufYSize, eDT,
papszOptions );
}
/************************************************************************/
/* GetStatistics() */
/************************************************************************/
/**
* Fetch image statistics.
*
* Returns the minimum, maximum, mean and standard deviation of all
* pixel values in this band. If approximate statistics are sufficient,
* the bApproxOK flag can be set to true in which case overviews, or a
* subset of image tiles may be used in computing the statistics.
*
* If bForce is FALSE results will only be returned if it can be done
* quickly (ie. without scanning the data). If bForce is FALSE and
* results cannot be returned efficiently, the method will return CE_Warning
* but no warning will have been issued. This is a non-standard use of
* the CE_Warning return value to indicate "nothing done".
*
* Note that file formats using PAM (Persistent Auxilary Metadata) services
* will generally cache statistics in the .pam file allowing fast fetch
* after the first request.
*
* This method is the same as the C function GDALGetRasterStatistics().
*
* @param bApproxOK If TRUE statistics may be computed based on overviews
* or a subset of all tiles.
*
* @param bForce If FALSE statistics will only be returned if it can
* be done without rescanning the image.
*
* @param pdfMin Location into which to load image minimum (may be NULL).
*
* @param pdfMax Location into which to load image maximum (may be NULL).-
*
* @param pdfMean Location into which to load image mean (may be NULL).
*
* @param pdfStdDev Location into which to load image standard deviation
* (may be NULL).
*
* @return CE_None on success, CE_Warning if no values returned,
* CE_Failure if an error occurs.
*/
CPLErr GDALRasterBand::GetStatistics( int bApproxOK, int bForce,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev )
{
double dfMin=0.0, dfMax=0.0;
/* -------------------------------------------------------------------- */
/* Do we already have metadata items for the requested values? */
/* -------------------------------------------------------------------- */
if( (pdfMin == NULL || GetMetadataItem("STATISTICS_MINIMUM") != NULL)
&& (pdfMax == NULL || GetMetadataItem("STATISTICS_MAXIMUM") != NULL)
&& (pdfMean == NULL || GetMetadataItem("STATISTICS_MEAN") != NULL)
&& (pdfStdDev == NULL || GetMetadataItem("STATISTICS_STDDEV") != NULL) )
{
if( pdfMin != NULL )
*pdfMin = atof(GetMetadataItem("STATISTICS_MINIMUM"));
if( pdfMax != NULL )
*pdfMax = atof(GetMetadataItem("STATISTICS_MAXIMUM"));
if( pdfMean != NULL )
*pdfMean = atof(GetMetadataItem("STATISTICS_MEAN"));
if( pdfStdDev != NULL )
*pdfStdDev = atof(GetMetadataItem("STATISTICS_STDDEV"));
return CE_None;
}
/* -------------------------------------------------------------------- */
/* Does the driver already know the min/max? */
/* -------------------------------------------------------------------- */
if( bApproxOK && pdfMean == NULL && pdfStdDev == NULL )
{
int bSuccessMin, bSuccessMax;
dfMin = GetMinimum( &bSuccessMin );
dfMax = GetMaximum( &bSuccessMax );
if( bSuccessMin && bSuccessMax )
{
if( pdfMin != NULL )
*pdfMin = dfMin;
if( pdfMax != NULL )
*pdfMax = dfMax;
return CE_None;
}
}
/* -------------------------------------------------------------------- */
/* Either return without results, or force computation. */
/* -------------------------------------------------------------------- */
if( !bForce )
return CE_Warning;
else
return ComputeStatistics( bApproxOK,
pdfMin, pdfMax, pdfMean, pdfStdDev,
GDALDummyProgress, NULL );
}
/************************************************************************/
/* GDALGetRasterStatistics() */
/************************************************************************/
CPLErr CPL_STDCALL GDALGetRasterStatistics(
GDALRasterBandH hBand, int bApproxOK, int bForce,
double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev )
{
return ((GDALRasterBand *) hBand)->GetStatistics(
bApproxOK, bForce, pdfMin, pdfMax, pdfMean, pdfStdDev );
}
/************************************************************************/
/* ComputeStatistics() */
/************************************************************************/
/**
* Compute image statistics.
*
* Returns the minimum, maximum, mean and standard deviation of all
* pixel values in this band. If approximate statistics are sufficient,
* the bApproxOK flag can be set to true in which case overviews, or a
* subset of image tiles may be used in computing the statistics.
*
* Once computed, the statistics will generally be "set" back on the
* raster band using SetStatistics().
*
* This method is the same as the C function GDALComputeRasterStatistics().
*
* @param bApproxOK If TRUE statistics may be computed based on overviews
* or a subset of all tiles.
*
* @param pdfMin Location into which to load image minimum (may be NULL).
*
* @param pdfMax Location into which to load image maximum (may be NULL).-
*
* @param pdfMean Location into which to load image mean (may be NULL).
*
* @param pdfStdDev Location into which to load image standard deviation
* (may be NULL).
*
* @param pfnProgress a function to call to report progress, or NULL.
*
* @param pProgressData application data to pass to the progress function.
*
* @return CE_None on success, or CE_Failure if an error occurs or processing
* is terminated by the user.
*/
CPLErr
GDALRasterBand::ComputeStatistics( int bApproxOK,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev,
GDALProgressFunc pfnProgress,
void *pProgressData )
{
if( pfnProgress == NULL )
pfnProgress = GDALDummyProgress;
/* -------------------------------------------------------------------- */
/* If we have overview bands, use them for min/max. */
/* -------------------------------------------------------------------- */
if( bApproxOK )
{
GDALRasterBand *poBand;
poBand = (GDALRasterBand *) GDALGetRasterSampleOverview( this, 2500 );
if( poBand != this )
return poBand->ComputeStatistics( FALSE,
pdfMin, pdfMax,
pdfMean, pdfStdDev,
pfnProgress, pProgressData );
}
/* -------------------------------------------------------------------- */
/* Figure out the ratio of blocks we will read to get an */
/* approximate value. */
/* -------------------------------------------------------------------- */
double dfMin=0.0, dfMax=0.0;
int nBlockXSize, nBlockYSize;
int nBlocksPerRow, nBlocksPerColumn;
int nSampleRate;
int bGotNoDataValue, bFirstValue = TRUE;
double dfNoDataValue, dfSum=0.0, dfSum2=0.0;
GIntBig nSampleCount = 0;
if( !pfnProgress( 0.0, NULL, pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return CE_Failure;
}
dfNoDataValue = GetNoDataValue( &bGotNoDataValue );
GetBlockSize( &nBlockXSize, &nBlockYSize );
nBlocksPerRow = (GetXSize() + nBlockXSize - 1) / nBlockXSize;
nBlocksPerColumn = (GetYSize() + nBlockYSize - 1) / nBlockYSize;
if( bApproxOK )
nSampleRate =
(int) MAX(1,sqrt((double) nBlocksPerRow * nBlocksPerColumn));
else
nSampleRate = 1;
for( int iSampleBlock = 0;
iSampleBlock < nBlocksPerRow * nBlocksPerColumn;
iSampleBlock += nSampleRate )
{
double dfValue = 0.0;
int iXBlock, iYBlock, nXCheck, nYCheck;
GDALRasterBlock *poBlock;
iYBlock = iSampleBlock / nBlocksPerRow;
iXBlock = iSampleBlock - nBlocksPerRow * iYBlock;
poBlock = GetLockedBlockRef( iXBlock, iYBlock );
if( poBlock == NULL )
continue;
if( (iXBlock+1) * nBlockXSize > GetXSize() )
nXCheck = GetXSize() - iXBlock * nBlockXSize;
else
nXCheck = nBlockXSize;
if( (iYBlock+1) * nBlockYSize > GetYSize() )
nYCheck = GetYSize() - iYBlock * nBlockYSize;
else
nYCheck = nBlockYSize;
/* this isn't the fastest way to do this, but is easier for now */
for( int iY = 0; iY < nYCheck; iY++ )
{
for( int iX = 0; iX < nXCheck; iX++ )
{
int iOffset = iX + iY * nBlockXSize;
switch( poBlock->GetDataType() )
{
case GDT_Byte:
dfValue = ((GByte *) poBlock->GetDataRef())[iOffset];
break;
case GDT_UInt16:
dfValue = ((GUInt16 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Int16:
dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_UInt32:
dfValue = ((GUInt32 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Int32:
dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Float32:
dfValue = ((float *) poBlock->GetDataRef())[iOffset];
break;
case GDT_Float64:
dfValue = ((double *) poBlock->GetDataRef())[iOffset];
break;
case GDT_CInt16:
dfValue = ((GInt16 *) poBlock->GetDataRef())[iOffset*2];
break;
case GDT_CInt32:
dfValue = ((GInt32 *) poBlock->GetDataRef())[iOffset*2];
break;
case GDT_CFloat32:
dfValue = ((float *) poBlock->GetDataRef())[iOffset*2];
break;
case GDT_CFloat64:
dfValue = ((double *) poBlock->GetDataRef())[iOffset*2];
break;
default:
CPLAssert( FALSE );
}
if( bGotNoDataValue && dfValue == dfNoDataValue )
continue;
if( bFirstValue )
{
dfMin = dfMax = dfValue;
bFirstValue = FALSE;
}
else
{
dfMin = MIN(dfMin,dfValue);
dfMax = MAX(dfMax,dfValue);
}
dfSum += dfValue;
dfSum2 += dfValue * dfValue;
nSampleCount++;
}
}
poBlock->DropLock();
if( !pfnProgress( iSampleBlock / ((double) (nBlocksPerRow*nBlocksPerColumn)),
"Compute Statistics", pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return CE_Failure;
}
}
if( !pfnProgress( 1.0, "Compute Statistics", pProgressData ) )
{
CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Save computed information. */
/* -------------------------------------------------------------------- */
double dfMean = dfSum / nSampleCount;
double dfStdDev = sqrt((dfSum2 / nSampleCount) - (dfMean * dfMean));
if( nSampleCount > 1 )
SetStatistics( dfMin, dfMax, dfMean, dfStdDev );
/* -------------------------------------------------------------------- */
/* Record results. */
/* -------------------------------------------------------------------- */
if( pdfMin != NULL )
*pdfMin = dfMin;
if( pdfMax != NULL )
*pdfMax = dfMax;
if( pdfMean != NULL )
*pdfMean = dfMean;
if( pdfStdDev != NULL )
*pdfStdDev = dfStdDev;
if( nSampleCount > 0 )
return CE_None;
else
{
CPLError( CE_Failure, CPLE_AppDefined,
"Failed to compute statistics, no valid pixels found in sampling." );
return CE_Failure;
}
}
/************************************************************************/
/* GDALComputeRasterStatistics() */
/************************************************************************/
CPLErr CPL_STDCALL GDALComputeRasterStatistics(
GDALRasterBandH hBand, int bApproxOK,
double *pdfMin, double *pdfMax, double *pdfMean, double *pdfStdDev,
GDALProgressFunc pfnProgress, void *pProgressData )
{
return ((GDALRasterBand *) hBand)->ComputeStatistics(
bApproxOK, pdfMin, pdfMax, pdfMean, pdfStdDev,
pfnProgress, pProgressData );
}
/************************************************************************/
/* SetStatistics() */
/************************************************************************/
/**
* Set statistics on band.
*
* This method can be used to store min/max/mean/standard deviation
* statistics on a raster band.
*
* The default implementation stores them as metadata, and will only work
* on formats that can save arbitrary metadata. This method cannot detect
* whether metadata will be properly saved and so may return CE_None even
* if the statistics will never be saved.
*
* This method is the same as the C function GDALSetRasterStatistics().
*
* @param dfMin minimum pixel value.
*
* @param dfMax maximum pixel value.
*
* @param dfMean mean (average) of all pixel values.
*
* @param dfStdDev Standard deviation of all pixel values.
*
* @return CE_None on success or CE_Failure on failure.
*/
CPLErr GDALRasterBand::SetStatistics( double dfMin, double dfMax,
double dfMean, double dfStdDev )
{
char szValue[128];
sprintf( szValue, "%.14g", dfMin );
SetMetadataItem( "STATISTICS_MINIMUM", szValue );
sprintf( szValue, "%.14g", dfMax );
SetMetadataItem( "STATISTICS_MAXIMUM", szValue );
sprintf( szValue, "%.14g", dfMean );
SetMetadataItem( "STATISTICS_MEAN", szValue );
sprintf( szValue, "%.14g", dfStdDev );
SetMetadataItem( "STATISTICS_STDDEV", szValue );
return CE_None;
}
/************************************************************************/
/* GDALSetRasterStatistics() */
/************************************************************************/
CPLErr CPL_STDCALL GDALSetRasterStatistics(
GDALRasterBandH hBand,
double dfMin, double dfMax, double dfMean, double dfStdDev )
{
return ((GDALRasterBand *) hBand)->SetStatistics(
dfMin, dfMax, dfMean, dfStdDev );
}
/************************************************************************/
/* SetDefaultHistogram() */
/************************************************************************/
CPLErr GDALRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
int nBuckets, int *panHistogram )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetDefaultHistogram() not implemented for this format." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetDefaultHistogram() */
/************************************************************************/
CPLErr CPL_STDCALL GDALSetDefaultHistogram( GDALRasterBandH hBand,
double dfMin, double dfMax,
int nBuckets, int *panHistogram )
{
return ((GDALRasterBand *) hBand)->SetDefaultHistogram(
dfMin, dfMax, nBuckets, panHistogram );
}
/************************************************************************/
/* GetDefaultRAT() */
/************************************************************************/
/**
* Fetch default Raster Attribute Table.
*
* A RAT will be returned if there is a default one associated with the
* band, otherwise NULL is returned. The returned RAT is owned by the
* band and should not be deleted, or altered by the application.
*
* @return NULL, or a pointer to an internal RAT owned by the band.
*/
const GDALRasterAttributeTable *GDALRasterBand::GetDefaultRAT()
{
return NULL;
}
/************************************************************************/
/* GDALGetDefaultRAT() */
/************************************************************************/
GDALRasterAttributeTableH CPL_STDCALL GDALGetDefaultRAT( GDALRasterBandH hBand)
{
return (GDALRasterAttributeTableH)
((GDALRasterBand *) hBand)->GetDefaultRAT();
}
/************************************************************************/
/* SetDefaultRAT() */
/************************************************************************/
/**
* Set default Raster Attribute Table.
*
* Associates a default RAT with the band. If not implemented for the
* format a CPLE_NotSupported error will be issued. If successful a copy
* of the RAT is made, the original remains owned by the caller.
*
* @param poRAT the RAT to assign to the band.
*
* @return CE_None on success or CE_Failure if unsupported or otherwise
* failing.
*/
CPLErr GDALRasterBand::SetDefaultRAT( const GDALRasterAttributeTable *poRAT )
{
if( !(GetMOFlags() & GMO_IGNORE_UNIMPLEMENTED) )
CPLError( CE_Failure, CPLE_NotSupported,
"SetDefaultRAT() not implemented for this format." );
return CE_Failure;
}
/************************************************************************/
/* GDALSetDefaultRAT() */
/************************************************************************/
CPLErr CPL_STDCALL GDALSetDefaultRAT( GDALRasterBandH hBand,
GDALRasterAttributeTableH hRAT )
{
return ((GDALRasterBand *) hBand)->SetDefaultRAT(
(GDALRasterAttributeTable *) hRAT );
}