mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-06-19 14:15:21 -06:00
1210 lines
42 KiB
C++
1210 lines
42 KiB
C++
/******************************************************************************
|
|
* $Id: memdataset.cpp 28899 2015-04-14 09:27:00Z rouault $
|
|
*
|
|
* Project: Memory Array Translator
|
|
* Purpose: Complete implementation.
|
|
* Author: Frank Warmerdam, warmerdam@pobox.com
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2000, Frank Warmerdam
|
|
* Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
|
|
*
|
|
* 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 "memdataset.h"
|
|
#include "cpl_string.h"
|
|
|
|
CPL_CVSID("$Id: memdataset.cpp 28899 2015-04-14 09:27:00Z rouault $");
|
|
|
|
/************************************************************************/
|
|
/* MEMCreateRasterBand() */
|
|
/************************************************************************/
|
|
|
|
GDALRasterBandH MEMCreateRasterBand( GDALDataset *poDS, int nBand,
|
|
GByte *pabyData, GDALDataType eType,
|
|
int nPixelOffset, int nLineOffset,
|
|
int bAssumeOwnership )
|
|
|
|
{
|
|
return (GDALRasterBandH)
|
|
new MEMRasterBand( poDS, nBand, pabyData, eType, nPixelOffset,
|
|
nLineOffset, bAssumeOwnership );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* MEMRasterBand() */
|
|
/************************************************************************/
|
|
|
|
MEMRasterBand::MEMRasterBand( GDALDataset *poDS, int nBand,
|
|
GByte *pabyDataIn, GDALDataType eTypeIn,
|
|
GSpacing nPixelOffsetIn, GSpacing nLineOffsetIn,
|
|
int bAssumeOwnership, const char * pszPixelType)
|
|
|
|
{
|
|
//CPLDebug( "MEM", "MEMRasterBand(%p)", this );
|
|
|
|
this->poDS = poDS;
|
|
this->nBand = nBand;
|
|
|
|
this->eAccess = poDS->GetAccess();
|
|
|
|
eDataType = eTypeIn;
|
|
|
|
nBlockXSize = poDS->GetRasterXSize();
|
|
nBlockYSize = 1;
|
|
|
|
if( nPixelOffsetIn == 0 )
|
|
nPixelOffsetIn = GDALGetDataTypeSize(eTypeIn) / 8;
|
|
|
|
if( nLineOffsetIn == 0 )
|
|
nLineOffsetIn = nPixelOffsetIn * (size_t)nBlockXSize;
|
|
|
|
nPixelOffset = nPixelOffsetIn;
|
|
nLineOffset = nLineOffsetIn;
|
|
bOwnData = bAssumeOwnership;
|
|
|
|
pabyData = pabyDataIn;
|
|
|
|
bNoDataSet = FALSE;
|
|
|
|
poColorTable = NULL;
|
|
|
|
eColorInterp = GCI_Undefined;
|
|
|
|
papszCategoryNames = NULL;
|
|
dfOffset = 0.0;
|
|
dfScale = 1.0;
|
|
pszUnitType = NULL;
|
|
psSavedHistograms = NULL;
|
|
|
|
if( pszPixelType && EQUAL(pszPixelType,"SIGNEDBYTE") )
|
|
this->SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~MEMRasterBand() */
|
|
/************************************************************************/
|
|
|
|
MEMRasterBand::~MEMRasterBand()
|
|
|
|
{
|
|
//CPLDebug( "MEM", "~MEMRasterBand(%p)", this );
|
|
if( bOwnData )
|
|
{
|
|
//CPLDebug( "MEM", "~MEMRasterBand() - free raw data." );
|
|
VSIFree( pabyData );
|
|
}
|
|
|
|
if( poColorTable != NULL )
|
|
delete poColorTable;
|
|
|
|
CPLFree( pszUnitType );
|
|
CSLDestroy( papszCategoryNames );
|
|
|
|
if (psSavedHistograms != NULL)
|
|
CPLDestroyXMLNode(psSavedHistograms);
|
|
}
|
|
|
|
|
|
/************************************************************************/
|
|
/* IReadBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::IReadBlock( CPL_UNUSED int nBlockXOff,
|
|
int nBlockYOff,
|
|
void * pImage )
|
|
{
|
|
int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
|
|
CPLAssert( nBlockXOff == 0 );
|
|
|
|
if( nPixelOffset == nWordSize )
|
|
{
|
|
memcpy( pImage,
|
|
pabyData + nLineOffset*(size_t)nBlockYOff,
|
|
nPixelOffset * nBlockXSize );
|
|
}
|
|
else
|
|
{
|
|
GByte *pabyCur = pabyData + nLineOffset * (size_t)nBlockYOff;
|
|
|
|
for( int iPixel = 0; iPixel < nBlockXSize; iPixel++ )
|
|
{
|
|
memcpy( ((GByte *) pImage) + iPixel*nWordSize,
|
|
pabyCur + iPixel*nPixelOffset,
|
|
nWordSize );
|
|
}
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IWriteBlock() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::IWriteBlock( CPL_UNUSED int nBlockXOff,
|
|
int nBlockYOff,
|
|
void * pImage )
|
|
{
|
|
int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
|
|
CPLAssert( nBlockXOff == 0 );
|
|
|
|
if( nPixelOffset == nWordSize )
|
|
{
|
|
memcpy( pabyData+nLineOffset*(size_t)nBlockYOff,
|
|
pImage,
|
|
nPixelOffset * nBlockXSize );
|
|
}
|
|
else
|
|
{
|
|
GByte *pabyCur = pabyData + nLineOffset*(size_t)nBlockYOff;
|
|
|
|
for( int iPixel = 0; iPixel < nBlockXSize; iPixel++ )
|
|
{
|
|
memcpy( pabyCur + iPixel*nPixelOffset,
|
|
((GByte *) pImage) + iPixel*nWordSize,
|
|
nWordSize );
|
|
}
|
|
}
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
GSpacing nPixelSpaceBuf,
|
|
GSpacing nLineSpaceBuf,
|
|
GDALRasterIOExtraArg* psExtraArg )
|
|
{
|
|
if( nXSize != nBufXSize || nYSize != nBufYSize )
|
|
{
|
|
return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
|
|
pData, nBufXSize, nBufYSize,
|
|
eBufType,
|
|
nPixelSpaceBuf, nLineSpaceBuf,
|
|
psExtraArg);
|
|
}
|
|
|
|
// In case block based I/O has been done before
|
|
FlushCache();
|
|
|
|
if( eRWFlag == GF_Read )
|
|
{
|
|
for(int iLine=0;iLine<nYSize;iLine++)
|
|
{
|
|
GDALCopyWords( pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
|
|
eDataType,
|
|
nPixelOffset,
|
|
((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
|
|
eBufType,
|
|
nPixelSpaceBuf,
|
|
nXSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int iLine=0;iLine<nYSize;iLine++)
|
|
{
|
|
GDALCopyWords( ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
|
|
eBufType,
|
|
nPixelSpaceBuf,
|
|
pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
|
|
eDataType,
|
|
nPixelOffset,
|
|
nXSize);
|
|
}
|
|
}
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IRasterIO() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::IRasterIO( GDALRWFlag eRWFlag,
|
|
int nXOff, int nYOff, int nXSize, int nYSize,
|
|
void * pData, int nBufXSize, int nBufYSize,
|
|
GDALDataType eBufType,
|
|
int nBandCount, int *panBandMap,
|
|
GSpacing nPixelSpaceBuf,
|
|
GSpacing nLineSpaceBuf,
|
|
GSpacing nBandSpaceBuf,
|
|
GDALRasterIOExtraArg* psExtraArg)
|
|
{
|
|
int eBufTypeSize = GDALGetDataTypeSize(eBufType) / 8;
|
|
|
|
/* Detect if we have a pixel-interleaved buffer and a pixel-interleaved dataset */
|
|
if( nXSize == nBufXSize && nYSize == nBufYSize &&
|
|
nBandCount == nBands && nBands > 1 &&
|
|
nBandSpaceBuf == eBufTypeSize &&
|
|
nPixelSpaceBuf == nBandSpaceBuf * nBands )
|
|
{
|
|
GDALDataType eDT = GDT_Unknown;
|
|
GByte* pabyData = NULL;
|
|
GSpacing nPixelOffset = 0;
|
|
GSpacing nLineOffset = 0;
|
|
int eDTSize = 0;
|
|
int iBandIndex;
|
|
for( iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++ )
|
|
{
|
|
if( panBandMap[iBandIndex] != iBandIndex + 1 )
|
|
break;
|
|
MEMRasterBand *poBand = (MEMRasterBand*) GetRasterBand(iBandIndex + 1);
|
|
if( iBandIndex == 0 )
|
|
{
|
|
eDT = poBand->GetRasterDataType();
|
|
pabyData = poBand->pabyData;
|
|
nPixelOffset = poBand->nPixelOffset;
|
|
nLineOffset = poBand->nLineOffset;
|
|
eDTSize = GDALGetDataTypeSize(eDT) / 8;
|
|
if( nPixelOffset != nBands * eDTSize )
|
|
break;
|
|
}
|
|
else if( poBand->GetRasterDataType() != eDT ||
|
|
nPixelOffset != poBand->nPixelOffset ||
|
|
nLineOffset != poBand->nLineOffset ||
|
|
poBand->pabyData != pabyData + iBandIndex * eDTSize )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if( iBandIndex == nBandCount )
|
|
{
|
|
FlushCache();
|
|
if( eRWFlag == GF_Read )
|
|
{
|
|
for(int iLine=0;iLine<nYSize;iLine++)
|
|
{
|
|
GDALCopyWords( pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
|
|
eDT,
|
|
eDTSize,
|
|
((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
|
|
eBufType,
|
|
eBufTypeSize,
|
|
nXSize * nBands);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int iLine=0;iLine<nYSize;iLine++)
|
|
{
|
|
GDALCopyWords( ((GByte*)pData) + nLineSpaceBuf*(size_t)iLine,
|
|
eBufType,
|
|
eBufTypeSize,
|
|
pabyData + nLineOffset*(size_t)(iLine + nYOff) + nXOff*nPixelOffset,
|
|
eDT,
|
|
eDTSize,
|
|
nXSize * nBands);
|
|
}
|
|
}
|
|
return CE_None;
|
|
}
|
|
}
|
|
|
|
GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
|
|
void *pProgressDataGlobal = psExtraArg->pProgressData;
|
|
|
|
CPLErr eErr = CE_None;
|
|
for( int iBandIndex = 0;
|
|
iBandIndex < nBandCount && eErr == CE_None;
|
|
iBandIndex++ )
|
|
{
|
|
GDALRasterBand *poBand = GetRasterBand(panBandMap[iBandIndex]);
|
|
GByte *pabyBandData;
|
|
|
|
if (poBand == NULL)
|
|
{
|
|
eErr = CE_Failure;
|
|
break;
|
|
}
|
|
|
|
pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpaceBuf;
|
|
|
|
psExtraArg->pfnProgress = GDALScaledProgress;
|
|
psExtraArg->pProgressData =
|
|
GDALCreateScaledProgress( 1.0 * iBandIndex / nBandCount,
|
|
1.0 * (iBandIndex + 1) / nBandCount,
|
|
pfnProgressGlobal,
|
|
pProgressDataGlobal );
|
|
|
|
eErr = poBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
|
|
(void *) pabyBandData, nBufXSize, nBufYSize,
|
|
eBufType, nPixelSpaceBuf, nLineSpaceBuf,
|
|
psExtraArg);
|
|
|
|
GDALDestroyScaledProgress( psExtraArg->pProgressData );
|
|
}
|
|
|
|
psExtraArg->pfnProgress = pfnProgressGlobal;
|
|
psExtraArg->pProgressData = pProgressDataGlobal;
|
|
|
|
return eErr;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetNoDataValue() */
|
|
/************************************************************************/
|
|
double MEMRasterBand::GetNoDataValue( int *pbSuccess )
|
|
|
|
{
|
|
if( pbSuccess )
|
|
*pbSuccess = bNoDataSet;
|
|
|
|
if( bNoDataSet )
|
|
return dfNoData;
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetNoDataValue() */
|
|
/************************************************************************/
|
|
CPLErr MEMRasterBand::SetNoDataValue( double dfNewValue )
|
|
{
|
|
dfNoData = dfNewValue;
|
|
bNoDataSet = TRUE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
GDALColorInterp MEMRasterBand::GetColorInterpretation()
|
|
|
|
{
|
|
if( poColorTable != NULL )
|
|
return GCI_PaletteIndex;
|
|
else
|
|
return eColorInterp;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorInterpretation() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetColorInterpretation( GDALColorInterp eGCI )
|
|
|
|
{
|
|
eColorInterp = eGCI;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetColorTable() */
|
|
/************************************************************************/
|
|
|
|
GDALColorTable *MEMRasterBand::GetColorTable()
|
|
|
|
{
|
|
return poColorTable;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetColorTable() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetColorTable( GDALColorTable *poCT )
|
|
|
|
{
|
|
if( poColorTable != NULL )
|
|
delete poColorTable;
|
|
|
|
if( poCT == NULL )
|
|
poColorTable = NULL;
|
|
else
|
|
poColorTable = poCT->Clone();
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetUnitType() */
|
|
/************************************************************************/
|
|
|
|
const char *MEMRasterBand::GetUnitType()
|
|
|
|
{
|
|
if( pszUnitType == NULL )
|
|
return "";
|
|
else
|
|
return pszUnitType;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetUnitType() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetUnitType( const char *pszNewValue )
|
|
|
|
{
|
|
CPLFree( pszUnitType );
|
|
|
|
if( pszNewValue == NULL )
|
|
pszUnitType = NULL;
|
|
else
|
|
pszUnitType = CPLStrdup(pszNewValue);
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetOffset() */
|
|
/************************************************************************/
|
|
|
|
double MEMRasterBand::GetOffset( int *pbSuccess )
|
|
|
|
{
|
|
if( pbSuccess != NULL )
|
|
*pbSuccess = TRUE;
|
|
|
|
return dfOffset;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetOffset() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetOffset( double dfNewOffset )
|
|
|
|
{
|
|
dfOffset = dfNewOffset;
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetScale() */
|
|
/************************************************************************/
|
|
|
|
double MEMRasterBand::GetScale( int *pbSuccess )
|
|
|
|
{
|
|
if( pbSuccess != NULL )
|
|
*pbSuccess = TRUE;
|
|
|
|
return dfScale;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetScale() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetScale( double dfNewScale )
|
|
|
|
{
|
|
dfScale = dfNewScale;
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetCategoryNames() */
|
|
/************************************************************************/
|
|
|
|
char **MEMRasterBand::GetCategoryNames()
|
|
|
|
{
|
|
return papszCategoryNames;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetCategoryNames() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetCategoryNames( char ** papszNewNames )
|
|
|
|
{
|
|
CSLDestroy( papszCategoryNames );
|
|
papszCategoryNames = CSLDuplicate( papszNewNames );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetDefaultHistogram() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
|
|
int nBuckets, GUIntBig *panHistogram)
|
|
|
|
{
|
|
CPLXMLNode *psNode;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we have a matching histogram we should replace? */
|
|
/* -------------------------------------------------------------------- */
|
|
psNode = PamFindMatchingHistogram( psSavedHistograms,
|
|
dfMin, dfMax, nBuckets,
|
|
TRUE, TRUE );
|
|
if( psNode != NULL )
|
|
{
|
|
/* blow this one away */
|
|
CPLRemoveXMLChild( psSavedHistograms, psNode );
|
|
CPLDestroyXMLNode( psNode );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Translate into a histogram XML tree. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLXMLNode *psHistItem;
|
|
|
|
psHistItem = PamHistogramToXMLTree( dfMin, dfMax, nBuckets,
|
|
panHistogram, TRUE, FALSE );
|
|
if( psHistItem == NULL )
|
|
return CE_Failure;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Insert our new default histogram at the front of the */
|
|
/* histogram list so that it will be the default histogram. */
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
if( psSavedHistograms == NULL )
|
|
psSavedHistograms = CPLCreateXMLNode( NULL, CXT_Element,
|
|
"Histograms" );
|
|
|
|
psHistItem->psNext = psSavedHistograms->psChild;
|
|
psSavedHistograms->psChild = psHistItem;
|
|
|
|
return CE_None;
|
|
}
|
|
/************************************************************************/
|
|
/* GetDefaultHistogram() */
|
|
/************************************************************************/
|
|
|
|
CPLErr
|
|
MEMRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
|
|
int *pnBuckets, GUIntBig **ppanHistogram,
|
|
int bForce,
|
|
GDALProgressFunc pfnProgress,
|
|
void *pProgressData )
|
|
|
|
{
|
|
if( psSavedHistograms != NULL )
|
|
{
|
|
CPLXMLNode *psXMLHist;
|
|
|
|
for( psXMLHist = psSavedHistograms->psChild;
|
|
psXMLHist != NULL; psXMLHist = psXMLHist->psNext )
|
|
{
|
|
int bApprox, bIncludeOutOfRange;
|
|
|
|
if( psXMLHist->eType != CXT_Element
|
|
|| !EQUAL(psXMLHist->pszValue,"HistItem") )
|
|
continue;
|
|
|
|
if( PamParseHistogram( psXMLHist, pdfMin, pdfMax, pnBuckets,
|
|
ppanHistogram, &bIncludeOutOfRange,
|
|
&bApprox ) )
|
|
return CE_None;
|
|
else
|
|
return CE_Failure;
|
|
}
|
|
}
|
|
|
|
return GDALRasterBand::GetDefaultHistogram( pdfMin, pdfMax, pnBuckets,
|
|
ppanHistogram, bForce,
|
|
pfnProgress,pProgressData);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ==================================================================== */
|
|
/* MEMDataset */
|
|
/* ==================================================================== */
|
|
/************************************************************************/
|
|
|
|
|
|
/************************************************************************/
|
|
/* MEMDataset() */
|
|
/************************************************************************/
|
|
|
|
MEMDataset::MEMDataset()
|
|
|
|
{
|
|
pszProjection = NULL;
|
|
bGeoTransformSet = FALSE;
|
|
adfGeoTransform[0] = 0.0;
|
|
adfGeoTransform[1] = 1.0;
|
|
adfGeoTransform[2] = 0.0;
|
|
adfGeoTransform[3] = 0.0;
|
|
adfGeoTransform[4] = 0.0;
|
|
adfGeoTransform[5] = -1.0;
|
|
|
|
nGCPCount = 0;
|
|
pasGCPs = NULL;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~MEMDataset() */
|
|
/************************************************************************/
|
|
|
|
MEMDataset::~MEMDataset()
|
|
|
|
{
|
|
FlushCache();
|
|
CPLFree( pszProjection );
|
|
|
|
GDALDeinitGCPs( nGCPCount, pasGCPs );
|
|
CPLFree( pasGCPs );
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetProjectionRef() */
|
|
/************************************************************************/
|
|
|
|
const char *MEMDataset::GetProjectionRef()
|
|
|
|
{
|
|
if( pszProjection == NULL )
|
|
return "";
|
|
else
|
|
return pszProjection;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetProjection() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::SetProjection( const char *pszProjectionIn )
|
|
|
|
{
|
|
CPLFree( pszProjection );
|
|
pszProjection = CPLStrdup( pszProjectionIn );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::GetGeoTransform( double *padfGeoTransform )
|
|
|
|
{
|
|
memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
|
|
if( bGeoTransformSet )
|
|
return CE_None;
|
|
else
|
|
return CE_Failure;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGeoTransform() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::SetGeoTransform( double *padfGeoTransform )
|
|
|
|
{
|
|
memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
|
|
bGeoTransformSet = TRUE;
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetInternalHandle() */
|
|
/************************************************************************/
|
|
|
|
void *MEMDataset::GetInternalHandle( const char * pszRequest)
|
|
|
|
{
|
|
// check for MEMORYnnn string in pszRequest (nnnn can be up to 10
|
|
// digits, or even omitted)
|
|
if( EQUALN(pszRequest,"MEMORY",6))
|
|
{
|
|
if(int BandNumber = CPLScanLong(&pszRequest[6], 10))
|
|
{
|
|
MEMRasterBand *RequestedRasterBand =
|
|
(MEMRasterBand *)GetRasterBand(BandNumber);
|
|
|
|
// we're within a MEMDataset so the only thing a RasterBand
|
|
// could be is a MEMRasterBand
|
|
|
|
if( RequestedRasterBand != NULL )
|
|
{
|
|
// return the internal band data pointer
|
|
return(RequestedRasterBand->GetData());
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/************************************************************************/
|
|
/* GetGCPCount() */
|
|
/************************************************************************/
|
|
|
|
int MEMDataset::GetGCPCount()
|
|
|
|
{
|
|
return nGCPCount;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPProjection() */
|
|
/************************************************************************/
|
|
|
|
const char *MEMDataset::GetGCPProjection()
|
|
|
|
{
|
|
return osGCPProjection;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGCPs() */
|
|
/************************************************************************/
|
|
|
|
const GDAL_GCP *MEMDataset::GetGCPs()
|
|
|
|
{
|
|
return pasGCPs;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetGCPs() */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::SetGCPs( int nNewCount, const GDAL_GCP *pasNewGCPList,
|
|
const char *pszGCPProjection )
|
|
|
|
{
|
|
GDALDeinitGCPs( nGCPCount, pasGCPs );
|
|
CPLFree( pasGCPs );
|
|
|
|
if( pszGCPProjection == NULL )
|
|
osGCPProjection = "";
|
|
else
|
|
osGCPProjection = pszGCPProjection;
|
|
|
|
nGCPCount = nNewCount;
|
|
pasGCPs = GDALDuplicateGCPs( nGCPCount, pasNewGCPList );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AddBand() */
|
|
/* */
|
|
/* Add a new band to the dataset, allowing creation options to */
|
|
/* specify the existing memory to use, otherwise create new */
|
|
/* memory. */
|
|
/************************************************************************/
|
|
|
|
CPLErr MEMDataset::AddBand( GDALDataType eType, char **papszOptions )
|
|
|
|
{
|
|
int nBandId = GetRasterCount() + 1;
|
|
GByte *pData;
|
|
int nPixelSize = (GDALGetDataTypeSize(eType) / 8);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we need to allocate the memory ourselves? This is the */
|
|
/* simple case. */
|
|
/* -------------------------------------------------------------------- */
|
|
if( CSLFetchNameValue( papszOptions, "DATAPOINTER" ) == NULL )
|
|
{
|
|
|
|
pData = (GByte *)
|
|
VSICalloc(nPixelSize * GetRasterXSize(), GetRasterYSize() );
|
|
|
|
if( pData == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Unable to create band arrays ... out of memory." );
|
|
return CE_Failure;
|
|
}
|
|
|
|
SetBand( nBandId,
|
|
new MEMRasterBand( this, nBandId, pData, eType, nPixelSize,
|
|
nPixelSize * GetRasterXSize(), TRUE ) );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Get layout of memory and other flags. */
|
|
/* -------------------------------------------------------------------- */
|
|
const char *pszOption;
|
|
GSpacing nPixelOffset, nLineOffset;
|
|
const char *pszDataPointer;
|
|
|
|
pszDataPointer = CSLFetchNameValue(papszOptions,"DATAPOINTER");
|
|
pData = (GByte *) CPLScanPointer(pszDataPointer,
|
|
strlen(pszDataPointer));
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"PIXELOFFSET");
|
|
if( pszOption == NULL )
|
|
nPixelOffset = nPixelSize;
|
|
else
|
|
nPixelOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"LINEOFFSET");
|
|
if( pszOption == NULL )
|
|
nLineOffset = GetRasterXSize() * (size_t)nPixelOffset;
|
|
else
|
|
nLineOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
|
|
|
|
SetBand( nBandId,
|
|
new MEMRasterBand( this, nBandId, pData, eType,
|
|
nPixelOffset, nLineOffset, FALSE ) );
|
|
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *MEMDataset::Open( GDALOpenInfo * poOpenInfo )
|
|
|
|
{
|
|
char **papszOptions;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we have the special filename signature for MEM format */
|
|
/* description strings? */
|
|
/* -------------------------------------------------------------------- */
|
|
if( !EQUALN(poOpenInfo->pszFilename,"MEM:::",6)
|
|
|| poOpenInfo->fpL != NULL )
|
|
return NULL;
|
|
|
|
papszOptions = CSLTokenizeStringComplex(poOpenInfo->pszFilename+6, ",",
|
|
TRUE, FALSE );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Verify we have all required fields */
|
|
/* -------------------------------------------------------------------- */
|
|
if( CSLFetchNameValue( papszOptions, "PIXELS" ) == NULL
|
|
|| CSLFetchNameValue( papszOptions, "LINES" ) == NULL
|
|
|| CSLFetchNameValue( papszOptions, "DATAPOINTER" ) == NULL )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"Missing required field (one of PIXELS, LINES or DATAPOINTER)\n"
|
|
"Unable to access in-memory array." );
|
|
|
|
CSLDestroy( papszOptions );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the new MEMDataset object. */
|
|
/* -------------------------------------------------------------------- */
|
|
MEMDataset *poDS;
|
|
|
|
poDS = new MEMDataset();
|
|
|
|
poDS->nRasterXSize = atoi(CSLFetchNameValue(papszOptions,"PIXELS"));
|
|
poDS->nRasterYSize = atoi(CSLFetchNameValue(papszOptions,"LINES"));
|
|
poDS->eAccess = GA_Update;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Extract other information. */
|
|
/* -------------------------------------------------------------------- */
|
|
const char *pszOption;
|
|
GDALDataType eType;
|
|
int nBands;
|
|
GSpacing nPixelOffset, nLineOffset, nBandOffset;
|
|
const char *pszDataPointer;
|
|
GByte *pabyData;
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"BANDS");
|
|
if( pszOption == NULL )
|
|
nBands = 1;
|
|
else
|
|
{
|
|
nBands = atoi(pszOption);
|
|
}
|
|
|
|
if (!GDALCheckDatasetDimensions(poDS->nRasterXSize, poDS->nRasterYSize) ||
|
|
!GDALCheckBandCount(nBands, TRUE))
|
|
{
|
|
CSLDestroy( papszOptions );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"DATATYPE");
|
|
if( pszOption == NULL )
|
|
eType = GDT_Byte;
|
|
else
|
|
{
|
|
if( atoi(pszOption) > 0 && atoi(pszOption) < GDT_TypeCount )
|
|
eType = (GDALDataType) atoi(pszOption);
|
|
else
|
|
{
|
|
int iType;
|
|
|
|
eType = GDT_Unknown;
|
|
for( iType = 0; iType < GDT_TypeCount; iType++ )
|
|
{
|
|
if( EQUAL(GDALGetDataTypeName((GDALDataType) iType),
|
|
pszOption) )
|
|
{
|
|
eType = (GDALDataType) iType;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( eType == GDT_Unknown )
|
|
{
|
|
CPLError( CE_Failure, CPLE_AppDefined,
|
|
"DATATYPE=%s not recognised.",
|
|
pszOption );
|
|
CSLDestroy( papszOptions );
|
|
delete poDS;
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"PIXELOFFSET");
|
|
if( pszOption == NULL )
|
|
nPixelOffset = GDALGetDataTypeSize(eType) / 8;
|
|
else
|
|
nPixelOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"LINEOFFSET");
|
|
if( pszOption == NULL )
|
|
nLineOffset = poDS->nRasterXSize * (size_t) nPixelOffset;
|
|
else
|
|
nLineOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
|
|
|
|
pszOption = CSLFetchNameValue(papszOptions,"BANDOFFSET");
|
|
if( pszOption == NULL )
|
|
nBandOffset = nLineOffset * (size_t) poDS->nRasterYSize;
|
|
else
|
|
nBandOffset = CPLScanUIntBig(pszOption, strlen(pszOption));
|
|
|
|
pszDataPointer = CSLFetchNameValue(papszOptions,"DATAPOINTER");
|
|
pabyData = (GByte *) CPLScanPointer( pszDataPointer,
|
|
strlen(pszDataPointer) );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( int iBand = 0; iBand < nBands; iBand++ )
|
|
{
|
|
poDS->SetBand( iBand+1,
|
|
new MEMRasterBand( poDS, iBand+1,
|
|
pabyData + iBand * nBandOffset,
|
|
eType, nPixelOffset, nLineOffset,
|
|
FALSE ) );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to return a regular handle on the file. */
|
|
/* -------------------------------------------------------------------- */
|
|
CSLDestroy( papszOptions );
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *MEMDataset::Create( CPL_UNUSED const char * pszFilename,
|
|
int nXSize,
|
|
int nYSize,
|
|
int nBands,
|
|
GDALDataType eType,
|
|
char **papszOptions )
|
|
{
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Do we want a pixel interleaved buffer? I mostly care about */
|
|
/* this to test pixel interleaved io in other contexts, but it */
|
|
/* could be useful to create a directly accessable buffer for */
|
|
/* some apps. */
|
|
/* -------------------------------------------------------------------- */
|
|
int bPixelInterleaved = FALSE;
|
|
const char *pszOption = CSLFetchNameValue( papszOptions, "INTERLEAVE" );
|
|
if( pszOption && EQUAL(pszOption,"PIXEL") )
|
|
bPixelInterleaved = TRUE;
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* First allocate band data, verifying that we can get enough */
|
|
/* memory. */
|
|
/* -------------------------------------------------------------------- */
|
|
std::vector<GByte*> apbyBandData;
|
|
int iBand;
|
|
int nWordSize = GDALGetDataTypeSize(eType) / 8;
|
|
int bAllocOK = TRUE;
|
|
|
|
GUIntBig nGlobalBigSize = (GUIntBig)nWordSize * nBands * nXSize * nYSize;
|
|
size_t nGlobalSize = (size_t)nGlobalBigSize;
|
|
#if SIZEOF_VOIDP == 4
|
|
if( (GUIntBig)nGlobalSize != nGlobalBigSize )
|
|
{
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Cannot allocate " CPL_FRMT_GUIB " bytes on this platform.",
|
|
nGlobalBigSize );
|
|
return NULL;
|
|
}
|
|
#endif
|
|
|
|
if( bPixelInterleaved )
|
|
{
|
|
apbyBandData.push_back(
|
|
(GByte *) VSICalloc( 1, nGlobalSize ) );
|
|
|
|
if( apbyBandData[0] == NULL )
|
|
bAllocOK = FALSE;
|
|
else
|
|
{
|
|
for( iBand = 1; iBand < nBands; iBand++ )
|
|
apbyBandData.push_back( apbyBandData[0] + iBand * nWordSize );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( iBand = 0; iBand < nBands; iBand++ )
|
|
{
|
|
apbyBandData.push_back(
|
|
(GByte *) VSICalloc( 1, ((size_t)nWordSize) * nXSize * nYSize ) );
|
|
if( apbyBandData[iBand] == NULL )
|
|
{
|
|
bAllocOK = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !bAllocOK )
|
|
{
|
|
for( iBand = 0; iBand < (int) apbyBandData.size(); iBand++ )
|
|
{
|
|
if( apbyBandData[iBand] )
|
|
VSIFree( apbyBandData[iBand] );
|
|
}
|
|
CPLError( CE_Failure, CPLE_OutOfMemory,
|
|
"Unable to create band arrays ... out of memory." );
|
|
return NULL;
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create the new GTiffDataset object. */
|
|
/* -------------------------------------------------------------------- */
|
|
MEMDataset *poDS;
|
|
|
|
poDS = new MEMDataset();
|
|
|
|
poDS->nRasterXSize = nXSize;
|
|
poDS->nRasterYSize = nYSize;
|
|
poDS->eAccess = GA_Update;
|
|
|
|
const char *pszPixelType = CSLFetchNameValue( papszOptions, "PIXELTYPE" );
|
|
if( pszPixelType && EQUAL(pszPixelType,"SIGNEDBYTE") )
|
|
poDS->SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
|
|
|
|
if( bPixelInterleaved )
|
|
poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Create band information objects. */
|
|
/* -------------------------------------------------------------------- */
|
|
for( iBand = 0; iBand < nBands; iBand++ )
|
|
{
|
|
MEMRasterBand *poNewBand;
|
|
|
|
if( bPixelInterleaved )
|
|
poNewBand = new MEMRasterBand( poDS, iBand+1, apbyBandData[iBand],
|
|
eType, nWordSize * nBands, 0,
|
|
iBand == 0 );
|
|
else
|
|
poNewBand = new MEMRasterBand( poDS, iBand+1, apbyBandData[iBand],
|
|
eType, 0, 0, TRUE );
|
|
|
|
poDS->SetBand( iBand+1, poNewBand );
|
|
}
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Try to return a regular handle on the file. */
|
|
/* -------------------------------------------------------------------- */
|
|
return poDS;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* MEMDatasetIdentify() */
|
|
/************************************************************************/
|
|
|
|
static int MEMDatasetIdentify( GDALOpenInfo * poOpenInfo )
|
|
{
|
|
return (strncmp(poOpenInfo->pszFilename, "MEM:::", 6) == 0 &&
|
|
poOpenInfo->fpL == NULL);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* MEMDatasetDelete() */
|
|
/************************************************************************/
|
|
|
|
static CPLErr MEMDatasetDelete(CPL_UNUSED const char* fileName)
|
|
{
|
|
/* Null implementation, so that people can Delete("MEM:::") */
|
|
return CE_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GDALRegister_MEM() */
|
|
/************************************************************************/
|
|
|
|
void GDALRegister_MEM()
|
|
|
|
{
|
|
GDALDriver *poDriver;
|
|
|
|
if( GDALGetDriverByName( "MEM" ) == NULL )
|
|
{
|
|
poDriver = new GDALDriver();
|
|
|
|
poDriver->SetDescription( "MEM" );
|
|
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
|
|
"In Memory Raster" );
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
|
|
"Byte Int16 UInt16 Int32 UInt32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64" );
|
|
|
|
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
|
|
"<CreationOptionList>"
|
|
" <Option name='INTERLEAVE' type='string-select' default='BAND'>"
|
|
" <Value>BAND</Value>"
|
|
" <Value>PIXEL</Value>"
|
|
" </Option>"
|
|
"</CreationOptionList>" );
|
|
|
|
/* Define GDAL_NO_OPEN_FOR_MEM_DRIVER macro to undefine Open() method for MEM driver. */
|
|
/* Otherwise, bad user input can trigger easily a GDAL crash as random pointers can be passed as a string. */
|
|
/* All code in GDAL tree using the MEM driver use the Create() method only, so Open() */
|
|
/* is not needed, except for esoteric uses */
|
|
#ifndef GDAL_NO_OPEN_FOR_MEM_DRIVER
|
|
poDriver->pfnOpen = MEMDataset::Open;
|
|
poDriver->pfnIdentify = MEMDatasetIdentify;
|
|
#endif
|
|
poDriver->pfnCreate = MEMDataset::Create;
|
|
poDriver->pfnDelete = MEMDatasetDelete;
|
|
|
|
GetGDALDriverManager()->RegisterDriver( poDriver );
|
|
}
|
|
}
|