/******************************************************************************
* $Id: rasterio.cpp 10646 2007-01-18 02:38:10Z warmerdam $
*
* Project: GDAL Core
* Purpose: Contains default implementation of GDALRasterBand::IRasterIO()
* and supporting functions of broader utility.
* 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"
CPL_CVSID("$Id: rasterio.cpp 10646 2007-01-18 02:38:10Z warmerdam $");
/************************************************************************/
/* IRasterIO() */
/* */
/* Default internal implementation of RasterIO() ... utilizes */
/* the Block access methods to satisfy the request. This would */
/* normally only be overridden by formats with overviews. */
/************************************************************************/
CPLErr GDALRasterBand::IRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nPixelSpace, int nLineSpace )
{
int nBandDataSize = GDALGetDataTypeSize( eDataType ) / 8;
int nBufDataSize = GDALGetDataTypeSize( eBufType ) / 8;
GByte *pabySrcBlock = NULL;
GDALRasterBlock *poBlock = NULL;
int nLBlockX=-1, nLBlockY=-1, iBufYOff, iBufXOff, iSrcY;
/* ==================================================================== */
/* A common case is the data requested with the destination */
/* is packed, and the block width is the raster width. */
/* ==================================================================== */
if( nPixelSpace == nBufDataSize
&& nLineSpace == nPixelSpace * nXSize
&& nBlockXSize == GetXSize()
&& nBufXSize == nXSize
&& nBufYSize == nYSize )
{
// printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 1\n",
// nXOff, nYOff, nXSize, nYSize,
// (int) eRWFlag );
for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
{
int nSrcByteOffset;
iSrcY = iBufYOff + nYOff;
if( iSrcY < nLBlockY * nBlockYSize
|| iSrcY >= (nLBlockY+1) * nBlockYSize )
{
nLBlockY = iSrcY / nBlockYSize;
int bJustInitialize =
eRWFlag == GF_Write
&& nXOff == 0 && nXSize == nBlockXSize
&& nYOff <= nLBlockY * nBlockYSize
&& nYOff + nYSize >= (nLBlockY+1) * nBlockYSize;
if( poBlock )
poBlock->DropLock();
poBlock = GetLockedBlockRef( 0, nLBlockY, bJustInitialize );
if( poBlock == NULL )
{
CPLError( CE_Failure, CPLE_AppDefined,
"GetBlockRef failed at X block offset %d, "
"Y block offset %d", 0, nLBlockY );
return( CE_Failure );
}
if( eRWFlag == GF_Write )
poBlock->MarkDirty();
pabySrcBlock = (GByte *) poBlock->GetDataRef();
}
nSrcByteOffset = ((iSrcY-nLBlockY*nBlockYSize)*nBlockXSize + nXOff)
* nBandDataSize;
if( eDataType == eBufType )
{
if( eRWFlag == GF_Read )
memcpy( ((GByte *) pData) + iBufYOff * nLineSpace,
pabySrcBlock + nSrcByteOffset,
nLineSpace );
else
memcpy( pabySrcBlock + nSrcByteOffset,
((GByte *) pData) + iBufYOff * nLineSpace,
nLineSpace );
}
else
{
/* type to type conversion */
if( eRWFlag == GF_Read )
GDALCopyWords( pabySrcBlock + nSrcByteOffset,
eDataType, nBandDataSize,
((GByte *) pData) + iBufYOff * nLineSpace,
eBufType, nPixelSpace, nBufXSize );
else
GDALCopyWords( ((GByte *) pData) + iBufYOff * nLineSpace,
eBufType, nPixelSpace,
pabySrcBlock + nSrcByteOffset,
eDataType, nBandDataSize, nBufXSize );
}
}
if( poBlock )
poBlock->DropLock();
return CE_None;
}
/* ==================================================================== */
/* Do we have overviews that would be appropriate to satisfy */
/* this request? */
/* ==================================================================== */
if( (nBufXSize < nXSize || nBufYSize < nYSize)
&& GetOverviewCount() > 0 && eRWFlag == GF_Read )
{
if( OverviewRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize,
eBufType, nPixelSpace, nLineSpace ) == CE_None )
return CE_None;
}
/* ==================================================================== */
/* The second case when we don't need subsample data but likely */
/* need data type conversion. */
/* ==================================================================== */
int iSrcX;
if ( /* nPixelSpace == nBufDataSize
&& */ nXSize == nBufXSize
&& nYSize == nBufYSize )
{
// printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 2\n",
// nXOff, nYOff, nXSize, nYSize,
// (int) eRWFlag );
/* -------------------------------------------------------------------- */
/* Loop over buffer computing source locations. */
/* -------------------------------------------------------------------- */
int nLBlockXStart, nXSpanEnd;
// Calculate starting values out of loop
nLBlockXStart = nXOff / nBlockXSize;
nXSpanEnd = nBufXSize + nXOff;
for( iBufYOff = 0, iSrcY = nYOff; iBufYOff < nBufYSize; iBufYOff++, iSrcY++ )
{
int iBufOffset, iSrcOffset, nXSpan;
iBufOffset = iBufYOff * nLineSpace;
nLBlockY = iSrcY / nBlockYSize;
nLBlockX = nLBlockXStart;
iSrcX = nXOff;
while( iSrcX < nXSpanEnd )
{
int nXSpanSize;
nXSpan = (nLBlockX + 1) * nBlockXSize;
nXSpan = ( ( nXSpan < nXSpanEnd )?nXSpan:nXSpanEnd ) - iSrcX;
nXSpanSize = nXSpan * nPixelSpace;
int bJustInitialize =
eRWFlag == GF_Write
&& nYOff <= nLBlockY * nBlockYSize
&& nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
&& nXOff <= nLBlockX * nBlockXSize
&& nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
// printf( "bJustInitialize = %d (%d,%d,%d,%d)\n",
// bJustInitialize,
// nYOff, nYSize,
// nLBlockY, nBlockYSize );
// bJustInitialize = FALSE;
/* -------------------------------------------------------------------- */
/* Ensure we have the appropriate block loaded. */
/* -------------------------------------------------------------------- */
poBlock = GetLockedBlockRef( nLBlockX, nLBlockY, bJustInitialize );
if( !poBlock )
{
CPLError( CE_Failure, CPLE_AppDefined,
"GetBlockRef failed at X block offset %d, "
"Y block offset %d", nLBlockX, nLBlockY );
return( CE_Failure );
}
if( eRWFlag == GF_Write )
poBlock->MarkDirty();
pabySrcBlock = (GByte *) poBlock->GetDataRef();
if( pabySrcBlock == NULL )
{
poBlock->DropLock();
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Copy over this chunk of data. */
/* -------------------------------------------------------------------- */
iSrcOffset = (iSrcX - nLBlockX*nBlockXSize
+ (iSrcY - nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
if( eDataType == eBufType
&& nPixelSpace == nBufDataSize )
{
if( eRWFlag == GF_Read )
memcpy( ((GByte *) pData) + iBufOffset,
pabySrcBlock + iSrcOffset, nXSpanSize );
else
memcpy( pabySrcBlock + iSrcOffset,
((GByte *) pData) + iBufOffset, nXSpanSize );
}
else
{
/* type to type conversion */
if( eRWFlag == GF_Read )
GDALCopyWords( pabySrcBlock + iSrcOffset,
eDataType, nBandDataSize,
((GByte *) pData) + iBufOffset,
eBufType, nPixelSpace, nXSpan );
else
GDALCopyWords( ((GByte *) pData) + iBufOffset,
eBufType, nPixelSpace,
pabySrcBlock + iSrcOffset,
eDataType, nBandDataSize, nXSpan );
}
iBufOffset += nXSpanSize;
nLBlockX++;
iSrcX+=nXSpan;
poBlock->DropLock();
poBlock = NULL;
}
}
return CE_None;
}
/* ==================================================================== */
/* Loop reading required source blocks to satisfy output */
/* request. This is the most general implementation. */
/* ==================================================================== */
/* -------------------------------------------------------------------- */
/* Compute stepping increment. */
/* -------------------------------------------------------------------- */
double dfSrcX, dfSrcY, dfSrcXInc, dfSrcYInc;
// int iSrcX;
dfSrcXInc = nXSize / (double) nBufXSize;
dfSrcYInc = nYSize / (double) nBufYSize;
/* -------------------------------------------------------------------- */
/* Loop over buffer computing source locations. */
/* -------------------------------------------------------------------- */
// printf( "IRasterIO(%d,%d,%d,%d) rw=%d case 3\n",
// nXOff, nYOff, nXSize, nYSize,
// (int) eRWFlag );
for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
{
int iBufOffset, iSrcOffset;
dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
iSrcY = (int) dfSrcY;
iBufOffset = iBufYOff * nLineSpace;
for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++ )
{
dfSrcX = (iBufXOff+0.5) * dfSrcXInc + nXOff;
iSrcX = (int) dfSrcX;
/* -------------------------------------------------------------------- */
/* Ensure we have the appropriate block loaded. */
/* -------------------------------------------------------------------- */
if( iSrcX < nLBlockX * nBlockXSize
|| iSrcX >= (nLBlockX+1) * nBlockXSize
|| iSrcY < nLBlockY * nBlockYSize
|| iSrcY >= (nLBlockY+1) * nBlockYSize )
{
nLBlockX = iSrcX / nBlockXSize;
nLBlockY = iSrcY / nBlockYSize;
int bJustInitialize =
eRWFlag == GF_Write
&& nYOff <= nLBlockY * nBlockYSize
&& nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
&& nXOff <= nLBlockX * nBlockXSize
&& nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
if( poBlock != NULL )
poBlock->DropLock();
poBlock = GetLockedBlockRef( nLBlockX, nLBlockY,
bJustInitialize );
if( poBlock == NULL )
{
return( CE_Failure );
}
if( eRWFlag == GF_Write )
poBlock->MarkDirty();
pabySrcBlock = (GByte *) poBlock->GetDataRef();
if( pabySrcBlock == NULL )
{
poBlock->DropLock();
return CE_Failure;
}
}
/* -------------------------------------------------------------------- */
/* Copy over this pixel of data. */
/* -------------------------------------------------------------------- */
iSrcOffset = (iSrcX - nLBlockX*nBlockXSize
+ (iSrcY - nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
if( eDataType == eBufType )
{
if( eRWFlag == GF_Read )
memcpy( ((GByte *) pData) + iBufOffset,
pabySrcBlock + iSrcOffset, nBandDataSize );
else
memcpy( pabySrcBlock + iSrcOffset,
((GByte *) pData) + iBufOffset, nBandDataSize );
}
else
{
/* type to type conversion ... ouch, this is expensive way
of handling single words */
if( eRWFlag == GF_Read )
GDALCopyWords( pabySrcBlock + iSrcOffset, eDataType, 0,
((GByte *) pData) + iBufOffset, eBufType, 0,
1 );
else
GDALCopyWords( ((GByte *) pData) + iBufOffset, eBufType, 0,
pabySrcBlock + iSrcOffset, eDataType, 0,
1 );
}
iBufOffset += nPixelSpace;
}
}
if( poBlock != NULL )
poBlock->DropLock();
return( CE_None );
}
/************************************************************************/
/* GDALSwapWords() */
/************************************************************************/
/**
* Byte swap words in-place.
*
* This function will byte swap a set of 2, 4 or 8 byte words "in place" in
* a memory array. No assumption is made that the words being swapped are
* word aligned in memory. Use the CPL_LSB and CPL_MSB macros from cpl_port.h
* to determine if the current platform is big endian or little endian. Use
* The macros like CPL_SWAP32() to byte swap single values without the overhead
* of a function call.
*
* @param pData pointer to start of data buffer.
* @param nWordSize size of words being swapped in bytes. Normally 2, 4 or 8.
* @param nWordCount the number of words to be swapped in this call.
* @param nWordSkip the byte offset from the start of one word to the start of
* the next. For packed buffers this is the same as nWordSize.
*/
void CPL_STDCALL GDALSwapWords( void *pData, int nWordSize, int nWordCount,
int nWordSkip )
{
int i;
GByte *pabyData = (GByte *) pData;
switch( nWordSize )
{
case 1:
break;
case 2:
CPLAssert( nWordSkip >= 2 || nWordCount == 1 );
for( i = 0; i < nWordCount; i++ )
{
GByte byTemp;
byTemp = pabyData[0];
pabyData[0] = pabyData[1];
pabyData[1] = byTemp;
pabyData += nWordSkip;
}
break;
case 4:
CPLAssert( nWordSkip >= 4 || nWordCount == 1 );
for( i = 0; i < nWordCount; i++ )
{
GByte byTemp;
byTemp = pabyData[0];
pabyData[0] = pabyData[3];
pabyData[3] = byTemp;
byTemp = pabyData[1];
pabyData[1] = pabyData[2];
pabyData[2] = byTemp;
pabyData += nWordSkip;
}
break;
case 8:
CPLAssert( nWordSkip >= 8 || nWordCount == 1 );
for( i = 0; i < nWordCount; i++ )
{
GByte byTemp;
byTemp = pabyData[0];
pabyData[0] = pabyData[7];
pabyData[7] = byTemp;
byTemp = pabyData[1];
pabyData[1] = pabyData[6];
pabyData[6] = byTemp;
byTemp = pabyData[2];
pabyData[2] = pabyData[5];
pabyData[5] = byTemp;
byTemp = pabyData[3];
pabyData[3] = pabyData[4];
pabyData[4] = byTemp;
pabyData += nWordSkip;
}
break;
default:
CPLAssert( FALSE );
}
}
/************************************************************************/
/* GDALCopyWords() */
/************************************************************************/
/**
* Copy pixel words from buffer to buffer.
*
* This function is used to copy pixel word values from one memory buffer
* to another, with support for conversion between data types, and differing
* step factors. The data type conversion is done using the normal GDAL
* rules. Values assigned to a lower range integer type are clipped. For
* instance assigning GDT_Int16 values to a GDT_Byte buffer will cause values
* less the 0 to be set to 0, and values larger than 255 to be set to 255.
* Assignment from floating point to integer uses default C type casting
* semantics. Assignment from non-complex to complex will result in the
* imaginary part being set to zero on output. Assigment from complex to
* non-complex will result in the complex portion being lost and the real
* component being preserved (not magnitidue!).
*
* No assumptions are made about the source or destination words occuring
* on word boundaries. It is assumed that all values are in native machine
* byte order.
*
* @param pSrcData
*
*
*/
void CPL_STDCALL
GDALCopyWords( void * pSrcData, GDALDataType eSrcType, int nSrcPixelOffset,
void * pDstData, GDALDataType eDstType, int nDstPixelOffset,
int nWordCount )
{
/* -------------------------------------------------------------------- */
/* Special case when no data type translation is required. */
/* -------------------------------------------------------------------- */
if( eSrcType == eDstType )
{
int nWordSize = GDALGetDataTypeSize(eSrcType)/8;
int i;
// contiguous blocks.
if( nWordSize == nSrcPixelOffset && nWordSize == nDstPixelOffset )
{
memcpy( pDstData, pSrcData, nSrcPixelOffset * nWordCount );
return;
}
// Moving single bytes, avoid any possible memcpy() overhead.
if( nWordSize == 1 )
{
GByte *pabySrc = (GByte *) pSrcData;
GByte *pabyDst = (GByte *) pDstData;
for( i = nWordCount; i != 0; i-- )
{
*pabyDst = *pabySrc;
pabyDst += nDstPixelOffset;
pabySrc += nSrcPixelOffset;
}
return;
}
// source or destination is not contiguous
for( i = 0; i < nWordCount; i++ )
{
memcpy( ((GByte *)pDstData) + i * nDstPixelOffset,
((GByte *)pSrcData) + i * nSrcPixelOffset,
nWordSize );
}
return;
}
/* ==================================================================== */
/* General translation case */
/* ==================================================================== */
for( int iWord = 0; iWord < nWordCount; iWord++ )
{
void *pSrcWord, *pDstWord;
double dfPixelValue=0.0, dfPixelValueI=0.0;
pSrcWord = static_cast(pSrcData) + iWord * nSrcPixelOffset;
pDstWord = static_cast(pDstData) + iWord * nDstPixelOffset;
/* -------------------------------------------------------------------- */
/* Fetch source value based on data type. */
/* -------------------------------------------------------------------- */
switch( eSrcType )
{
case GDT_Byte:
{
GByte byVal = *static_cast(pSrcWord);
switch( eDstType )
{
case GDT_UInt16:
*static_cast(pDstWord) = byVal;
continue;
case GDT_Int16:
*static_cast(pDstWord) = byVal;
continue;
case GDT_UInt32:
*static_cast(pDstWord) = byVal;
continue;
case GDT_Int32:
*static_cast(pDstWord) = byVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
panDstWord[0] = byVal;
panDstWord[1] = 0;
continue;
}
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
panDstWord[0] = byVal;
panDstWord[1] = 0;
continue;
}
default:
break;
}
dfPixelValue = byVal;
}
break;
case GDT_UInt16:
{
GUInt16 nVal = *static_cast(pSrcWord);
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else
byVal = static_cast(nVal);
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_Int16:
if( nVal > 32767 )
nVal = 32767;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt32:
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int32:
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
if( nVal > 32767 )
nVal = 32767;
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
default:
break;
}
dfPixelValue = nVal;
}
break;
case GDT_Int16:
{
GInt16 nVal = *static_cast(pSrcWord);
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else if (nVal < 0)
byVal = 0;
else
byVal = static_cast(nVal);
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_UInt16:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt32:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int32:
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
default:
break;
}
dfPixelValue = nVal;
}
break;
case GDT_Int32:
{
GInt32 nVal = *static_cast(pSrcWord);
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else if (nVal < 0)
byVal = 0;
else
byVal = nVal;
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_UInt16:
if( nVal > 65535 )
nVal = 65535;
else if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int16:
if( nVal > 32767 )
nVal = 32767;
else if( nVal < -32768)
nVal = -32768;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt32:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
if( nVal > 32767 )
nVal = 32767;
else if( nVal < -32768)
nVal = -32768;
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
default:
break;
}
dfPixelValue = nVal;
}
break;
case GDT_UInt32:
{
GUInt32 nVal = *static_cast(pSrcWord);
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else if (nVal < 0)
byVal = 0;
else
byVal = nVal;
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_UInt16:
if( nVal > 65535 )
nVal = 65535;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int16:
if( nVal > 32767 )
nVal = 32767;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int32:
if( nVal > 2147483647UL )
nVal = 2147483647UL;
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
if( nVal > 32767 )
nVal = 32767;
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
if( nVal > 2147483647UL )
nVal = 2147483647UL;
panDstWord[0] = nVal;
panDstWord[1] = 0;
continue;
}
default:
break;
}
dfPixelValue = nVal;
}
break;
case GDT_CInt16:
{
GInt16 *panSrcWord = static_cast(pSrcWord);
GInt16 nVal = panSrcWord[0];
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else if (nVal < 0)
byVal = 0;
else
byVal = static_cast(nVal);
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_Int16:
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt16:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt32:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int32:
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt32:
{
GInt32 *panDstWord = static_cast(pDstWord);
panDstWord[0] = panSrcWord[0];
panDstWord[1] = panSrcWord[1];
continue;
}
default:
break;
}
dfPixelValue = panSrcWord[0];
dfPixelValueI = panSrcWord[1];
}
break;
case GDT_CInt32:
{
GInt32 *panSrcWord = static_cast(pSrcWord);
GInt32 nVal = panSrcWord[0];
switch( eDstType )
{
case GDT_Byte:
{
GByte byVal;
if( nVal > 255 )
byVal = 255;
else if (nVal < 0)
byVal = 0;
else
byVal = nVal;
*static_cast(pDstWord) = byVal;
continue;
}
case GDT_Int16:
if( nVal > 32767 )
nVal = 32767;
else if( nVal < -32768)
nVal = -32768;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt16:
if( nVal > 65535 )
nVal = 65535;
else if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_UInt32:
if( nVal < 0 )
nVal = 0;
*static_cast(pDstWord) = nVal;
continue;
case GDT_Int32:
*static_cast(pDstWord) = nVal;
continue;
case GDT_CInt16:
{
GInt16 *panDstWord = static_cast(pDstWord);
if( nVal > 32767 )
nVal = 32767;
else if( nVal < -32768)
nVal = -32768;
panDstWord[0] = nVal;
nVal = panSrcWord[1];
if( nVal > 32767 )
nVal = 32767;
else if( nVal < -32768)
nVal = -32768;
panDstWord[1] = nVal;
continue;
}
default:
break;
}
dfPixelValue = panSrcWord[0];
dfPixelValueI = panSrcWord[1];
}
break;
case GDT_Float32:
{
float fVal = *static_cast(pSrcWord);
dfPixelValue = fVal;
}
break;
case GDT_Float64:
{
dfPixelValue = *static_cast(pSrcWord);
}
break;
case GDT_CFloat32:
{
float *pafSrcWord = static_cast(pSrcWord);
dfPixelValue = pafSrcWord[0];
dfPixelValueI = pafSrcWord[1];
}
break;
case GDT_CFloat64:
{
double *padfSrcWord = static_cast(pSrcWord);
dfPixelValue = padfSrcWord[0];
dfPixelValueI = padfSrcWord[1];
}
break;
default:
CPLAssert( FALSE );
}
/* -------------------------------------------------------------------- */
/* Set the destination pixel, doing range clipping as needed. */
/* -------------------------------------------------------------------- */
switch( eDstType )
{
case GDT_Byte:
{
GByte *pabyDstWord = static_cast(pDstWord);
dfPixelValue += (float) 0.5;
if( dfPixelValue < 0.0 )
*pabyDstWord = 0;
else if( dfPixelValue > 255.0 )
*pabyDstWord = 255;
else
*pabyDstWord = (GByte) dfPixelValue;
}
break;
case GDT_UInt16:
{
GUInt16 nVal;
dfPixelValue += 0.5;
if( dfPixelValue < 0.0 )
nVal = 0;
else if( dfPixelValue > 65535.0 )
nVal = 65535;
else
nVal = (GUInt16) dfPixelValue;
*static_cast(pDstWord) = nVal;
}
break;
case GDT_Int16:
{
GInt16 nVal;
dfPixelValue += 0.5;
if( dfPixelValue < -32768 )
nVal = -32768;
else if( dfPixelValue > 32767 )
nVal = 32767;
else
nVal = (GInt16) floor(dfPixelValue);
*static_cast(pDstWord) = nVal;
}
break;
case GDT_UInt32:
{
GUInt32 nVal;
dfPixelValue += 0.5;
if( dfPixelValue < 0 )
nVal = 0;
else if( dfPixelValue > 4294967295U )
nVal = 4294967295U;
else
nVal = (GInt32) dfPixelValue;
*static_cast(pDstWord) = nVal;
}
break;
case GDT_Int32:
{
GInt32 nVal;
dfPixelValue += 0.5;
if( dfPixelValue < -2147483647.0 )
nVal = -2147483647;
else if( dfPixelValue > 2147483647 )
nVal = 2147483647;
else
nVal = (GInt32) floor(dfPixelValue);
*static_cast(pDstWord) = nVal;
}
break;
case GDT_Float32:
{
*static_cast(pDstWord) = static_cast(dfPixelValue);
}
break;
case GDT_Float64:
*static_cast(pDstWord) = dfPixelValue;
break;
case GDT_CInt16:
{
GInt16 nVal;
GInt16 *panDstWord = static_cast(pDstWord);
dfPixelValue += 0.5;
dfPixelValueI += 0.5;
if( dfPixelValue < -32768 )
nVal = -32768;
else if( dfPixelValue > 32767 )
nVal = 32767;
else
nVal = (GInt16) floor(dfPixelValue);
panDstWord[0] = nVal;
if( dfPixelValueI < -32768 )
nVal = -32768;
else if( dfPixelValueI > 32767 )
nVal = 32767;
else
nVal = (GInt16) floor(dfPixelValueI);
panDstWord[1] = nVal;
}
break;
case GDT_CInt32:
{
GInt32 nVal;
GInt32 *panDstWord = static_cast(pDstWord);
dfPixelValue += 0.5;
dfPixelValueI += 0.5;
if( dfPixelValue < -2147483647.0 )
nVal = -2147483647;
else if( dfPixelValue > 2147483647 )
nVal = 2147483647;
else
nVal = (GInt32) floor(dfPixelValue);
panDstWord[0] = nVal;
if( dfPixelValueI < -2147483647.0 )
nVal = -2147483647;
else if( dfPixelValueI > 2147483647 )
nVal = 2147483647;
else
nVal = (GInt32) floor(dfPixelValueI);
panDstWord[1] = nVal;
}
break;
case GDT_CFloat32:
{
float *pafDstWord = static_cast(pDstWord);
pafDstWord[0] = static_cast(dfPixelValue);
pafDstWord[1] = static_cast(dfPixelValueI);
}
break;
case GDT_CFloat64:
{
double *padfDstWord = static_cast(pDstWord);
padfDstWord[0] = dfPixelValue;
padfDstWord[1] = dfPixelValueI;
}
break;
default:
CPLAssert( FALSE );
}
} /* next iWord */
}
/************************************************************************/
/* OverviewRasterIO() */
/* */
/* Special work function to utilize available overviews to */
/* more efficiently satisfy downsampled requests. It will */
/* return CE_Failure if there are no appropriate overviews */
/* available but it doesn't emit any error messages. */
/************************************************************************/
CPLErr GDALRasterBand::OverviewRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nPixelSpace, int nLineSpace )
{
GDALRasterBand *poBestOverview = NULL;
int nOverviewCount = GetOverviewCount();
double dfDesiredResolution, dfBestResolution = 1.0;
/* -------------------------------------------------------------------- */
/* Find the Compute the desired resolution. The resolution is */
/* based on the least reduced axis, and represents the number */
/* of source pixels to one destination pixel. */
/* -------------------------------------------------------------------- */
if( (nXSize / (double) nBufXSize) < (nYSize / (double) nBufYSize )
|| nBufYSize == 1 )
dfDesiredResolution = nXSize / (double) nBufXSize;
else
dfDesiredResolution = nYSize / (double) nBufYSize;
/* -------------------------------------------------------------------- */
/* Find the overview level that largest resolution value (most */
/* downsampled) that is still less than (or only a little more) */
/* downsampled than the request. */
/* -------------------------------------------------------------------- */
for( int iOverview = 0; iOverview < nOverviewCount; iOverview++ )
{
GDALRasterBand *poOverview = GetOverview( iOverview );
double dfResolution;
if( (GetXSize() / (double) poOverview->GetXSize())
< (GetYSize() / (double) poOverview->GetYSize()) )
dfResolution =
GetXSize() / (double) poOverview->GetXSize();
else
dfResolution =
GetYSize() / (double) poOverview->GetYSize();
if( dfResolution < dfDesiredResolution * 1.2
&& dfResolution > dfBestResolution )
{
poBestOverview = poOverview;
dfBestResolution = dfResolution;
}
}
/* -------------------------------------------------------------------- */
/* If we didn't find an overview that helps us, just return */
/* indicating failure and the full resolution image will be used. */
/* -------------------------------------------------------------------- */
if( poBestOverview == NULL )
return CE_Failure;
/* -------------------------------------------------------------------- */
/* Recompute the source window in terms of the selected */
/* overview. */
/* -------------------------------------------------------------------- */
int nOXOff, nOYOff, nOXSize, nOYSize;
double dfXRes, dfYRes;
dfXRes = GetXSize() / (double) poBestOverview->GetXSize();
dfYRes = GetYSize() / (double) poBestOverview->GetYSize();
nOXOff = MIN(poBestOverview->GetXSize()-1,(int) (nXOff/dfXRes+0.5));
nOYOff = MIN(poBestOverview->GetYSize()-1,(int) (nYOff/dfYRes+0.5));
nOXSize = MAX(1,(int) (nXSize/dfXRes + 0.5));
nOYSize = MAX(1,(int) (nYSize/dfYRes + 0.5));
if( nOXOff + nOXSize > poBestOverview->GetXSize() )
nOXSize = poBestOverview->GetXSize() - nOXOff;
if( nOYOff + nOYSize > poBestOverview->GetYSize() )
nOYSize = poBestOverview->GetYSize() - nOYOff;
/* -------------------------------------------------------------------- */
/* Recast the call in terms of the new raster layer. */
/* -------------------------------------------------------------------- */
return poBestOverview->RasterIO( eRWFlag, nOXOff, nOYOff, nOXSize, nOYSize,
pData, nBufXSize, nBufYSize, eBufType,
nPixelSpace, nLineSpace );
}
/************************************************************************/
/* BlockBasedRasterIO() */
/* */
/* This convenience function implements a dataset level */
/* RasterIO() interface based on calling down to fetch blocks, */
/* much like the GDALRasterBand::IRasterIO(), but it handles */
/* all bands at once, so that a format driver that handles a */
/* request for different bands of the same block efficiently */
/* (ie. without re-reading interleaved data) will efficiently. */
/* */
/* This method is intended to be called by an overridden */
/* IRasterIO() method in the driver specific GDALDataset */
/* derived class. */
/* */
/* Default internal implementation of RasterIO() ... utilizes */
/* the Block access methods to satisfy the request. This would */
/* normally only be overridden by formats with overviews. */
/* */
/* To keep things relatively simple, this method does not */
/* currently take advantage of some special cases addressed in */
/* GDALRasterBand::IRasterIO(), so it is likely best to only */
/* call it when you know it will help. That is in cases where */
/* data is at 1:1 to the buffer, you don't want to take */
/* advantage of overviews, and you know the driver is */
/* implementing interleaved IO efficiently on a block by block */
/* basis. */
/************************************************************************/
CPLErr
GDALDataset::BlockBasedRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
int nPixelSpace, int nLineSpace,int nBandSpace)
{
GByte **papabySrcBlock = NULL;
GDALRasterBlock *poBlock;
GDALRasterBlock **papoBlocks;
int nLBlockX=-1, nLBlockY=-1, iBufYOff, iBufXOff, iSrcY, iBand;
int nBlockXSize=1, nBlockYSize=1;
CPLErr eErr = CE_None;
GDALDataType eDataType = GDT_Byte;
/* -------------------------------------------------------------------- */
/* Ensure that all bands share a common block size and data type. */
/* -------------------------------------------------------------------- */
for( iBand = 0; iBand < nBandCount; iBand++ )
{
GDALRasterBand *poBand = GetRasterBand( panBandMap[iBand] );
int nThisBlockXSize, nThisBlockYSize;
if( iBand == 0 )
{
poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
eDataType = poBand->GetRasterDataType();
}
else
{
poBand->GetBlockSize( &nThisBlockXSize, &nThisBlockYSize );
if( nThisBlockXSize != nBlockXSize
|| nThisBlockYSize != nBlockYSize )
{
CPLDebug( "GDAL",
"GDALDataset::BlockBasedRasterIO() ... "
"mismatched block sizes, use std method." );
return GDALDataset::IRasterIO( eRWFlag,
nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize,
eBufType,
nBandCount, panBandMap,
nPixelSpace, nLineSpace,
nBandSpace );
}
if( eDataType != poBand->GetRasterDataType()
&& (nXSize != nBufXSize || nYSize != nBufYSize) )
{
CPLDebug( "GDAL",
"GDALDataset::BlockBasedRasterIO() ... "
"mismatched band data types, use std method." );
return GDALDataset::IRasterIO( eRWFlag,
nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize,
eBufType,
nBandCount, panBandMap,
nPixelSpace, nLineSpace,
nBandSpace );
}
}
}
/* ==================================================================== */
/* In this special case at full resolution we step through in */
/* blocks, turning the request over to the per-band */
/* IRasterIO(), but ensuring that all bands of one block are */
/* called before proceeding to the next. */
/* ==================================================================== */
if( nXSize == nBufXSize && nYSize == nBufYSize )
{
int nChunkYSize, nChunkXSize, nChunkXOff, nChunkYOff;
for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff += nChunkYSize )
{
nChunkYSize = nBlockYSize;
nChunkYOff = iBufYOff + nYOff;
nChunkYSize = nBlockYSize - (nChunkYOff % nBlockYSize);
if( nChunkYSize == 0 )
nChunkYSize = nBlockYSize;
if( nChunkYOff + nChunkYSize > nYOff + nYSize )
nChunkYSize = (nYOff + nYSize) - nChunkYOff;
for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff += nChunkXSize )
{
nChunkXSize = nBlockXSize;
nChunkXOff = iBufXOff + nXOff;
nChunkXSize = nBlockXSize - (nChunkXOff % nBlockXSize);
if( nChunkXSize == 0 )
nChunkXSize = nBlockXSize;
if( nChunkXOff + nChunkXSize > nXOff + nXSize )
nChunkXSize = (nXOff + nXSize) - nChunkXOff;
GByte *pabyChunkData;
pabyChunkData = ((GByte *) pData)
+ iBufXOff * nPixelSpace
+ iBufYOff * nLineSpace;
for( iBand = 0; iBand < nBandCount; iBand++ )
{
GDALRasterBand *poBand = GetRasterBand(panBandMap[iBand]);
eErr =
poBand->GDALRasterBand::IRasterIO(
eRWFlag, nChunkXOff, nChunkYOff,
nChunkXSize, nChunkYSize,
pabyChunkData + iBand * nBandSpace,
nChunkXSize, nChunkYSize, eBufType,
nPixelSpace, nLineSpace );
if( eErr != CE_None )
return eErr;
}
}
}
return CE_None;
}
/* ==================================================================== */
/* Loop reading required source blocks to satisfy output */
/* request. This is the most general implementation. */
/* ==================================================================== */
int nBandDataSize = GDALGetDataTypeSize( eDataType ) / 8;
papabySrcBlock = (GByte **) CPLCalloc(sizeof(GByte*),nBandCount);
papoBlocks = (GDALRasterBlock **) CPLCalloc(sizeof(void*),nBandCount);
/* -------------------------------------------------------------------- */
/* Compute stepping increment. */
/* -------------------------------------------------------------------- */
double dfSrcX, dfSrcY, dfSrcXInc, dfSrcYInc;
dfSrcXInc = nXSize / (double) nBufXSize;
dfSrcYInc = nYSize / (double) nBufYSize;
/* -------------------------------------------------------------------- */
/* Loop over buffer computing source locations. */
/* -------------------------------------------------------------------- */
for( iBufYOff = 0; iBufYOff < nBufYSize; iBufYOff++ )
{
int iBufOffset, iSrcOffset;
dfSrcY = (iBufYOff+0.5) * dfSrcYInc + nYOff;
iSrcY = (int) dfSrcY;
iBufOffset = iBufYOff * nLineSpace;
for( iBufXOff = 0; iBufXOff < nBufXSize; iBufXOff++ )
{
int iSrcX;
dfSrcX = (iBufXOff+0.5) * dfSrcXInc + nXOff;
iSrcX = (int) dfSrcX;
/* -------------------------------------------------------------------- */
/* Ensure we have the appropriate block loaded. */
/* -------------------------------------------------------------------- */
if( iSrcX < nLBlockX * nBlockXSize
|| iSrcX >= (nLBlockX+1) * nBlockXSize
|| iSrcY < nLBlockY * nBlockYSize
|| iSrcY >= (nLBlockY+1) * nBlockYSize )
{
nLBlockX = iSrcX / nBlockXSize;
nLBlockY = iSrcY / nBlockYSize;
int bJustInitialize =
eRWFlag == GF_Write
&& nYOff <= nLBlockY * nBlockYSize
&& nYOff + nYSize >= (nLBlockY+1) * nBlockYSize
&& nXOff <= nLBlockX * nBlockXSize
&& nXOff + nXSize >= (nLBlockX+1) * nBlockXSize;
for( iBand = 0; iBand < nBandCount; iBand++ )
{
GDALRasterBand *poBand = GetRasterBand( panBandMap[iBand]);
poBlock = poBand->GetLockedBlockRef( nLBlockX, nLBlockY,
bJustInitialize );
if( poBlock == NULL )
{
eErr = CE_Failure;
goto CleanupAndReturn;
}
if( eRWFlag == GF_Write )
poBlock->MarkDirty();
if( papoBlocks[iBand] != NULL )
papoBlocks[iBand]->DropLock();
papoBlocks[iBand] = poBlock;
papabySrcBlock[iBand] = (GByte *) poBlock->GetDataRef();
if( papabySrcBlock[iBand] == NULL )
{
eErr = CE_Failure;
goto CleanupAndReturn;
}
}
}
/* -------------------------------------------------------------------- */
/* Copy over this pixel of data. */
/* -------------------------------------------------------------------- */
iSrcOffset = (iSrcX - nLBlockX*nBlockXSize
+ (iSrcY - nLBlockY*nBlockYSize) * nBlockXSize)*nBandDataSize;
for( iBand = 0; iBand < nBandCount; iBand++ )
{
GByte *pabySrcBlock = papabySrcBlock[iBand];
int iBandBufOffset = iBufOffset + iBand * nBandSpace;
if( eDataType == eBufType )
{
if( eRWFlag == GF_Read )
memcpy( ((GByte *) pData) + iBandBufOffset,
pabySrcBlock + iSrcOffset, nBandDataSize );
else
memcpy( pabySrcBlock + iSrcOffset,
((GByte *)pData) + iBandBufOffset, nBandDataSize );
}
else
{
/* type to type conversion ... ouch, this is expensive way
of handling single words */
if( eRWFlag == GF_Read )
GDALCopyWords( pabySrcBlock + iSrcOffset, eDataType, 0,
((GByte *) pData) + iBandBufOffset,
eBufType, 0, 1 );
else
GDALCopyWords( ((GByte *) pData) + iBandBufOffset,
eBufType, 0,
pabySrcBlock + iSrcOffset, eDataType, 0,
1 );
}
}
iBufOffset += nPixelSpace;
}
}
/* -------------------------------------------------------------------- */
/* CleanupAndReturn. */
/* -------------------------------------------------------------------- */
CleanupAndReturn:
CPLFree( papabySrcBlock );
if( papoBlocks != NULL )
{
for( iBand = 0; iBand < nBandCount; iBand++ )
{
if( papoBlocks[iBand] != NULL )
papoBlocks[iBand]->DropLock();
}
CPLFree( papoBlocks );
}
return( CE_None );
}