ultimatepp/bazaar/plugin/gdal/frmts/nitf/nitfrasterband.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

1008 lines
36 KiB
C++

/******************************************************************************
* $Id: nitfrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $
*
* Project: NITF Read/Write Translator
* Purpose: NITFRasterBand (and related proxy band) implementations.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2002, Frank Warmerdam
* Copyright (c) 2011-2013, Even Rouault <even dot rouault at mines-paris dot org>
*
* Portions Copyright (c) Her majesty the Queen in right of Canada as
* represented by the Minister of National Defence, 2006.
*
* 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 "nitfdataset.h"
#include "cpl_string.h"
#include "cpl_csv.h"
CPL_CVSID("$Id: nitfrasterband.cpp 28899 2015-04-14 09:27:00Z rouault $");
/************************************************************************/
/* NITFMakeColorTable() */
/************************************************************************/
static GDALColorTable* NITFMakeColorTable(NITFImage* psImage, NITFBandInfo *psBandInfo)
{
GDALColorTable* poColorTable = NULL;
if( psBandInfo->nSignificantLUTEntries > 0 )
{
int iColor;
poColorTable = new GDALColorTable();
for( iColor = 0; iColor < psBandInfo->nSignificantLUTEntries; iColor++)
{
GDALColorEntry sEntry;
sEntry.c1 = psBandInfo->pabyLUT[ 0 + iColor];
sEntry.c2 = psBandInfo->pabyLUT[256 + iColor];
sEntry.c3 = psBandInfo->pabyLUT[512 + iColor];
sEntry.c4 = 255;
poColorTable->SetColorEntry( iColor, &sEntry );
}
if (psImage->bNoDataSet)
{
GDALColorEntry sEntry;
sEntry.c1 = sEntry.c2 = sEntry.c3 = sEntry.c4 = 0;
poColorTable->SetColorEntry( psImage->nNoDataValue, &sEntry );
}
}
/* -------------------------------------------------------------------- */
/* We create a color table for 1 bit data too... */
/* -------------------------------------------------------------------- */
if( poColorTable == NULL && psImage->nBitsPerSample == 1 )
{
GDALColorEntry sEntry;
poColorTable = new GDALColorTable();
sEntry.c1 = 0;
sEntry.c2 = 0;
sEntry.c3 = 0;
sEntry.c4 = 255;
poColorTable->SetColorEntry( 0, &sEntry );
sEntry.c1 = 255;
sEntry.c2 = 255;
sEntry.c3 = 255;
sEntry.c4 = 255;
poColorTable->SetColorEntry( 1, &sEntry );
}
return poColorTable;
}
/************************************************************************/
/* ==================================================================== */
/* NITFProxyPamRasterBand */
/* ==================================================================== */
/************************************************************************/
NITFProxyPamRasterBand::~NITFProxyPamRasterBand()
{
std::map<CPLString, char**>::iterator oIter = oMDMap.begin();
while(oIter != oMDMap.end())
{
CSLDestroy(oIter->second);
oIter ++;
}
}
#define RB_PROXY_METHOD_WITH_RET(retType, retErrValue, methodName, argList, argParams) \
retType NITFProxyPamRasterBand::methodName argList \
{ \
retType ret; \
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
if (_poSrcBand) \
{ \
ret = _poSrcBand->methodName argParams; \
UnrefUnderlyingRasterBand(_poSrcBand); \
} \
else \
{ \
ret = retErrValue; \
} \
return ret; \
}
#define RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(retType, retErrValue, methodName, underlyingMethodName, argList, argParams) \
retType NITFProxyPamRasterBand::methodName argList \
{ \
retType ret; \
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
if (_poSrcBand) \
{ \
ret = _poSrcBand->underlyingMethodName argParams; \
UnrefUnderlyingRasterBand(_poSrcBand); \
} \
else \
{ \
ret = retErrValue; \
} \
return ret; \
}
char **NITFProxyPamRasterBand::GetMetadata( const char * pszDomain )
{
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
if (_poSrcBand)
{
/* Let's merge metadata of PAM and the underlying band */
/* PAM metadata should override underlying band metadata */
char** papszMD = CSLDuplicate(_poSrcBand->GetMetadata( pszDomain ));
papszMD = CSLMerge( papszMD, GDALPamRasterBand::GetMetadata(pszDomain) );
if (pszDomain == NULL)
pszDomain = "";
std::map<CPLString, char**>::iterator oIter = oMDMap.find(pszDomain);
if (oIter != oMDMap.end())
CSLDestroy(oIter->second);
oMDMap[pszDomain] = papszMD;
UnrefUnderlyingRasterBand(_poSrcBand);
return papszMD;
}
return GDALPamRasterBand::GetMetadata(pszDomain);
}
const char *NITFProxyPamRasterBand::GetMetadataItem( const char * pszName,
const char * pszDomain )
{
const char* pszRet = GDALPamRasterBand::GetMetadataItem(pszName, pszDomain);
if (pszRet)
return pszRet;
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
if (_poSrcBand)
{
pszRet = _poSrcBand->GetMetadataItem( pszName, pszDomain );
UnrefUnderlyingRasterBand(_poSrcBand);
}
return pszRet;
}
CPLErr NITFProxyPamRasterBand::GetStatistics( int bApproxOK, int bForce,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev )
{
CPLErr ret;
/* -------------------------------------------------------------------- */
/* 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) )
{
return GDALPamRasterBand::GetStatistics( bApproxOK, bForce,
pdfMin, pdfMax,
pdfMean, pdfStdDev);
}
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
if (_poSrcBand)
{
ret = _poSrcBand->GetStatistics( bApproxOK, bForce,
pdfMin, pdfMax, pdfMean, pdfStdDev);
if (ret == CE_None)
{
/* Report underlying statistics at PAM level */
SetMetadataItem("STATISTICS_MINIMUM",
_poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
SetMetadataItem("STATISTICS_MAXIMUM",
_poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
SetMetadataItem("STATISTICS_MEAN",
_poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
SetMetadataItem("STATISTICS_STDDEV",
_poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
}
UnrefUnderlyingRasterBand(_poSrcBand);
}
else
{
ret = CE_Failure;
}
return ret;
}
CPLErr NITFProxyPamRasterBand::ComputeStatistics( int bApproxOK,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev,
GDALProgressFunc pfn, void *pProgressData )
{
CPLErr ret;
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand();
if (_poSrcBand)
{
ret = _poSrcBand->ComputeStatistics( bApproxOK, pdfMin, pdfMax,
pdfMean, pdfStdDev,
pfn, pProgressData);
if (ret == CE_None)
{
/* Report underlying statistics at PAM level */
SetMetadataItem("STATISTICS_MINIMUM",
_poSrcBand->GetMetadataItem("STATISTICS_MINIMUM"));
SetMetadataItem("STATISTICS_MAXIMUM",
_poSrcBand->GetMetadataItem("STATISTICS_MAXIMUM"));
SetMetadataItem("STATISTICS_MEAN",
_poSrcBand->GetMetadataItem("STATISTICS_MEAN"));
SetMetadataItem("STATISTICS_STDDEV",
_poSrcBand->GetMetadataItem("STATISTICS_STDDEV"));
}
UnrefUnderlyingRasterBand(_poSrcBand);
}
else
{
ret = CE_Failure;
}
return ret;
}
#define RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(methodName) \
double NITFProxyPamRasterBand::methodName( int *pbSuccess ) \
{ \
int bSuccess = FALSE; \
double dfRet = GDALPamRasterBand::methodName(&bSuccess); \
if (bSuccess) \
{ \
if (pbSuccess) \
*pbSuccess = TRUE; \
return dfRet; \
} \
GDALRasterBand* _poSrcBand = RefUnderlyingRasterBand(); \
if (_poSrcBand) \
{ \
dfRet = _poSrcBand->methodName( pbSuccess ); \
UnrefUnderlyingRasterBand(_poSrcBand); \
} \
else \
{ \
dfRet = 0; \
} \
return dfRet; \
}
RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetNoDataValue)
RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMinimum)
RB_PROXY_METHOD_GET_DBL_WITH_SUCCESS(GetMaximum)
RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IReadBlock, ReadBlock,
( int nXBlockOff, int nYBlockOff, void* pImage),
(nXBlockOff, nYBlockOff, pImage) )
RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IWriteBlock, WriteBlock,
( int nXBlockOff, int nYBlockOff, void* pImage),
(nXBlockOff, nYBlockOff, pImage) )
RB_PROXY_METHOD_WITH_RET_AND_CALL_OTHER_METHOD(CPLErr, CE_Failure, IRasterIO, RasterIO,
( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
GSpacing nPixelSpace, GSpacing nLineSpace,
GDALRasterIOExtraArg* psExtraArg ),
(eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize, eBufType,
nPixelSpace, nLineSpace, psExtraArg ) )
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, FlushCache, (), ())
RB_PROXY_METHOD_WITH_RET(GDALColorInterp, GCI_Undefined, GetColorInterpretation, (), ())
RB_PROXY_METHOD_WITH_RET(GDALColorTable*, NULL, GetColorTable, (), ())
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, Fill,
(double dfRealValue, double dfImaginaryValue),
(dfRealValue, dfImaginaryValue))
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, ComputeRasterMinMax,
( int arg1, double* arg2 ), (arg1, arg2))
RB_PROXY_METHOD_WITH_RET(int, 0, HasArbitraryOverviews, (), ())
RB_PROXY_METHOD_WITH_RET(int, 0, GetOverviewCount, (), ())
RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL, GetOverview, (int arg1), (arg1))
RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL, GetRasterSampleOverview,
(GUIntBig arg1), (arg1))
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, BuildOverviews,
(const char * arg1, int arg2, int *arg3,
GDALProgressFunc arg4, void * arg5),
(arg1, arg2, arg3, arg4, arg5))
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, AdviseRead,
( int nXOff, int nYOff, int nXSize, int nYSize,
int nBufXSize, int nBufYSize,
GDALDataType eDT, char **papszOptions ),
(nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, eDT, papszOptions))
RB_PROXY_METHOD_WITH_RET(GDALRasterBand*, NULL, GetMaskBand, (), ())
RB_PROXY_METHOD_WITH_RET(int, 0, GetMaskFlags, (), ())
RB_PROXY_METHOD_WITH_RET(CPLErr, CE_Failure, CreateMaskBand, ( int nFlags ), (nFlags))
/************************************************************************/
/* UnrefUnderlyingRasterBand() */
/************************************************************************/
void NITFProxyPamRasterBand::UnrefUnderlyingRasterBand(CPL_UNUSED GDALRasterBand* poUnderlyingRasterBand)
{
}
/************************************************************************/
/* ==================================================================== */
/* NITFRasterBand */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* NITFRasterBand() */
/************************************************************************/
NITFRasterBand::NITFRasterBand( NITFDataset *poDS, int nBand )
{
NITFBandInfo *psBandInfo = poDS->psImage->pasBandInfo + nBand - 1;
this->poDS = poDS;
this->nBand = nBand;
this->eAccess = poDS->eAccess;
this->psImage = poDS->psImage;
/* -------------------------------------------------------------------- */
/* Translate data type(s). */
/* -------------------------------------------------------------------- */
if( psImage->nBitsPerSample <= 8 )
eDataType = GDT_Byte;
else if( psImage->nBitsPerSample == 16
&& EQUAL(psImage->szPVType,"SI") )
eDataType = GDT_Int16;
else if( psImage->nBitsPerSample == 16 )
eDataType = GDT_UInt16;
else if( psImage->nBitsPerSample == 12 )
eDataType = GDT_UInt16;
else if( psImage->nBitsPerSample == 32
&& EQUAL(psImage->szPVType,"SI") )
eDataType = GDT_Int32;
else if( psImage->nBitsPerSample == 32
&& EQUAL(psImage->szPVType,"R") )
eDataType = GDT_Float32;
else if( psImage->nBitsPerSample == 32 )
eDataType = GDT_UInt32;
else if( psImage->nBitsPerSample == 64
&& EQUAL(psImage->szPVType,"R") )
eDataType = GDT_Float64;
else if( psImage->nBitsPerSample == 64
&& EQUAL(psImage->szPVType,"C") )
eDataType = GDT_CFloat32;
/* ERO : note I'm not sure if CFloat64 can be transmitted as NBPP is only 2 characters */
else
{
int bOpenUnderlyingDS = CSLTestBoolean(
CPLGetConfigOption("NITF_OPEN_UNDERLYING_DS", "YES"));
if (!bOpenUnderlyingDS && psImage->nBitsPerSample > 8 && psImage->nBitsPerSample < 16)
{
if (EQUAL(psImage->szPVType,"SI"))
eDataType = GDT_Int16;
else
eDataType = GDT_UInt16;
}
else
{
eDataType = GDT_Unknown;
CPLError( CE_Warning, CPLE_AppDefined,
"Unsupported combination of PVTYPE(%s) and NBPP(%d).",
psImage->szPVType, psImage->nBitsPerSample );
}
}
/* -------------------------------------------------------------------- */
/* Work out block size. If the image is all one big block we */
/* handle via the scanline access API. */
/* -------------------------------------------------------------------- */
if( psImage->nBlocksPerRow == 1
&& psImage->nBlocksPerColumn == 1
&& psImage->nBitsPerSample >= 8
&& EQUAL(psImage->szIC,"NC") )
{
bScanlineAccess = TRUE;
nBlockXSize = psImage->nBlockWidth;
nBlockYSize = 1;
}
else
{
bScanlineAccess = FALSE;
nBlockXSize = psImage->nBlockWidth;
nBlockYSize = psImage->nBlockHeight;
}
/* -------------------------------------------------------------------- */
/* Do we have a color table? */
/* -------------------------------------------------------------------- */
poColorTable = NITFMakeColorTable(psImage,
psBandInfo);
if( psImage->nBitsPerSample == 1
|| psImage->nBitsPerSample == 3
|| psImage->nBitsPerSample == 5
|| psImage->nBitsPerSample == 6
|| psImage->nBitsPerSample == 7
|| psImage->nBitsPerSample == 12 )
SetMetadataItem( "NBITS", CPLString().Printf("%d", psImage->nBitsPerSample), "IMAGE_STRUCTURE" );
pUnpackData = 0;
if (psImage->nBitsPerSample == 3
|| psImage->nBitsPerSample == 5
|| psImage->nBitsPerSample == 6
|| psImage->nBitsPerSample == 7)
pUnpackData = new GByte[((nBlockXSize*nBlockYSize+7)/8)*8];
}
/************************************************************************/
/* ~NITFRasterBand() */
/************************************************************************/
NITFRasterBand::~NITFRasterBand()
{
if( poColorTable != NULL )
delete poColorTable;
delete[] pUnpackData;
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr NITFRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
int nBlockResult;
NITFDataset *poGDS = (NITFDataset *) poDS;
/* -------------------------------------------------------------------- */
/* Special case for JPEG blocks. */
/* -------------------------------------------------------------------- */
if( EQUAL(psImage->szIC,"C3") || EQUAL(psImage->szIC,"M3") )
{
CPLErr eErr = poGDS->ReadJPEGBlock( nBlockXOff, nBlockYOff );
int nBlockBandSize = psImage->nBlockWidth*psImage->nBlockHeight*
(GDALGetDataTypeSize(eDataType)/8);
if( eErr != CE_None )
return eErr;
memcpy( pImage,
poGDS->pabyJPEGBlock + (nBand - 1) * nBlockBandSize,
nBlockBandSize );
return eErr;
}
/* -------------------------------------------------------------------- */
/* Read the line/block */
/* -------------------------------------------------------------------- */
if( bScanlineAccess )
{
nBlockResult =
NITFReadImageLine(psImage, nBlockYOff, nBand, pImage);
}
else
{
nBlockResult =
NITFReadImageBlock(psImage, nBlockXOff, nBlockYOff, nBand, pImage);
}
if( nBlockResult == BLKREAD_OK )
{
if( psImage->nBitsPerSample % 8 )
Unpack((GByte*)pImage);
return CE_None;
}
if( nBlockResult == BLKREAD_FAIL )
return CE_Failure;
/* -------------------------------------------------------------------- */
/* If we got a null/missing block, try to fill it in with the */
/* nodata value. It seems this only really works properly for */
/* 8bit. */
/* -------------------------------------------------------------------- */
if( psImage->bNoDataSet )
memset( pImage, psImage->nNoDataValue,
psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
else
memset( pImage, 0,
psImage->nWordSize*psImage->nBlockWidth*psImage->nBlockHeight);
return CE_None;
}
/************************************************************************/
/* IWriteBlock() */
/************************************************************************/
CPLErr NITFRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
int nBlockResult;
/* -------------------------------------------------------------------- */
/* Write the line/block */
/* -------------------------------------------------------------------- */
if( bScanlineAccess )
{
nBlockResult =
NITFWriteImageLine(psImage, nBlockYOff, nBand, pImage);
}
else
{
nBlockResult =
NITFWriteImageBlock(psImage, nBlockXOff, nBlockYOff, nBand,pImage);
}
if( nBlockResult == BLKREAD_OK )
return CE_None;
else
return CE_Failure;
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
double NITFRasterBand::GetNoDataValue( int *pbSuccess )
{
if( pbSuccess != NULL )
*pbSuccess = psImage->bNoDataSet;
if( psImage->bNoDataSet )
return psImage->nNoDataValue;
else
return GDALPamRasterBand::GetNoDataValue( pbSuccess );
}
/************************************************************************/
/* GetColorInterpretation() */
/************************************************************************/
GDALColorInterp NITFRasterBand::GetColorInterpretation()
{
NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
if( poColorTable != NULL )
return GCI_PaletteIndex;
if( EQUAL(psBandInfo->szIREPBAND,"R") )
return GCI_RedBand;
if( EQUAL(psBandInfo->szIREPBAND,"G") )
return GCI_GreenBand;
if( EQUAL(psBandInfo->szIREPBAND,"B") )
return GCI_BlueBand;
if( EQUAL(psBandInfo->szIREPBAND,"M") )
return GCI_GrayIndex;
if( EQUAL(psBandInfo->szIREPBAND,"Y") )
return GCI_YCbCr_YBand;
if( EQUAL(psBandInfo->szIREPBAND,"Cb") )
return GCI_YCbCr_CbBand;
if( EQUAL(psBandInfo->szIREPBAND,"Cr") )
return GCI_YCbCr_CrBand;
return GCI_Undefined;
}
/************************************************************************/
/* NITFSetColorInterpretation() */
/************************************************************************/
CPLErr NITFSetColorInterpretation( NITFImage *psImage,
int nBand,
GDALColorInterp eInterp )
{
NITFBandInfo *psBandInfo = psImage->pasBandInfo + nBand - 1;
const char *pszREP = NULL;
GUIntBig nOffset;
if( eInterp == GCI_RedBand )
pszREP = "R";
else if( eInterp == GCI_GreenBand )
pszREP = "G";
else if( eInterp == GCI_BlueBand )
pszREP = "B";
else if( eInterp == GCI_GrayIndex )
pszREP = "M";
else if( eInterp == GCI_YCbCr_YBand )
pszREP = "Y";
else if( eInterp == GCI_YCbCr_CbBand )
pszREP = "Cb";
else if( eInterp == GCI_YCbCr_CrBand )
pszREP = "Cr";
else if( eInterp == GCI_Undefined )
return CE_None;
if( pszREP == NULL )
{
CPLError( CE_Failure, CPLE_NotSupported,
"Requested color interpretation (%s) not supported in NITF.",
GDALGetColorInterpretationName( eInterp ) );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Where does this go in the file? */
/* -------------------------------------------------------------------- */
strcpy( psBandInfo->szIREPBAND, pszREP );
nOffset = NITFIHFieldOffset( psImage, "IREPBAND" );
if( nOffset != 0 )
nOffset += (nBand - 1) * 13;
/* -------------------------------------------------------------------- */
/* write it (space padded). */
/* -------------------------------------------------------------------- */
char szPadded[4];
strcpy( szPadded, pszREP );
strcat( szPadded, " " );
if( nOffset != 0 )
{
if( VSIFSeekL( psImage->psFile->fp, nOffset, SEEK_SET ) != 0
|| VSIFWriteL( (void *) szPadded, 1, 2, psImage->psFile->fp ) != 2 )
{
CPLError( CE_Failure, CPLE_AppDefined,
"IO failure writing new IREPBAND value to NITF file." );
return CE_Failure;
}
}
return CE_None;
}
/************************************************************************/
/* SetColorInterpretation() */
/************************************************************************/
CPLErr NITFRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
{
return NITFSetColorInterpretation( psImage, nBand, eInterp );
}
/************************************************************************/
/* GetColorTable() */
/************************************************************************/
GDALColorTable *NITFRasterBand::GetColorTable()
{
return poColorTable;
}
/************************************************************************/
/* SetColorTable() */
/************************************************************************/
CPLErr NITFRasterBand::SetColorTable( GDALColorTable *poNewCT )
{
NITFDataset *poGDS = (NITFDataset *) poDS;
if( poGDS->bInLoadXML )
return GDALPamRasterBand::SetColorTable(poNewCT);
if( poNewCT == NULL )
return CE_Failure;
GByte abyNITFLUT[768];
int i;
int nCount = MIN(256,poNewCT->GetColorEntryCount());
memset( abyNITFLUT, 0, 768 );
for( i = 0; i < nCount; i++ )
{
GDALColorEntry sEntry;
poNewCT->GetColorEntryAsRGB( i, &sEntry );
abyNITFLUT[i ] = (GByte) sEntry.c1;
abyNITFLUT[i+256] = (GByte) sEntry.c2;
abyNITFLUT[i+512] = (GByte) sEntry.c3;
}
if( NITFWriteLUT( psImage, nBand, nCount, abyNITFLUT ) )
return CE_None;
else
return CE_Failure;
}
/************************************************************************/
/* Unpack() */
/************************************************************************/
void NITFRasterBand::Unpack( GByte* pData )
{
long n = nBlockXSize*nBlockYSize;
long i;
long k;
GByte abyTempData[7] = {0, 0, 0, 0, 0, 0, 0};
const GByte* pDataSrc = pData;
if (n < psImage->nBitsPerSample &&
psImage->nBitsPerSample < 8)
{
memcpy(abyTempData, pData, n);
pDataSrc = abyTempData;
}
switch (psImage->nBitsPerSample)
{
case 1:
{
// unpack 1-bit in-place in reverse
for (i = n; --i >= 0; )
pData[i] = (pData[i>>3] & (0x80 >> (i&7))) != 0;
break;
}
case 2:
{
static const int s_Shift2[] = {6, 4, 2, 0};
// unpack 2-bit in-place in reverse
for (i = n; --i >= 0; )
pData[i] = (pData[i>>2] >> (GByte)s_Shift2[i&3]) & 0x03;
break;
}
case 4:
{
static const int s_Shift4[] = {4, 0};
// unpack 4-bit in-place in reverse
for (i = n; --i >= 0; )
pData[i] = (pData[i>>1] >> (GByte)s_Shift4[i&1]) & 0x0f;
break;
}
case 3:
{
// unpacks 8 pixels (3 bytes) at time
for (i = 0, k = 0; i < n; i += 8, k += 3)
{
pUnpackData[i+0] = ((pDataSrc[k+0] >> 5));
pUnpackData[i+1] = ((pDataSrc[k+0] >> 2) & 0x07);
pUnpackData[i+2] = ((pDataSrc[k+0] << 1) & 0x07) | (pDataSrc[k+1] >> 7);
pUnpackData[i+3] = ((pDataSrc[k+1] >> 4) & 0x07);
pUnpackData[i+4] = ((pDataSrc[k+1] >> 1) & 0x07);
pUnpackData[i+5] = ((pDataSrc[k+1] << 2) & 0x07) | (pDataSrc[k+2] >> 6);
pUnpackData[i+6] = ((pDataSrc[k+2] >> 3) & 0x07);
pUnpackData[i+7] = ((pDataSrc[k+2]) & 0x7);
}
memcpy(pData, pUnpackData, n);
break;
}
case 5:
{
// unpacks 8 pixels (5 bytes) at time
for (i = 0, k = 0; i < n; i += 8, k += 5)
{
pUnpackData[i+0] = ((pDataSrc[k+0] >> 3));
pUnpackData[i+1] = ((pDataSrc[k+0] << 2) & 0x1f) | (pDataSrc[k+1] >> 6);
pUnpackData[i+2] = ((pDataSrc[k+1] >> 1) & 0x1f);
pUnpackData[i+3] = ((pDataSrc[k+1] << 4) & 0x1f) | (pDataSrc[k+2] >> 4);
pUnpackData[i+4] = ((pDataSrc[k+2] << 1) & 0x1f) | (pDataSrc[k+3] >> 7);
pUnpackData[i+5] = ((pDataSrc[k+3] >> 2) & 0x1f);
pUnpackData[i+6] = ((pDataSrc[k+3] << 3) & 0x1f) | (pDataSrc[k+4] >> 5);
pUnpackData[i+7] = ((pDataSrc[k+4]) & 0x1f);
}
memcpy(pData, pUnpackData, n);
break;
}
case 6:
{
// unpacks 4 pixels (3 bytes) at time
for (i = 0, k = 0; i < n; i += 4, k += 3)
{
pUnpackData[i+0] = ((pDataSrc[k+0] >> 2));
pUnpackData[i+1] = ((pDataSrc[k+0] << 4) & 0x3f) | (pDataSrc[k+1] >> 4);
pUnpackData[i+2] = ((pDataSrc[k+1] << 2) & 0x3f) | (pDataSrc[k+2] >> 6);
pUnpackData[i+3] = ((pDataSrc[k+2]) & 0x3f);
}
memcpy(pData, pUnpackData, n);
break;
}
case 7:
{
// unpacks 8 pixels (7 bytes) at time
for (i = 0, k = 0; i < n; i += 8, k += 7)
{
pUnpackData[i+0] = ((pDataSrc[k+0] >> 1));
pUnpackData[i+1] = ((pDataSrc[k+0] << 6) & 0x7f) | (pDataSrc[k+1] >> 2);
pUnpackData[i+2] = ((pDataSrc[k+1] << 5) & 0x7f) | (pDataSrc[k+2] >> 3) ;
pUnpackData[i+3] = ((pDataSrc[k+2] << 4) & 0x7f) | (pDataSrc[k+3] >> 4);
pUnpackData[i+4] = ((pDataSrc[k+3] << 3) & 0x7f) | (pDataSrc[k+4] >> 5);
pUnpackData[i+5] = ((pDataSrc[k+4] << 2) & 0x7f) | (pDataSrc[k+5] >> 6);
pUnpackData[i+6] = ((pDataSrc[k+5] << 1) & 0x7f) | (pDataSrc[k+6] >> 7);
pUnpackData[i+7] = ((pDataSrc[k+6]) & 0x7f);
}
memcpy(pData, pUnpackData, n);
break;
}
case 12:
{
GByte* pabyImage = (GByte *)pData;
GUInt16* panImage = (GUInt16*)pData;
for (i = n; --i >= 0; )
{
long iOffset = i*3 / 2;
if (i % 2 == 0)
panImage[i] = pabyImage[iOffset] + (pabyImage[iOffset+1] & 0xf0) * 16;
else
panImage[i] = (pabyImage[iOffset] & 0x0f) * 16
+ (pabyImage[iOffset+1] & 0xf0) / 16
+ (pabyImage[iOffset+1] & 0x0f) * 256;
}
break;
}
}
}
/************************************************************************/
/* ==================================================================== */
/* NITFWrapperRasterBand */
/* ==================================================================== */
/************************************************************************/
/************************************************************************/
/* NITFWrapperRasterBand() */
/************************************************************************/
NITFWrapperRasterBand::NITFWrapperRasterBand( NITFDataset * poDS,
GDALRasterBand* poBaseBand,
int nBand)
{
this->poDS = poDS;
this->nBand = nBand;
this->poBaseBand = poBaseBand;
eDataType = poBaseBand->GetRasterDataType();
poBaseBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
poColorTable = NULL;
eInterp = poBaseBand->GetColorInterpretation();
bIsJPEG = poBaseBand->GetDataset() != NULL &&
poBaseBand->GetDataset()->GetDriver() != NULL &&
EQUAL(poBaseBand->GetDataset()->GetDriver()->GetDescription(), "JPEG");
}
/************************************************************************/
/* ~NITFWrapperRasterBand() */
/************************************************************************/
NITFWrapperRasterBand::~NITFWrapperRasterBand()
{
if( poColorTable != NULL )
delete poColorTable;
}
/************************************************************************/
/* RefUnderlyingRasterBand() */
/************************************************************************/
/* We don't need ref-counting. Just return the base band */
GDALRasterBand* NITFWrapperRasterBand::RefUnderlyingRasterBand()
{
return poBaseBand;
}
/************************************************************************/
/* GetColorTable() */
/************************************************************************/
GDALColorTable *NITFWrapperRasterBand::GetColorTable()
{
return poColorTable;
}
/************************************************************************/
/* SetColorTableFromNITFBandInfo() */
/************************************************************************/
void NITFWrapperRasterBand::SetColorTableFromNITFBandInfo()
{
NITFDataset* poGDS = (NITFDataset* )poDS;
poColorTable = NITFMakeColorTable(poGDS->psImage,
poGDS->psImage->pasBandInfo + nBand - 1);
}
/************************************************************************/
/* GetColorInterpretation() */
/************************************************************************/
GDALColorInterp NITFWrapperRasterBand::GetColorInterpretation()
{
return eInterp;
}
/************************************************************************/
/* SetColorInterpretation() */
/************************************************************************/
CPLErr NITFWrapperRasterBand::SetColorInterpretation( GDALColorInterp eInterp)
{
this->eInterp = eInterp;
if( poBaseBand->GetDataset() != NULL &&
poBaseBand->GetDataset()->GetDriver() != NULL &&
EQUAL(poBaseBand->GetDataset()->GetDriver()->GetDescription(), "JP2ECW") )
poBaseBand->SetColorInterpretation( eInterp );
return CE_None;
}
/************************************************************************/
/* GetOverviewCount() */
/************************************************************************/
int NITFWrapperRasterBand::GetOverviewCount()
{
if( bIsJPEG )
{
if( ((NITFDataset*)poDS)->ExposeUnderlyingJPEGDatasetOverviews() )
return NITFProxyPamRasterBand::GetOverviewCount();
else
return GDALPamRasterBand::GetOverviewCount();
}
else
return NITFProxyPamRasterBand::GetOverviewCount();
}
/************************************************************************/
/* GetOverview() */
/************************************************************************/
GDALRasterBand * NITFWrapperRasterBand::GetOverview(int iOverview)
{
if( bIsJPEG )
{
if( ((NITFDataset*)poDS)->ExposeUnderlyingJPEGDatasetOverviews() )
return NITFProxyPamRasterBand::GetOverview(iOverview);
else
return GDALPamRasterBand::GetOverview(iOverview);
}
else
return NITFProxyPamRasterBand::GetOverview(iOverview);
}