ultimatepp/bazaar/plugin/gdal/frmts/mrsid/mrsiddataset.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

3658 lines
135 KiB
C++

/******************************************************************************
* $Id: mrsiddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $
*
* Project: Multi-resolution Seamless Image Database (MrSID)
* Purpose: Read/write LizardTech's MrSID file format - Version 4+ SDK.
* Author: Andrey Kiselev, dron@ak4719.spb.edu
*
******************************************************************************
* Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
* Copyright (c) 2007-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.
****************************************************************************/
#define NO_DELETE
#include "gdaljp2abstractdataset.h"
#include "ogr_spatialref.h"
#include "cpl_string.h"
#include "gdaljp2metadata.h"
#include <string>
#include <geo_normalize.h>
#include <geovalues.h>
CPL_CVSID("$Id: mrsiddataset.cpp 28785 2015-03-26 20:46:45Z goatbar $");
CPL_C_START
double GTIFAngleToDD( double dfAngle, int nUOMAngle );
void CPL_DLL LibgeotiffOneTimeInit();
CPL_C_END
// Key Macros from Makefile:
// MRSID_ESDK: Means we have the encoding SDK (version 5 or newer required)
// MRSID_J2K: Means we are enabling MrSID SDK JPEG2000 support.
#include "lt_types.h"
#include "lt_base.h"
#include "lt_fileSpec.h"
#include "lt_ioFileStream.h"
#include "lt_utilStatusStrings.h"
#include "lti_geoCoord.h"
#include "lti_pixel.h"
#include "lti_navigator.h"
#include "lti_sceneBuffer.h"
#include "lti_metadataDatabase.h"
#include "lti_metadataRecord.h"
#include "lti_utils.h"
#include "lti_delegates.h"
#include "lt_utilStatus.h"
#include "MrSIDImageReader.h"
#ifdef MRSID_J2K
# include "J2KImageReader.h"
#endif
// It seems that LT_STS_UTIL_TimeUnknown was added in version 6, also
// the first version with lti_version.h
#ifdef LT_STS_UTIL_TimeUnknown
# include "lti_version.h"
#endif
// Are we using version 6 or newer?
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
# define MRSID_POST5
#endif
#ifdef MRSID_ESDK
# include "MG3ImageWriter.h"
# include "MG3WriterParams.h"
# include "MG2ImageWriter.h"
# include "MG2WriterParams.h"
# ifdef MRSID_HAVE_MG4WRITE
# include "MG4ImageWriter.h"
# include "MG4WriterParams.h"
# endif
# ifdef MRSID_J2K
# ifdef MRSID_POST5
# include "JP2WriterManager.h"
# include "JPCWriterParams.h"
# else
# include "J2KImageWriter.h"
# include "J2KWriterParams.h"
# endif
# endif
#endif /* MRSID_ESDK */
#ifdef MRSID_POST5
# define MRSID_HAVE_GETWKT
#endif
#include "mrsidstream.h"
LT_USE_NAMESPACE(LizardTech)
/* -------------------------------------------------------------------- */
/* Various wrapper templates used to force new/delete to happen */
/* in the same heap. See bug 1213 and MSDN knowledgebase */
/* article 122675. */
/* -------------------------------------------------------------------- */
template <class T>
class LTIDLLPixel : public T
{
public:
LTIDLLPixel(LTIColorSpace colorSpace,
lt_uint16 numBands,
LTIDataType dataType) : T(colorSpace,numBands,dataType) {}
virtual ~LTIDLLPixel() {};
};
template <class T>
class LTIDLLReader : public T
{
public:
LTIDLLReader(const LTFileSpec& fileSpec,
bool useWorldFile = false) : T(fileSpec, useWorldFile) {}
LTIDLLReader(LTIOStreamInf &oStream,
bool useWorldFile = false) : T(oStream, useWorldFile) {}
LTIDLLReader(LTIOStreamInf *poStream,
LTIOStreamInf *poWorldFile = NULL) : T(poStream, poWorldFile) {}
virtual ~LTIDLLReader() {};
};
template <class T>
class LTIDLLNavigator : public T
{
public:
LTIDLLNavigator(const LTIImage& image ) : T(image) {}
virtual ~LTIDLLNavigator() {};
};
template <class T>
class LTIDLLBuffer : public T
{
public:
LTIDLLBuffer(const LTIPixel& pixelProps,
lt_uint32 totalNumCols,
lt_uint32 totalNumRows,
void** data ) : T(pixelProps,totalNumCols,totalNumRows,data) {}
virtual ~LTIDLLBuffer() {};
};
template <class T>
class LTIDLLCopy : public T
{
public:
LTIDLLCopy(const T& original) : T(original) {}
virtual ~LTIDLLCopy() {};
};
template <class T>
class LTIDLLWriter : public T
{
public:
LTIDLLWriter(LTIImageStage *image) : T(image) {}
virtual ~LTIDLLWriter() {}
};
template <class T>
class LTIDLLDefault : public T
{
public:
LTIDLLDefault() : T() {}
virtual ~LTIDLLDefault() {}
};
/* -------------------------------------------------------------------- */
/* Interface to MrSID SDK progress reporting. */
/* -------------------------------------------------------------------- */
class MrSIDProgress : public LTIProgressDelegate
{
public:
MrSIDProgress(GDALProgressFunc f, void *arg) : m_f(f), m_arg(arg) {}
virtual ~MrSIDProgress() {}
virtual LT_STATUS setProgressStatus(float fraction)
{
if (!m_f)
return LT_STS_BadContext;
if( !m_f( fraction, NULL, m_arg ) )
return LT_STS_Failure;
return LT_STS_Success;
}
private:
GDALProgressFunc m_f;
void *m_arg;
};
/************************************************************************/
/* ==================================================================== */
/* MrSIDDataset */
/* ==================================================================== */
/************************************************************************/
class MrSIDDataset : public GDALJP2AbstractDataset
{
friend class MrSIDRasterBand;
LTIOStreamInf *poStream;
LTIOFileStream oLTIStream;
LTIVSIStream oVSIStream;
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
LTIImageFilter *poImageReader;
#else
LTIImageReader *poImageReader;
#endif
#ifdef MRSID_ESDK
LTIGeoFileImageWriter *poImageWriter;
#endif
LTIDLLNavigator<LTINavigator> *poLTINav;
LTIDLLCopy<LTIMetadataDatabase> *poMetadata;
const LTIPixel *poNDPixel;
LTIDLLBuffer<LTISceneBuffer> *poBuffer;
int nBlockXSize, nBlockYSize;
int bPrevBlockRead;
int nPrevBlockXOff, nPrevBlockYOff;
LTIDataType eSampleType;
GDALDataType eDataType;
LTIColorSpace eColorSpace;
double dfCurrentMag;
GTIFDefn *psDefn;
MrSIDDataset *poParentDS;
int bIsOverview;
int nOverviewCount;
MrSIDDataset **papoOverviewDS;
CPLString osMETFilename;
CPLErr OpenZoomLevel( lt_int32 iZoom );
char *SerializeMetadataRec( const LTIMetadataRecord* );
int GetMetadataElement( const char *, void *, int=0 );
void FetchProjParms();
void GetGTIFDefn();
char *GetOGISDefn( GTIFDefn * );
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int, void *,
int, int, GDALDataType, int, int *,
GSpacing nPixelSpace, GSpacing nLineSpace,
GSpacing nBandSpace,
GDALRasterIOExtraArg* psExtraArg);
protected:
virtual int CloseDependentDatasets();
virtual CPLErr IBuildOverviews( const char *, int, int *,
int, int *, GDALProgressFunc, void * );
public:
MrSIDDataset(int bIsJPEG2000);
~MrSIDDataset();
static GDALDataset *Open( GDALOpenInfo * poOpenInfo, int bIsJP2 );
virtual char **GetFileList();
#ifdef MRSID_ESDK
static GDALDataset *Create( const char * pszFilename,
int nXSize, int nYSize, int nBands,
GDALDataType eType, char ** papszParmList );
virtual void FlushCache( void );
#endif
};
/************************************************************************/
/* ==================================================================== */
/* MrSIDRasterBand */
/* ==================================================================== */
/************************************************************************/
class MrSIDRasterBand : public GDALPamRasterBand
{
friend class MrSIDDataset;
LTIPixel *poPixel;
int nBlockSize;
int bNoDataSet;
double dfNoDataValue;
MrSIDDataset *poGDS;
GDALColorInterp eBandInterp;
public:
MrSIDRasterBand( MrSIDDataset *, int );
~MrSIDRasterBand();
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
void *, int, int, GDALDataType,
GSpacing nPixelSpace, GSpacing nLineSpace,
GDALRasterIOExtraArg* psExtraArg);
virtual CPLErr IReadBlock( int, int, void * );
virtual GDALColorInterp GetColorInterpretation();
CPLErr SetColorInterpretation( GDALColorInterp eNewInterp );
virtual double GetNoDataValue( int * );
virtual int GetOverviewCount();
virtual GDALRasterBand *GetOverview( int );
virtual CPLErr GetStatistics( int bApproxOK, int bForce,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev );
#ifdef MRSID_ESDK
virtual CPLErr IWriteBlock( int, int, void * );
#endif
};
/************************************************************************/
/* MrSIDRasterBand() */
/************************************************************************/
MrSIDRasterBand::MrSIDRasterBand( MrSIDDataset *poDS, int nBand )
{
this->poDS = poDS;
poGDS = poDS;
this->nBand = nBand;
this->eDataType = poDS->eDataType;
/* -------------------------------------------------------------------- */
/* Set the block sizes and buffer parameters. */
/* -------------------------------------------------------------------- */
nBlockXSize = poDS->nBlockXSize;
nBlockYSize = poDS->nBlockYSize;
//#ifdef notdef
if( poDS->GetRasterXSize() > 2048 )
nBlockXSize = 1024;
if( poDS->GetRasterYSize() > 128 )
nBlockYSize = 128;
else
nBlockYSize = poDS->GetRasterYSize();
//#endif
nBlockSize = nBlockXSize * nBlockYSize;
poPixel = new LTIDLLPixel<LTIPixel>( poDS->eColorSpace, poDS->nBands,
poDS->eSampleType );
/* -------------------------------------------------------------------- */
/* Set NoData values. */
/* */
/* This logic is disabled for now since the MrSID nodata */
/* semantics are different than GDAL. In MrSID all bands must */
/* match the nodata value for that band in order for the pixel */
/* to be considered nodata, otherwise all values are valid. */
/* -------------------------------------------------------------------- */
#ifdef notdef
if ( poDS->poNDPixel )
{
switch( poDS->eSampleType )
{
case LTI_DATATYPE_UINT8:
case LTI_DATATYPE_SINT8:
dfNoDataValue = (double)
poDS->poNDPixel->getSampleValueUint8( nBand - 1 );
break;
case LTI_DATATYPE_UINT16:
dfNoDataValue = (double)
poDS->poNDPixel->getSampleValueUint16( nBand - 1 );
break;
case LTI_DATATYPE_FLOAT32:
dfNoDataValue =
poDS->poNDPixel->getSampleValueFloat32( nBand - 1 );
break;
case LTI_DATATYPE_SINT16:
dfNoDataValue = (double)
*(GInt16 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
break;
case LTI_DATATYPE_UINT32:
dfNoDataValue = (double)
*(GUInt32 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
break;
case LTI_DATATYPE_SINT32:
dfNoDataValue = (double)
*(GInt32 *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
break;
case LTI_DATATYPE_FLOAT64:
dfNoDataValue =
*(double *)poDS->poNDPixel->getSampleValueAddr( nBand - 1 );
break;
case LTI_DATATYPE_INVALID:
CPLAssert( FALSE );
break;
}
bNoDataSet = TRUE;
}
else
#endif
{
dfNoDataValue = 0.0;
bNoDataSet = FALSE;
}
switch( poGDS->eColorSpace )
{
case LTI_COLORSPACE_RGB:
if( nBand == 1 )
eBandInterp = GCI_RedBand;
else if( nBand == 2 )
eBandInterp = GCI_GreenBand;
else if( nBand == 3 )
eBandInterp = GCI_BlueBand;
else
eBandInterp = GCI_Undefined;
break;
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
case LTI_COLORSPACE_RGBA:
if( nBand == 1 )
eBandInterp = GCI_RedBand;
else if( nBand == 2 )
eBandInterp = GCI_GreenBand;
else if( nBand == 3 )
eBandInterp = GCI_BlueBand;
else if( nBand == 4 )
eBandInterp = GCI_AlphaBand;
else
eBandInterp = GCI_Undefined;
break;
#endif
case LTI_COLORSPACE_CMYK:
if( nBand == 1 )
eBandInterp = GCI_CyanBand;
else if( nBand == 2 )
eBandInterp = GCI_MagentaBand;
else if( nBand == 3 )
eBandInterp = GCI_YellowBand;
else if( nBand == 4 )
eBandInterp = GCI_BlackBand;
else
eBandInterp = GCI_Undefined;
break;
case LTI_COLORSPACE_GRAYSCALE:
eBandInterp = GCI_GrayIndex;
break;
default:
eBandInterp = GCI_Undefined;
break;
}
}
/************************************************************************/
/* ~MrSIDRasterBand() */
/************************************************************************/
MrSIDRasterBand::~MrSIDRasterBand()
{
if ( poPixel )
delete poPixel;
}
/************************************************************************/
/* IReadBlock() */
/************************************************************************/
CPLErr MrSIDRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
#ifdef MRSID_ESDK
if( poGDS->eAccess == GA_Update )
{
CPLDebug( "MrSID",
"IReadBlock() - DSDK - read on updatable file fails." );
memset( pImage, 0, nBlockSize * GDALGetDataTypeSize(eDataType) / 8 );
return CE_None;
}
#endif /* MRSID_ESDK */
CPLDebug( "MrSID", "IReadBlock(%d,%d)", nBlockXOff, nBlockYOff );
if ( !poGDS->bPrevBlockRead
|| poGDS->nPrevBlockXOff != nBlockXOff
|| poGDS->nPrevBlockYOff != nBlockYOff )
{
GInt32 nLine = nBlockYOff * nBlockYSize;
GInt32 nCol = nBlockXOff * nBlockXSize;
// XXX: The scene, passed to LTIImageStage::read() call must be
// inside the image boundaries. So we should detect the last strip and
// form the scene properly.
CPLDebug( "MrSID",
"IReadBlock - read() %dx%d block at %d,%d.",
nBlockXSize, nBlockYSize, nCol, nLine );
if(!LT_SUCCESS( poGDS->poLTINav->setSceneAsULWH(
nCol, nLine,
(nCol+nBlockXSize>poGDS->GetRasterXSize())?
(poGDS->GetRasterXSize()-nCol):nBlockXSize,
(nLine+nBlockYSize>poGDS->GetRasterYSize())?
(poGDS->GetRasterYSize()-nLine):nBlockYSize,
poGDS->dfCurrentMag) ))
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IReadBlock(): Failed to set scene position." );
return CE_Failure;
}
if ( !poGDS->poBuffer )
{
poGDS->poBuffer =
new LTIDLLBuffer<LTISceneBuffer>( *poPixel, nBlockXSize, nBlockYSize, NULL );
// poGDS->poBuffer =
// new LTISceneBuffer( *poPixel, nBlockXSize, nBlockYSize, NULL );
}
if(!LT_SUCCESS(poGDS->poImageReader->read(poGDS->poLTINav->getScene(),
*poGDS->poBuffer)))
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IReadBlock(): Failed to load image." );
return CE_Failure;
}
poGDS->bPrevBlockRead = TRUE;
poGDS->nPrevBlockXOff = nBlockXOff;
poGDS->nPrevBlockYOff = nBlockYOff;
}
memcpy( pImage, poGDS->poBuffer->getTotalBandData(nBand - 1),
nBlockSize * (GDALGetDataTypeSize(poGDS->eDataType) / 8) );
return CE_None;
}
#ifdef MRSID_ESDK
/************************************************************************/
/* IWriteBlock() */
/************************************************************************/
CPLErr MrSIDRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
void * pImage )
{
CPLAssert( poGDS != NULL
&& nBlockXOff >= 0
&& nBlockYOff >= 0
&& pImage != NULL );
#ifdef DEBUG
CPLDebug( "MrSID", "IWriteBlock(): nBlockXOff=%d, nBlockYOff=%d",
nBlockXOff, nBlockYOff );
#endif
LTIScene oScene( nBlockXOff * nBlockXSize,
nBlockYOff * nBlockYSize,
nBlockXSize, nBlockYSize, 1.0);
LTISceneBuffer oSceneBuf( *poPixel, poGDS->nBlockXSize,
poGDS->nBlockYSize, &pImage );
if( !LT_SUCCESS(poGDS->poImageWriter->writeBegin(oScene)) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IWriteBlock(): writeBegin failed." );
return CE_Failure;
}
if( !LT_SUCCESS(poGDS->poImageWriter->writeStrip(oSceneBuf, oScene)) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IWriteBlock(): writeStrip failed." );
return CE_Failure;
}
if( !LT_SUCCESS(poGDS->poImageWriter->writeEnd()) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IWriteBlock(): writeEnd failed." );
return CE_Failure;
}
return CE_None;
}
#endif /* MRSID_ESDK */
/************************************************************************/
/* IRasterIO() */
/************************************************************************/
CPLErr MrSIDRasterBand::IRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
GSpacing nPixelSpace, GSpacing nLineSpace,
GDALRasterIOExtraArg* psExtraArg)
{
/* -------------------------------------------------------------------- */
/* Fallback to default implementation if the whole scanline */
/* without subsampling requested. */
/* -------------------------------------------------------------------- */
if ( nXSize == poGDS->GetRasterXSize()
&& nXSize == nBufXSize
&& nYSize == nBufYSize )
{
return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff,
nXSize, nYSize, pData,
nBufXSize, nBufYSize, eBufType,
nPixelSpace, nLineSpace, psExtraArg );
}
/* -------------------------------------------------------------------- */
/* Handle via the dataset level IRasterIO() */
/* -------------------------------------------------------------------- */
return poGDS->IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
nBufXSize, nBufYSize, eBufType,
1, &nBand, nPixelSpace, nLineSpace, 0, psExtraArg );
}
/************************************************************************/
/* GetColorInterpretation() */
/************************************************************************/
GDALColorInterp MrSIDRasterBand::GetColorInterpretation()
{
return eBandInterp;
}
/************************************************************************/
/* SetColorInterpretation() */
/* */
/* This would normally just be used by folks using the MrSID code */
/* to read JP2 streams in other formats (such as NITF) and */
/* providing their own color interpretation regardless of what */
/* MrSID might think the stream itself says. */
/************************************************************************/
CPLErr MrSIDRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
{
eBandInterp = eNewInterp;
return CE_None;
}
/************************************************************************/
/* GetStatistics() */
/* */
/* We override this method so that we can force generation of */
/* statistics if approx ok is true since we know that a small */
/* overview is always available, and that computing statistics */
/* from it is very fast. */
/************************************************************************/
CPLErr MrSIDRasterBand::GetStatistics( int bApproxOK, int bForce,
double *pdfMin, double *pdfMax,
double *pdfMean, double *pdfStdDev )
{
if( bApproxOK )
bForce = TRUE;
return GDALPamRasterBand::GetStatistics( bApproxOK, bForce,
pdfMin, pdfMax,
pdfMean, pdfStdDev );
}
/************************************************************************/
/* GetNoDataValue() */
/************************************************************************/
double MrSIDRasterBand::GetNoDataValue( int * pbSuccess )
{
if( bNoDataSet )
{
if( pbSuccess )
*pbSuccess = bNoDataSet;
return dfNoDataValue;
}
return GDALPamRasterBand::GetNoDataValue( pbSuccess );
}
/************************************************************************/
/* GetOverviewCount() */
/************************************************************************/
int MrSIDRasterBand::GetOverviewCount()
{
return poGDS->nOverviewCount;
}
/************************************************************************/
/* GetOverview() */
/************************************************************************/
GDALRasterBand *MrSIDRasterBand::GetOverview( int i )
{
if( i < 0 || i >= poGDS->nOverviewCount )
return NULL;
else
return poGDS->papoOverviewDS[i]->GetRasterBand( nBand );
}
/************************************************************************/
/* MrSIDDataset() */
/************************************************************************/
MrSIDDataset::MrSIDDataset(int bIsJPEG2000)
{
poStream = NULL;
poImageReader = NULL;
#ifdef MRSID_ESDK
poImageWriter = NULL;
#endif
poLTINav = NULL;
poMetadata = NULL;
poNDPixel = NULL;
eSampleType = LTI_DATATYPE_UINT8;
nBands = 0;
eDataType = GDT_Byte;
poBuffer = NULL;
bPrevBlockRead = FALSE;
nPrevBlockXOff = 0;
nPrevBlockYOff = 0;
psDefn = NULL;
dfCurrentMag = 1.0;
bIsOverview = FALSE;
poParentDS = this;
nOverviewCount = 0;
papoOverviewDS = NULL;
poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2MrSID" : "MrSID" );
}
/************************************************************************/
/* ~MrSIDDataset() */
/************************************************************************/
MrSIDDataset::~MrSIDDataset()
{
FlushCache();
#ifdef MRSID_ESDK
if ( poImageWriter )
delete poImageWriter;
#endif
if ( poBuffer )
delete poBuffer;
if ( poMetadata )
delete poMetadata;
if ( poLTINav )
delete poLTINav;
if ( poImageReader && !bIsOverview )
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
{
poImageReader->release();
poImageReader = NULL;
}
#else
delete poImageReader;
#endif
// points to another member, don't delete
poStream = NULL;
if ( psDefn )
delete psDefn;
CloseDependentDatasets();
}
/************************************************************************/
/* CloseDependentDatasets() */
/************************************************************************/
int MrSIDDataset::CloseDependentDatasets()
{
int bRet = GDALPamDataset::CloseDependentDatasets();
if ( papoOverviewDS )
{
for( int i = 0; i < nOverviewCount; i++ )
delete papoOverviewDS[i];
CPLFree( papoOverviewDS );
papoOverviewDS = NULL;
bRet = TRUE;
}
return bRet;
}
/************************************************************************/
/* IRasterIO() */
/************************************************************************/
CPLErr MrSIDDataset::IRasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount, int *panBandMap,
GSpacing nPixelSpace, GSpacing nLineSpace,
GSpacing nBandSpace,
GDALRasterIOExtraArg* psExtraArg )
{
/* -------------------------------------------------------------------- */
/* We need various criteria to skip out to block based methods. */
/* -------------------------------------------------------------------- */
int bUseBlockedIO = bForceCachedIO;
if( nYSize == 1 || nXSize * ((double) nYSize) < 100.0 )
bUseBlockedIO = TRUE;
if( nBufYSize == 1 || nBufXSize * ((double) nBufYSize) < 100.0 )
bUseBlockedIO = TRUE;
if( CSLTestBoolean( CPLGetConfigOption( "GDAL_ONE_BIG_READ", "NO") ) )
bUseBlockedIO = FALSE;
if( bUseBlockedIO )
return GDALDataset::BlockBasedRasterIO(
eRWFlag, nXOff, nYOff, nXSize, nYSize,
pData, nBufXSize, nBufYSize, eBufType,
nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace, psExtraArg );
CPLDebug( "MrSID", "RasterIO() - using optimized dataset level IO." );
/* -------------------------------------------------------------------- */
/* What is our requested window relative to the base dataset. */
/* We want to operate from here on as if we were operating on */
/* the full res band. */
/* -------------------------------------------------------------------- */
int nZoomMag = (int) ((1/dfCurrentMag) * 1.0000001);
nXOff *= nZoomMag;
nYOff *= nZoomMag;
nXSize *= nZoomMag;
nYSize *= nZoomMag;
/* -------------------------------------------------------------------- */
/* We need to figure out the best zoom level to use for this */
/* request. We apply a small fudge factor to make sure that */
/* request just very, very slightly larger than a zoom level do */
/* not force us to the next level. */
/* -------------------------------------------------------------------- */
int iOverview = 0;
double dfZoomMag = MIN((nXSize / (double)nBufXSize),
(nYSize / (double)nBufYSize));
for( nZoomMag = 1;
nZoomMag * 2 < (dfZoomMag + 0.1)
&& iOverview < poParentDS->nOverviewCount;
nZoomMag *= 2, iOverview++ ) {}
/* -------------------------------------------------------------------- */
/* Work out the size of the temporary buffer and allocate it. */
/* The temporary buffer will generally be at a moderately */
/* higher resolution than the buffer of data requested. */
/* -------------------------------------------------------------------- */
int nTmpPixelSize;
LTIPixel oPixel( eColorSpace, nBands, eSampleType );
LT_STATUS eLTStatus;
unsigned int maxWidth;
unsigned int maxHeight;
eLTStatus = poImageReader->getDimsAtMag(1.0/nZoomMag,maxWidth,maxHeight);
if( !LT_SUCCESS(eLTStatus)) {
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDataset::IRasterIO(): Failed to get zoomed image dimensions.\n%s",
getLastStatusString( eLTStatus ) );
return CE_Failure;
}
int maxWidthAtL0 = bIsOverview?poParentDS->GetRasterXSize():this->GetRasterXSize();
int maxHeightAtL0 = bIsOverview?poParentDS->GetRasterYSize():this->GetRasterYSize();
int sceneUlXOff = nXOff / nZoomMag;
int sceneUlYOff = nYOff / nZoomMag;
int sceneWidth = (int)(nXSize * (double) maxWidth / (double)maxWidthAtL0 + 0.99);
int sceneHeight = (int)(nYSize * (double) maxHeight / (double)maxHeightAtL0 + 0.99);
if( (sceneUlXOff + sceneWidth) > (int) maxWidth )
sceneWidth = maxWidth - sceneUlXOff;
if( (sceneUlYOff + sceneHeight) > (int) maxHeight )
sceneHeight = maxHeight - sceneUlYOff;
LTISceneBuffer oLTIBuffer( oPixel, sceneWidth, sceneHeight, NULL );
nTmpPixelSize = GDALGetDataTypeSize( eDataType ) / 8;
/* -------------------------------------------------------------------- */
/* Create navigator, and move to the requested scene area. */
/* -------------------------------------------------------------------- */
LTINavigator oNav( *poImageReader );
if( !LT_SUCCESS(oNav.setSceneAsULWH( sceneUlXOff, sceneUlYOff,
sceneWidth, sceneHeight,
1.0 / nZoomMag )) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDataset::IRasterIO(): Failed to set scene position." );
return CE_Failure;
}
CPLDebug( "MrSID",
"Dataset:IRasterIO(%d,%d %dx%d -> %dx%d -> %dx%d, zoom=%d)",
nXOff, nYOff, nXSize, nYSize,
sceneWidth, sceneHeight,
nBufXSize, nBufYSize,
nZoomMag );
if( !oNav.isSceneValid() )
CPLDebug( "MrSID", "LTINavigator in invalid state." );
/* -------------------------------------------------------------------- */
/* Read into the buffer. */
/* -------------------------------------------------------------------- */
eLTStatus = poImageReader->read(oNav.getScene(),oLTIBuffer);
if(!LT_SUCCESS(eLTStatus) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDRasterBand::IRasterIO(): Failed to load image.\n%s",
getLastStatusString( eLTStatus ) );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* If we are pulling the data at a matching resolution, try to */
/* do a more direct copy without subsampling. */
/* -------------------------------------------------------------------- */
int iBufLine, iBufPixel;
if( nBufXSize == sceneWidth && nBufYSize == sceneHeight )
{
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
GByte *pabySrcBand = (GByte *)
oLTIBuffer.getTotalBandData( panBandMap[iBand] - 1 );
for( int iLine = 0; iLine < nBufYSize; iLine++ )
{
GDALCopyWords( pabySrcBand + iLine*nTmpPixelSize*sceneWidth,
eDataType, nTmpPixelSize,
((GByte *)pData) + iLine*nLineSpace
+ iBand * nBandSpace,
eBufType, nPixelSpace,
nBufXSize );
}
}
}
/* -------------------------------------------------------------------- */
/* Manually resample to our target buffer. */
/* -------------------------------------------------------------------- */
else
{
for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
{
int iTmpLine = (int) floor(((iBufLine+0.5) / nBufYSize)*sceneHeight);
for( iBufPixel = 0; iBufPixel < nBufXSize; iBufPixel++ )
{
int iTmpPixel = (int)
floor(((iBufPixel+0.5) / nBufXSize) * sceneWidth);
for( int iBand = 0; iBand < nBandCount; iBand++ )
{
GByte *pabySrc, *pabyDst;
pabyDst = ((GByte *) pData)
+ nPixelSpace * iBufPixel
+ nLineSpace * iBufLine
+ nBandSpace * iBand;
pabySrc = (GByte *) oLTIBuffer.getTotalBandData(
panBandMap[iBand] - 1 );
pabySrc += (iTmpLine * sceneWidth + iTmpPixel) * nTmpPixelSize;
if( eDataType == eBufType )
memcpy( pabyDst, pabySrc, nTmpPixelSize );
else
GDALCopyWords( pabySrc, eDataType, 0,
pabyDst, eBufType, 0, 1 );
}
}
}
}
return CE_None;
}
/************************************************************************/
/* IBuildOverviews() */
/************************************************************************/
CPLErr MrSIDDataset::IBuildOverviews( const char *, int, int *,
int, int *, GDALProgressFunc,
void * )
{
CPLError( CE_Warning, CPLE_AppDefined,
"MrSID overviews are built-in, so building external "
"overviews is unnecessary. Ignoring.\n" );
return CE_None;
}
/************************************************************************/
/* SerializeMetadataRec() */
/************************************************************************/
char *MrSIDDataset::SerializeMetadataRec( const LTIMetadataRecord *poMetadataRec )
{
GUInt32 iNumDims = 0;
const GUInt32 *paiDims = NULL;
const void *pData = poMetadataRec->getArrayData( iNumDims, paiDims );
GUInt32 i, j, k = 0, iLength;
char *pszMetadata = CPLStrdup( "" );
for ( i = 0; i < iNumDims; i++ )
{
// stops on large binary data
if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_UINT8
&& paiDims[i] > 1024 )
return pszMetadata;
for ( j = 0; j < paiDims[i]; j++ )
{
CPLString osTemp;
switch( poMetadataRec->getDataType() )
{
case LTI_METADATA_DATATYPE_UINT8:
case LTI_METADATA_DATATYPE_SINT8:
osTemp.Printf( "%d", ((GByte *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_UINT16:
osTemp.Printf( "%u", ((GUInt16 *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_SINT16:
osTemp.Printf( "%d", ((GInt16 *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_UINT32:
osTemp.Printf( "%u", ((GUInt32 *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_SINT32:
osTemp.Printf( "%d", ((GInt32 *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_FLOAT32:
osTemp.Printf( "%f", ((float *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_FLOAT64:
osTemp.Printf( "%f", ((double *)pData)[k++] );
break;
case LTI_METADATA_DATATYPE_ASCII:
osTemp = ((const char **)pData)[k++];
break;
default:
osTemp = "";
break;
}
iLength = strlen(pszMetadata) + strlen(osTemp) + 2;
pszMetadata = (char *)CPLRealloc( pszMetadata, iLength );
if ( !EQUAL( pszMetadata, "" ) )
strncat( pszMetadata, ",", 1 );
strncat( pszMetadata, osTemp, iLength );
}
}
return pszMetadata;
}
/************************************************************************/
/* GetMetadataElement() */
/************************************************************************/
int MrSIDDataset::GetMetadataElement( const char *pszKey, void *pValue,
int iLength )
{
if ( !poMetadata->has( pszKey ) )
return FALSE;
const LTIMetadataRecord *poMetadataRec = NULL;
poMetadata->get( pszKey, poMetadataRec );
if ( !poMetadataRec->isScalar() )
return FALSE;
// XXX: return FALSE if we have more than one element in metadata record
int iSize;
switch( poMetadataRec->getDataType() )
{
case LTI_METADATA_DATATYPE_UINT8:
case LTI_METADATA_DATATYPE_SINT8:
iSize = 1;
break;
case LTI_METADATA_DATATYPE_UINT16:
case LTI_METADATA_DATATYPE_SINT16:
iSize = 2;
break;
case LTI_METADATA_DATATYPE_UINT32:
case LTI_METADATA_DATATYPE_SINT32:
case LTI_METADATA_DATATYPE_FLOAT32:
iSize = 4;
break;
case LTI_METADATA_DATATYPE_FLOAT64:
iSize = 8;
break;
case LTI_METADATA_DATATYPE_ASCII:
iSize = iLength;
break;
default:
iSize = 0;
break;
}
if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_ASCII )
{
strncpy( (char *)pValue,
((const char**)poMetadataRec->getScalarData())[0], iSize );
((char *)pValue)[iSize - 1] = '\0';
}
else
memcpy( pValue, poMetadataRec->getScalarData(), iSize );
return TRUE;
}
/************************************************************************/
/* GetFileList() */
/************************************************************************/
char** MrSIDDataset::GetFileList()
{
char** papszFileList = GDALPamDataset::GetFileList();
if (osMETFilename.size() != 0)
papszFileList = CSLAddString(papszFileList, osMETFilename.c_str());
return papszFileList;
}
/************************************************************************/
/* OpenZoomLevel() */
/************************************************************************/
CPLErr MrSIDDataset::OpenZoomLevel( lt_int32 iZoom )
{
/* -------------------------------------------------------------------- */
/* Get image geometry. */
/* -------------------------------------------------------------------- */
if ( iZoom != 0 )
{
lt_uint32 iWidth, iHeight;
dfCurrentMag = LTIUtils::levelToMag( iZoom );
poImageReader->getDimsAtMag( dfCurrentMag, iWidth, iHeight );
nRasterXSize = iWidth;
nRasterYSize = iHeight;
}
else
{
dfCurrentMag = 1.0;
nRasterXSize = poImageReader->getWidth();
nRasterYSize = poImageReader->getHeight();
}
nBands = poImageReader->getNumBands();
nBlockXSize = nRasterXSize;
nBlockYSize = poImageReader->getStripHeight();
CPLDebug( "MrSID", "Opened zoom level %d with size %dx%d.",
iZoom, nRasterXSize, nRasterYSize );
try
{
poLTINav = new LTIDLLNavigator<LTINavigator>( *poImageReader );
}
catch ( ... )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDataset::OpenZoomLevel(): "
"Failed to create LTINavigator object." );
return CE_Failure;
}
/* -------------------------------------------------------------------- */
/* Handle sample type and color space. */
/* -------------------------------------------------------------------- */
eColorSpace = poImageReader->getColorSpace();
eSampleType = poImageReader->getDataType();
switch ( eSampleType )
{
case LTI_DATATYPE_UINT16:
eDataType = GDT_UInt16;
break;
case LTI_DATATYPE_SINT16:
eDataType = GDT_Int16;
break;
case LTI_DATATYPE_UINT32:
eDataType = GDT_UInt32;
break;
case LTI_DATATYPE_SINT32:
eDataType = GDT_Int32;
break;
case LTI_DATATYPE_FLOAT32:
eDataType = GDT_Float32;
break;
case LTI_DATATYPE_FLOAT64:
eDataType = GDT_Float64;
break;
case LTI_DATATYPE_UINT8:
case LTI_DATATYPE_SINT8:
default:
eDataType = GDT_Byte;
break;
}
/* -------------------------------------------------------------------- */
/* Read georeferencing. */
/* -------------------------------------------------------------------- */
if ( !poImageReader->isGeoCoordImplicit() )
{
const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
oGeo.get( adfGeoTransform[0], adfGeoTransform[3],
adfGeoTransform[1], adfGeoTransform[5],
adfGeoTransform[2], adfGeoTransform[4] );
adfGeoTransform[0] = adfGeoTransform[0] - adfGeoTransform[1] / 2;
adfGeoTransform[3] = adfGeoTransform[3] - adfGeoTransform[5] / 2;
bGeoTransformValid = TRUE;
}
else if( iZoom == 0 )
{
bGeoTransformValid =
GDALReadWorldFile( GetDescription(), NULL,
adfGeoTransform )
|| GDALReadWorldFile( GetDescription(), ".wld",
adfGeoTransform );
}
/* -------------------------------------------------------------------- */
/* Read wkt. */
/* -------------------------------------------------------------------- */
#ifdef MRSID_HAVE_GETWKT
if( !poImageReader->isGeoCoordImplicit() )
{
const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
if( oGeo.getWKT() )
{
/* Workaround probable issue with GeoDSK 7 on 64bit Linux */
if (!(pszProjection != NULL && !EQUALN(pszProjection, "LOCAL_CS", 8)
&& EQUALN( oGeo.getWKT(), "LOCAL_CS", 8)))
{
CPLFree( pszProjection );
pszProjection = CPLStrdup( oGeo.getWKT() );
}
}
}
#endif // HAVE_MRSID_GETWKT
/* -------------------------------------------------------------------- */
/* Special case for https://zulu.ssc.nasa.gov/mrsid/mrsid.pl */
/* where LandSat .SID are accompanied by a .met file with the */
/* projection */
/* -------------------------------------------------------------------- */
if (iZoom == 0 && (pszProjection == NULL || pszProjection[0] == '\0') &&
EQUAL(CPLGetExtension(GetDescription()), "sid"))
{
const char* pszMETFilename = CPLResetExtension(GetDescription(), "met");
VSILFILE* fp = VSIFOpenL(pszMETFilename, "rb");
if (fp)
{
const char* pszLine;
int nCountLine = 0;
int nUTMZone = 0;
int bWGS84 = FALSE;
int bUnitsMeter = FALSE;
while ( (pszLine = CPLReadLine2L(fp, 200, NULL)) != NULL &&
++nCountLine < 1000 )
{
if (nCountLine == 1 && strcmp(pszLine, "::MetadataFile") != 0)
break;
if (EQUALN(pszLine, "Projection UTM ", 15))
nUTMZone = atoi(pszLine + 15);
else if (EQUAL(pszLine, "Datum WGS84"))
bWGS84 = TRUE;
else if (EQUAL(pszLine, "Units Meters"))
bUnitsMeter = TRUE;
}
VSIFCloseL(fp);
/* Images in southern hemisphere have negative northings in the */
/* .sdw file. A bit weird, but anyway we must use the northern */
/* UTM SRS for consistency */
if (nUTMZone >= 1 && nUTMZone <= 60 && bWGS84 && bUnitsMeter)
{
osMETFilename = pszMETFilename;
OGRSpatialReference oSRS;
oSRS.importFromEPSG(32600 + nUTMZone);
CPLFree(pszProjection);
pszProjection = NULL;
oSRS.exportToWkt(&pszProjection);
}
}
}
/* -------------------------------------------------------------------- */
/* Read NoData value. */
/* -------------------------------------------------------------------- */
poNDPixel = poImageReader->getNoDataPixel();
/* -------------------------------------------------------------------- */
/* Create band information objects. */
/* -------------------------------------------------------------------- */
int iBand;
for( iBand = 1; iBand <= nBands; iBand++ )
SetBand( iBand, new MrSIDRasterBand( this, iBand ) );
return CE_None;
}
/************************************************************************/
/* MrSIDIdentify() */
/* */
/* Identify method that only supports MrSID files. */
/************************************************************************/
static int MrSIDIdentify( GDALOpenInfo * poOpenInfo )
{
if( poOpenInfo->nHeaderBytes < 32 )
return FALSE;
if ( !EQUALN((const char *) poOpenInfo->pabyHeader, "msid", 4) )
return FALSE;
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
lt_uint8 gen;
bool raster;
LT_STATUS eStat =
MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
if (!LT_SUCCESS(eStat) || !raster)
return FALSE;
#endif
return TRUE;
}
/************************************************************************/
/* MrSIDOpen() */
/* */
/* Open method that only supports MrSID files. */
/************************************************************************/
static GDALDataset* MrSIDOpen( GDALOpenInfo *poOpenInfo )
{
if (!MrSIDIdentify(poOpenInfo))
return NULL;
return MrSIDDataset::Open( poOpenInfo, FALSE );
}
#ifdef MRSID_J2K
static const unsigned char jpc_header[] =
{0xff,0x4f};
/************************************************************************/
/* JP2Identify() */
/* */
/* Identify method that only supports JPEG2000 files. */
/************************************************************************/
static int JP2Identify( GDALOpenInfo *poOpenInfo )
{
if( poOpenInfo->nHeaderBytes < 32 )
return FALSE;
if( memcmp( poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header) ) == 0 )
{
const char *pszExtension;
pszExtension = CPLGetExtension( poOpenInfo->pszFilename );
if( !EQUAL(pszExtension,"jpc") && !EQUAL(pszExtension,"j2k")
&& !EQUAL(pszExtension,"jp2") && !EQUAL(pszExtension,"jpx")
&& !EQUAL(pszExtension,"j2c") && !EQUAL(pszExtension,"ntf"))
return FALSE;
}
else if( !EQUALN((const char *) poOpenInfo->pabyHeader + 4, "jP ", 4) )
return FALSE;
return TRUE;
}
/************************************************************************/
/* JP2Open() */
/* */
/* Open method that only supports JPEG2000 files. */
/************************************************************************/
static GDALDataset* JP2Open( GDALOpenInfo *poOpenInfo )
{
if (!JP2Identify(poOpenInfo))
return NULL;
return MrSIDDataset::Open( poOpenInfo, TRUE );
}
#endif // MRSID_J2K
/************************************************************************/
/* Open() */
/************************************************************************/
GDALDataset *MrSIDDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJP2 )
{
if(poOpenInfo->fpL)
{
VSIFCloseL( poOpenInfo->fpL );
poOpenInfo->fpL = NULL;
}
/* -------------------------------------------------------------------- */
/* Make sure we have hooked CSV lookup for GDAL_DATA. */
/* -------------------------------------------------------------------- */
LibgeotiffOneTimeInit();
/* -------------------------------------------------------------------- */
/* Create a corresponding GDALDataset. */
/* -------------------------------------------------------------------- */
MrSIDDataset *poDS;
LT_STATUS eStat;
poDS = new MrSIDDataset(bIsJP2);
// try the LTIOFileStream first, since it uses filesystem caching
eStat = poDS->oLTIStream.initialize( poOpenInfo->pszFilename, "rb" );
if ( LT_SUCCESS(eStat) )
{
eStat = poDS->oLTIStream.open();
if ( LT_SUCCESS(eStat) )
poDS->poStream = &(poDS->oLTIStream);
}
// fall back on VSI for non-files
if ( !LT_SUCCESS(eStat) || !poDS->poStream )
{
eStat = poDS->oVSIStream.initialize( poOpenInfo->pszFilename, "rb" );
if ( !LT_SUCCESS(eStat) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"LTIVSIStream::initialize(): "
"failed to open file \"%s\".\n%s",
poOpenInfo->pszFilename, getLastStatusString( eStat ) );
delete poDS;
return NULL;
}
eStat = poDS->oVSIStream.open();
if ( !LT_SUCCESS(eStat) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"LTIVSIStream::open(): "
"failed to open file \"%s\".\n%s",
poOpenInfo->pszFilename, getLastStatusString( eStat ) );
delete poDS;
return NULL;
}
poDS->poStream = &(poDS->oVSIStream);
}
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
#ifdef MRSID_J2K
if ( bIsJP2 )
{
J2KImageReader *reader = J2KImageReader::create();
eStat = reader->initialize( *(poDS->poStream) );
poDS->poImageReader = reader;
}
else
#endif /* MRSID_J2K */
{
MrSIDImageReader *reader = MrSIDImageReader::create();
eStat = reader->initialize( poDS->poStream, NULL );
poDS->poImageReader = reader;
}
#else /* LTI_SDK_MAJOR < 7 */
#ifdef MRSID_J2K
if ( bIsJP2 )
{
poDS->poImageReader =
new LTIDLLReader<J2KImageReader>( *(poDS->poStream), true );
eStat = poDS->poImageReader->initialize();
}
else
#endif /* MRSID_J2K */
{
poDS->poImageReader =
new LTIDLLReader<MrSIDImageReader>( poDS->poStream, NULL );
eStat = poDS->poImageReader->initialize();
}
#endif /* LTI_SDK_MAJOR >= 7 */
if ( !LT_SUCCESS(eStat) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"LTIImageReader::initialize(): "
"failed to initialize reader from the stream \"%s\".\n%s",
poOpenInfo->pszFilename, getLastStatusString( eStat ) );
delete poDS;
return NULL;
}
/* -------------------------------------------------------------------- */
/* Read metadata. */
/* -------------------------------------------------------------------- */
poDS->poMetadata = new LTIDLLCopy<LTIMetadataDatabase>(
poDS->poImageReader->getMetadata() );
const GUInt32 iNumRecs = poDS->poMetadata->getIndexCount();
GUInt32 i;
for ( i = 0; i < iNumRecs; i++ )
{
const LTIMetadataRecord *poMetadataRec = NULL;
if ( LT_SUCCESS(poDS->poMetadata->getDataByIndex(i, poMetadataRec)) )
{
char *pszElement = poDS->SerializeMetadataRec( poMetadataRec );
char *pszKey = CPLStrdup( poMetadataRec->getTagName() );
char *pszTemp = pszKey;
// GDAL metadata keys should not contain ':' and '=' characters.
// We will replace them with '_'.
do
{
if ( *pszTemp == ':' || *pszTemp == '=' )
*pszTemp = '_';
}
while ( *++pszTemp );
poDS->SetMetadataItem( pszKey, pszElement );
CPLFree( pszElement );
CPLFree( pszKey );
}
}
/* -------------------------------------------------------------------- */
/* Add MrSID version. */
/* -------------------------------------------------------------------- */
#ifdef MRSID_J2K
if( !bIsJP2 )
#endif
{
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
lt_uint8 gen;
bool raster;
MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d%s", gen, raster ? "" : " LiDAR") );
#else
lt_uint8 major;
lt_uint8 minor;
char letter;
MrSIDImageReader* poMrSIDImageReader = (MrSIDImageReader*)poDS->poImageReader;
poMrSIDImageReader->getVersion(major, minor, minor, letter);
if (major < 2)
major = 2;
poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d", major) );
#endif
}
poDS->GetGTIFDefn();
/* -------------------------------------------------------------------- */
/* Get number of resolution levels (we will use them as overviews).*/
/* -------------------------------------------------------------------- */
#ifdef MRSID_J2K
if( bIsJP2 )
poDS->nOverviewCount
= ((J2KImageReader *) (poDS->poImageReader))->getNumLevels();
else
#endif
poDS->nOverviewCount
= ((MrSIDImageReader *) (poDS->poImageReader))->getNumLevels();
if ( poDS->nOverviewCount > 0 )
{
lt_int32 i;
poDS->papoOverviewDS = (MrSIDDataset **)
CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );
for ( i = 0; i < poDS->nOverviewCount; i++ )
{
poDS->papoOverviewDS[i] = new MrSIDDataset(bIsJP2);
poDS->papoOverviewDS[i]->poImageReader = poDS->poImageReader;
poDS->papoOverviewDS[i]->OpenZoomLevel( i + 1 );
poDS->papoOverviewDS[i]->bIsOverview = TRUE;
poDS->papoOverviewDS[i]->poParentDS = poDS;
}
}
/* -------------------------------------------------------------------- */
/* Create object for the whole image. */
/* -------------------------------------------------------------------- */
poDS->SetDescription( poOpenInfo->pszFilename );
poDS->OpenZoomLevel( 0 );
CPLDebug( "MrSID",
"Opened image: width %d, height %d, bands %d",
poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );
if( poDS->nBands > 1 )
poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
if (bIsJP2)
{
poDS->LoadJP2Metadata(poOpenInfo);
}
/* -------------------------------------------------------------------- */
/* Initialize any PAM information. */
/* -------------------------------------------------------------------- */
poDS->TryLoadXML();
/* -------------------------------------------------------------------- */
/* Initialize the overview manager for mask band support. */
/* -------------------------------------------------------------------- */
poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
return( poDS );
}
/************************************************************************/
/* EPSGProjMethodToCTProjMethod() */
/* */
/* Convert between the EPSG enumeration for projection methods, */
/* and the GeoTIFF CT codes. */
/* Explicitly copied from geo_normalize.c of the GeoTIFF package */
/************************************************************************/
static int EPSGProjMethodToCTProjMethod( int nEPSG )
{
/* see trf_method.csv for list of EPSG codes */
switch( nEPSG )
{
case 9801:
return( CT_LambertConfConic_1SP );
case 9802:
return( CT_LambertConfConic_2SP );
case 9803:
return( CT_LambertConfConic_2SP ); /* Belgian variant not supported */
case 9804:
return( CT_Mercator ); /* 1SP and 2SP not differentiated */
case 9805:
return( CT_Mercator ); /* 1SP and 2SP not differentiated */
case 9806:
return( CT_CassiniSoldner );
case 9807:
return( CT_TransverseMercator );
case 9808:
return( CT_TransvMercator_SouthOriented );
case 9809:
return( CT_ObliqueStereographic );
case 9810:
return( CT_PolarStereographic );
case 9811:
return( CT_NewZealandMapGrid );
case 9812:
return( CT_ObliqueMercator ); /* is hotine actually different? */
case 9813:
return( CT_ObliqueMercator_Laborde );
case 9814:
return( CT_ObliqueMercator_Rosenmund ); /* swiss */
case 9815:
return( CT_ObliqueMercator );
case 9816: /* tunesia mining grid has no counterpart */
return( KvUserDefined );
}
return( KvUserDefined );
}
/* EPSG Codes for projection parameters. Unfortunately, these bear no
relationship to the GeoTIFF codes even though the names are so similar. */
#define EPSGNatOriginLat 8801
#define EPSGNatOriginLong 8802
#define EPSGNatOriginScaleFactor 8805
#define EPSGFalseEasting 8806
#define EPSGFalseNorthing 8807
#define EPSGProjCenterLat 8811
#define EPSGProjCenterLong 8812
#define EPSGAzimuth 8813
#define EPSGAngleRectifiedToSkewedGrid 8814
#define EPSGInitialLineScaleFactor 8815
#define EPSGProjCenterEasting 8816
#define EPSGProjCenterNorthing 8817
#define EPSGPseudoStdParallelLat 8818
#define EPSGPseudoStdParallelScaleFactor 8819
#define EPSGFalseOriginLat 8821
#define EPSGFalseOriginLong 8822
#define EPSGStdParallel1Lat 8823
#define EPSGStdParallel2Lat 8824
#define EPSGFalseOriginEasting 8826
#define EPSGFalseOriginNorthing 8827
#define EPSGSphericalOriginLat 8828
#define EPSGSphericalOriginLong 8829
#define EPSGInitialLongitude 8830
#define EPSGZoneWidth 8831
/************************************************************************/
/* SetGTParmIds() */
/* */
/* This is hardcoded logic to set the GeoTIFF parameter */
/* identifiers for all the EPSG supported projections. As the */
/* trf_method.csv table grows with new projections, this code */
/* will need to be updated. */
/* Explicitly copied from geo_normalize.c of the GeoTIFF package. */
/************************************************************************/
static int SetGTParmIds( int nCTProjection,
int *panProjParmId,
int *panEPSGCodes )
{
int anWorkingDummy[7];
if( panEPSGCodes == NULL )
panEPSGCodes = anWorkingDummy;
if( panProjParmId == NULL )
panProjParmId = anWorkingDummy;
memset( panEPSGCodes, 0, sizeof(int) * 7 );
/* psDefn->nParms = 7; */
switch( nCTProjection )
{
case CT_CassiniSoldner:
case CT_NewZealandMapGrid:
panProjParmId[0] = ProjNatOriginLatGeoKey;
panProjParmId[1] = ProjNatOriginLongGeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
panEPSGCodes[0] = EPSGNatOriginLat;
panEPSGCodes[1] = EPSGNatOriginLong;
panEPSGCodes[5] = EPSGFalseEasting;
panEPSGCodes[6] = EPSGFalseNorthing;
return TRUE;
case CT_ObliqueMercator:
panProjParmId[0] = ProjCenterLatGeoKey;
panProjParmId[1] = ProjCenterLongGeoKey;
panProjParmId[2] = ProjAzimuthAngleGeoKey;
panProjParmId[3] = ProjRectifiedGridAngleGeoKey;
panProjParmId[4] = ProjScaleAtCenterGeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
panEPSGCodes[0] = EPSGProjCenterLat;
panEPSGCodes[1] = EPSGProjCenterLong;
panEPSGCodes[2] = EPSGAzimuth;
panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
panEPSGCodes[4] = EPSGInitialLineScaleFactor;
panEPSGCodes[5] = EPSGProjCenterEasting;
panEPSGCodes[6] = EPSGProjCenterNorthing;
return TRUE;
case CT_ObliqueMercator_Laborde:
panProjParmId[0] = ProjCenterLatGeoKey;
panProjParmId[1] = ProjCenterLongGeoKey;
panProjParmId[2] = ProjAzimuthAngleGeoKey;
panProjParmId[4] = ProjScaleAtCenterGeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
panEPSGCodes[0] = EPSGProjCenterLat;
panEPSGCodes[1] = EPSGProjCenterLong;
panEPSGCodes[2] = EPSGAzimuth;
panEPSGCodes[4] = EPSGInitialLineScaleFactor;
panEPSGCodes[5] = EPSGProjCenterEasting;
panEPSGCodes[6] = EPSGProjCenterNorthing;
return TRUE;
case CT_LambertConfConic_1SP:
case CT_Mercator:
case CT_ObliqueStereographic:
case CT_PolarStereographic:
case CT_TransverseMercator:
case CT_TransvMercator_SouthOriented:
panProjParmId[0] = ProjNatOriginLatGeoKey;
panProjParmId[1] = ProjNatOriginLongGeoKey;
panProjParmId[4] = ProjScaleAtNatOriginGeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
panEPSGCodes[0] = EPSGNatOriginLat;
panEPSGCodes[1] = EPSGNatOriginLong;
panEPSGCodes[4] = EPSGNatOriginScaleFactor;
panEPSGCodes[5] = EPSGFalseEasting;
panEPSGCodes[6] = EPSGFalseNorthing;
return TRUE;
case CT_LambertConfConic_2SP:
panProjParmId[0] = ProjFalseOriginLatGeoKey;
panProjParmId[1] = ProjFalseOriginLongGeoKey;
panProjParmId[2] = ProjStdParallel1GeoKey;
panProjParmId[3] = ProjStdParallel2GeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
panEPSGCodes[0] = EPSGFalseOriginLat;
panEPSGCodes[1] = EPSGFalseOriginLong;
panEPSGCodes[2] = EPSGStdParallel1Lat;
panEPSGCodes[3] = EPSGStdParallel2Lat;
panEPSGCodes[5] = EPSGFalseOriginEasting;
panEPSGCodes[6] = EPSGFalseOriginNorthing;
return TRUE;
case CT_SwissObliqueCylindrical:
panProjParmId[0] = ProjCenterLatGeoKey;
panProjParmId[1] = ProjCenterLongGeoKey;
panProjParmId[5] = ProjFalseEastingGeoKey;
panProjParmId[6] = ProjFalseNorthingGeoKey;
/* EPSG codes? */
return TRUE;
default:
return( FALSE );
}
}
static const char *papszDatumEquiv[] =
{
"Militar_Geographische_Institut",
"Militar_Geographische_Institute",
"World_Geodetic_System_1984",
"WGS_1984",
"WGS_72_Transit_Broadcast_Ephemeris",
"WGS_1972_Transit_Broadcast_Ephemeris",
"World_Geodetic_System_1972",
"WGS_1972",
"European_Terrestrial_Reference_System_89",
"European_Reference_System_1989",
NULL
};
/************************************************************************/
/* WKTMassageDatum() */
/* */
/* Massage an EPSG datum name into WMT format. Also transform */
/* specific exception cases into WKT versions. */
/* Explicitly copied from the gt_wkt_srs.cpp. */
/************************************************************************/
static void WKTMassageDatum( char ** ppszDatum )
{
int i, j;
char *pszDatum = *ppszDatum;
if (pszDatum[0] == '\0')
return;
/* -------------------------------------------------------------------- */
/* Translate non-alphanumeric values to underscores. */
/* -------------------------------------------------------------------- */
for( i = 0; pszDatum[i] != '\0'; i++ )
{
if( !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
&& !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
&& !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
{
pszDatum[i] = '_';
}
}
/* -------------------------------------------------------------------- */
/* Remove repeated and trailing underscores. */
/* -------------------------------------------------------------------- */
for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
{
if( pszDatum[j] == '_' && pszDatum[i] == '_' )
continue;
pszDatum[++j] = pszDatum[i];
}
if( pszDatum[j] == '_' )
pszDatum[j] = '\0';
else
pszDatum[j+1] = '\0';
/* -------------------------------------------------------------------- */
/* Search for datum equivelences. Specific massaged names get */
/* mapped to OpenGIS specified names. */
/* -------------------------------------------------------------------- */
for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
{
if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
{
CPLFree( *ppszDatum );
*ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
return;
}
}
}
/************************************************************************/
/* FetchProjParms() */
/* */
/* Fetch the projection parameters for a particular projection */
/* from MrSID metadata, and fill the GTIFDefn structure out */
/* with them. */
/* Copied from geo_normalize.c of the GeoTIFF package. */
/************************************************************************/
void MrSIDDataset::FetchProjParms()
{
double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
/* -------------------------------------------------------------------- */
/* Get the false easting, and northing if available. */
/* -------------------------------------------------------------------- */
if( !GetMetadataElement( "GEOTIFF_NUM::3082::ProjFalseEastingGeoKey",
&dfFalseEasting )
&& !GetMetadataElement( "GEOTIFF_NUM::3090:ProjCenterEastingGeoKey",
&dfFalseEasting ) )
dfFalseEasting = 0.0;
if( !GetMetadataElement( "GEOTIFF_NUM::3083::ProjFalseNorthingGeoKey",
&dfFalseNorthing )
&& !GetMetadataElement( "GEOTIFF_NUM::3091::ProjCenterNorthingGeoKey",
&dfFalseNorthing ) )
dfFalseNorthing = 0.0;
switch( psDefn->CTProjection )
{
/* -------------------------------------------------------------------- */
case CT_Stereographic:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
&dfNatOriginScale ) == 0 )
dfNatOriginScale = 1.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
psDefn->ProjParm[4] = dfNatOriginScale;
psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_LambertConfConic_1SP:
case CT_Mercator:
case CT_ObliqueStereographic:
case CT_TransverseMercator:
case CT_TransvMercator_SouthOriented:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
&dfNatOriginScale ) == 0 )
dfNatOriginScale = 1.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
psDefn->ProjParm[4] = dfNatOriginScale;
psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_ObliqueMercator: /* hotine */
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3094::ProjAzimuthAngleGeoKey",
&dfAzimuth ) == 0 )
dfAzimuth = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3096::ProjRectifiedGridAngleGeoKey",
&dfRectGridAngle ) == 0 )
dfRectGridAngle = 90.0;
if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
&dfNatOriginScale ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
&dfNatOriginScale ) == 0 )
dfNatOriginScale = 1.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
psDefn->ProjParm[2] = dfAzimuth;
psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
psDefn->ProjParm[3] = dfRectGridAngle;
psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
psDefn->ProjParm[4] = dfNatOriginScale;
psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_CassiniSoldner:
case CT_Polyconic:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
&dfNatOriginScale ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
&dfNatOriginScale ) == 0 )
dfNatOriginScale = 1.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
psDefn->ProjParm[4] = dfNatOriginScale;
psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_AzimuthalEquidistant:
case CT_MillerCylindrical:
case CT_Equirectangular:
case CT_Gnomonic:
case CT_LambertAzimEqualArea:
case CT_Orthographic:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_Robinson:
case CT_Sinusoidal:
case CT_VanDerGrinten:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_PolarStereographic:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3095::ProjStraightVertPoleLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
&dfNatOriginScale ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
&dfNatOriginScale ) == 0 )
dfNatOriginScale = 1.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
psDefn->ProjParm[4] = dfNatOriginScale;
psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_LambertConfConic_2SP:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
&dfStdParallel1 ) == 0 )
dfStdParallel1 = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
&dfStdParallel2 ) == 0 )
dfStdParallel1 = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfNatOriginLat;
psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
psDefn->ProjParm[1] = dfNatOriginLong;
psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
psDefn->ProjParm[2] = dfStdParallel1;
psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
psDefn->ProjParm[3] = dfStdParallel2;
psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
/* -------------------------------------------------------------------- */
case CT_AlbersEqualArea:
case CT_EquidistantConic:
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
&dfStdParallel1 ) == 0 )
dfStdParallel1 = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
&dfStdParallel2 ) == 0 )
dfStdParallel1 = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
&dfNatOriginLong ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
&dfNatOriginLong ) == 0 )
dfNatOriginLong = 0.0;
if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
&dfNatOriginLat ) == 0
&& GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
&dfNatOriginLat ) == 0 )
dfNatOriginLat = 0.0;
/* notdef: should transform to decimal degrees at this point */
psDefn->ProjParm[0] = dfStdParallel1;
psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
psDefn->ProjParm[1] = dfStdParallel2;
psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
psDefn->ProjParm[2] = dfNatOriginLat;
psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
psDefn->ProjParm[3] = dfNatOriginLong;
psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
psDefn->ProjParm[5] = dfFalseEasting;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[6] = dfFalseNorthing;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
psDefn->nParms = 7;
break;
}
}
/************************************************************************/
/* GetGTIFDefn() */
/* This function borrowed from the GTIFGetDefn() function. */
/* See geo_normalize.c from the GeoTIFF package. */
/************************************************************************/
void MrSIDDataset::GetGTIFDefn()
{
double dfInvFlattening;
/* -------------------------------------------------------------------- */
/* Make sure we have hooked CSV lookup for GDAL_DATA. */
/* -------------------------------------------------------------------- */
LibgeotiffOneTimeInit();
/* -------------------------------------------------------------------- */
/* Initially we default all the information we can. */
/* -------------------------------------------------------------------- */
psDefn = new( GTIFDefn );
psDefn->Model = KvUserDefined;
psDefn->PCS = KvUserDefined;
psDefn->GCS = KvUserDefined;
psDefn->UOMLength = KvUserDefined;
psDefn->UOMLengthInMeters = 1.0;
psDefn->UOMAngle = KvUserDefined;
psDefn->UOMAngleInDegrees = 1.0;
psDefn->Datum = KvUserDefined;
psDefn->Ellipsoid = KvUserDefined;
psDefn->SemiMajor = 0.0;
psDefn->SemiMinor = 0.0;
psDefn->PM = KvUserDefined;
psDefn->PMLongToGreenwich = 0.0;
psDefn->ProjCode = KvUserDefined;
psDefn->Projection = KvUserDefined;
psDefn->CTProjection = KvUserDefined;
psDefn->nParms = 0;
for( int i = 0; i < MAX_GTIF_PROJPARMS; i++ )
{
psDefn->ProjParm[i] = 0.0;
psDefn->ProjParmId[i] = 0;
}
psDefn->MapSys = KvUserDefined;
psDefn->Zone = 0;
/* -------------------------------------------------------------------- */
/* Try to get the overall model type. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::1024::GTModelTypeGeoKey",
&(psDefn->Model) );
/* -------------------------------------------------------------------- */
/* Try to get a PCS. */
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey",
&(psDefn->PCS) )
&& psDefn->PCS != KvUserDefined )
{
/*
* Translate this into useful information.
*/
GTIFGetPCSInfo( psDefn->PCS, NULL, &(psDefn->ProjCode),
&(psDefn->UOMLength), &(psDefn->GCS) );
}
/* -------------------------------------------------------------------- */
/* If we have the PCS code, but didn't find it in the CSV files */
/* (likely because we can't find them) we will try some ``jiffy */
/* rules'' for UTM and state plane. */
/* -------------------------------------------------------------------- */
if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
{
int nMapSys, nZone;
int nGCS = psDefn->GCS;
nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
if( nMapSys != KvUserDefined )
{
psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
psDefn->GCS = (short) nGCS;
}
}
/* -------------------------------------------------------------------- */
/* If the Proj_ code is specified directly, use that. */
/* -------------------------------------------------------------------- */
if( psDefn->ProjCode == KvUserDefined )
GetMetadataElement( "GEOTIFF_NUM::3074::ProjectionGeoKey",
&(psDefn->ProjCode) );
if( psDefn->ProjCode != KvUserDefined )
{
/*
* We have an underlying projection transformation value. Look
* this up. For a PCS of ``WGS 84 / UTM 11'' the transformation
* would be Transverse Mercator, with a particular set of options.
* The nProjTRFCode itself would correspond to the name
* ``UTM zone 11N'', and doesn't include datum info.
*/
GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),
psDefn->ProjParm );
/*
* Set the GeoTIFF identity of the parameters.
*/
psDefn->CTProjection = (short)
EPSGProjMethodToCTProjMethod( psDefn->Projection );
SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
psDefn->nParms = 7;
}
/* -------------------------------------------------------------------- */
/* Try to get a GCS. If found, it will override any implied by */
/* the PCS. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2048::GeographicTypeGeoKey",
&(psDefn->GCS) );
/* -------------------------------------------------------------------- */
/* Derive the datum, and prime meridian from the GCS. */
/* -------------------------------------------------------------------- */
if( psDefn->GCS != KvUserDefined )
{
GTIFGetGCSInfo( psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
&(psDefn->UOMAngle) );
}
/* -------------------------------------------------------------------- */
/* Handle the GCS angular units. GeogAngularUnitsGeoKey */
/* overrides the GCS or PCS setting. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2054::GeogAngularUnitsGeoKey",
&(psDefn->UOMAngle) );
if( psDefn->UOMAngle != KvUserDefined )
{
GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
&(psDefn->UOMAngleInDegrees) );
}
/* -------------------------------------------------------------------- */
/* Check for a datum setting, and then use the datum to derive */
/* an ellipsoid. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2050::GeogGeodeticDatumGeoKey",
&(psDefn->Datum) );
if( psDefn->Datum != KvUserDefined )
{
GTIFGetDatumInfo( psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
}
/* -------------------------------------------------------------------- */
/* Check for an explicit ellipsoid. Use the ellipsoid to */
/* derive the ellipsoid characteristics, if possible. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2056::GeogEllipsoidGeoKey",
&(psDefn->Ellipsoid) );
if( psDefn->Ellipsoid != KvUserDefined )
{
GTIFGetEllipsoidInfo( psDefn->Ellipsoid, NULL,
&(psDefn->SemiMajor), &(psDefn->SemiMinor) );
}
/* -------------------------------------------------------------------- */
/* Check for overridden ellipsoid parameters. It would be nice */
/* to warn if they conflict with provided information, but for */
/* now we just override. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2057::GeogSemiMajorAxisGeoKey",
&(psDefn->SemiMajor) );
GetMetadataElement( "GEOTIFF_NUM::2058::GeogSemiMinorAxisGeoKey",
&(psDefn->SemiMinor) );
if( GetMetadataElement( "GEOTIFF_NUM::2059::GeogInvFlatteningGeoKey",
&dfInvFlattening ) == 1 )
{
if( dfInvFlattening != 0.0 )
psDefn->SemiMinor = OSRCalcSemiMinorFromInvFlattening(psDefn->SemiMajor, dfInvFlattening);
}
/* -------------------------------------------------------------------- */
/* Get the prime meridian info. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::2051::GeogPrimeMeridianGeoKey",
&(psDefn->PM) );
if( psDefn->PM != KvUserDefined )
{
GTIFGetPMInfo( psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
}
else
{
GetMetadataElement( "GEOTIFF_NUM::2061::GeogPrimeMeridianLongGeoKey",
&(psDefn->PMLongToGreenwich) );
psDefn->PMLongToGreenwich =
GTIFAngleToDD( psDefn->PMLongToGreenwich,
psDefn->UOMAngle );
}
/* -------------------------------------------------------------------- */
/* Have the projection units of measure been overridden? We */
/* should likely be doing something about angular units too, */
/* but these are very rarely not decimal degrees for actual */
/* file coordinates. */
/* -------------------------------------------------------------------- */
GetMetadataElement( "GEOTIFF_NUM::3076::ProjLinearUnitsGeoKey",
&(psDefn->UOMLength) );
if( psDefn->UOMLength != KvUserDefined )
{
GTIFGetUOMLengthInfo( psDefn->UOMLength, NULL,
&(psDefn->UOMLengthInMeters) );
}
/* -------------------------------------------------------------------- */
/* Handle a variety of user defined transform types. */
/* -------------------------------------------------------------------- */
if( GetMetadataElement( "GEOTIFF_NUM::3075::ProjCoordTransGeoKey",
&(psDefn->CTProjection) ) )
{
FetchProjParms();
}
/* -------------------------------------------------------------------- */
/* Try to set the zoned map system information. */
/* -------------------------------------------------------------------- */
psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
/* -------------------------------------------------------------------- */
/* If this is UTM, and we were unable to extract the projection */
/* parameters from the CSV file, just set them directly now, */
/* since it's pretty easy, and a common case. */
/* -------------------------------------------------------------------- */
if( (psDefn->MapSys == MapSys_UTM_North
|| psDefn->MapSys == MapSys_UTM_South)
&& psDefn->CTProjection == KvUserDefined )
{
psDefn->CTProjection = CT_TransverseMercator;
psDefn->nParms = 7;
psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
psDefn->ProjParm[0] = 0.0;
psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
psDefn->ProjParm[4] = 0.9996;
psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
psDefn->ProjParm[5] = 500000.0;
psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
if( psDefn->MapSys == MapSys_UTM_North )
psDefn->ProjParm[6] = 0.0;
else
psDefn->ProjParm[6] = 10000000.0;
}
if ( pszProjection )
CPLFree( pszProjection );
pszProjection = GetOGISDefn( psDefn );
}
/************************************************************************/
/* GTIFToCPLRecyleString() */
/* */
/* This changes a string from the libgeotiff heap to the GDAL */
/* heap. */
/************************************************************************/
static void GTIFToCPLRecycleString( char **ppszTarget )
{
if( *ppszTarget == NULL )
return;
char *pszTempString = CPLStrdup(*ppszTarget);
GTIFFreeMemory( *ppszTarget );
*ppszTarget = pszTempString;
}
/************************************************************************/
/* GetOGISDefn() */
/* Copied from the gt_wkt_srs.cpp. */
/************************************************************************/
char *MrSIDDataset::GetOGISDefn( GTIFDefn *psDefn )
{
OGRSpatialReference oSRS;
if( psDefn->Model != ModelTypeProjected
&& psDefn->Model != ModelTypeGeographic )
return CPLStrdup("");
/* -------------------------------------------------------------------- */
/* If this is a projected SRS we set the PROJCS keyword first */
/* to ensure that the GEOGCS will be a child. */
/* -------------------------------------------------------------------- */
if( psDefn->Model == ModelTypeProjected )
{
char *pszPCSName;
int bPCSNameSet = FALSE;
if( psDefn->PCS != KvUserDefined )
{
if( GTIFGetPCSInfo( psDefn->PCS, &pszPCSName, NULL, NULL, NULL ) )
bPCSNameSet = TRUE;
oSRS.SetNode( "PROJCS", bPCSNameSet ? pszPCSName : "unnamed" );
if( bPCSNameSet )
GTIFFreeMemory( pszPCSName );
oSRS.SetAuthority( "PROJCS", "EPSG", psDefn->PCS );
}
else
{
char szPCSName[200];
strcpy( szPCSName, "unnamed" );
if ( GetMetadataElement( "GEOTIFF_NUM::1026::GTCitationGeoKey",
szPCSName, sizeof(szPCSName) ) )
oSRS.SetNode( "PROJCS", szPCSName );
}
}
/* ==================================================================== */
/* Setup the GeogCS */
/* ==================================================================== */
char *pszGeogName = NULL;
char *pszDatumName = NULL;
char *pszPMName = NULL;
char *pszSpheroidName = NULL;
char *pszAngularUnits = NULL;
double dfInvFlattening, dfSemiMajor;
char szGCSName[200];
if( GetMetadataElement( "GEOTIFF_NUM::2049::GeogCitationGeoKey",
szGCSName, sizeof(szGCSName) ) )
pszGeogName = CPLStrdup(szGCSName);
else
{
GTIFGetGCSInfo( psDefn->GCS, &pszGeogName, NULL, NULL, NULL );
GTIFToCPLRecycleString(&pszGeogName);
}
GTIFGetDatumInfo( psDefn->Datum, &pszDatumName, NULL );
GTIFToCPLRecycleString(&pszDatumName);
GTIFGetPMInfo( psDefn->PM, &pszPMName, NULL );
GTIFToCPLRecycleString(&pszPMName);
GTIFGetEllipsoidInfo( psDefn->Ellipsoid, &pszSpheroidName, NULL, NULL );
GTIFToCPLRecycleString(&pszSpheroidName);
GTIFGetUOMAngleInfo( psDefn->UOMAngle, &pszAngularUnits, NULL );
GTIFToCPLRecycleString(&pszAngularUnits);
if( pszAngularUnits == NULL )
pszAngularUnits = CPLStrdup("unknown");
if( pszDatumName != NULL )
WKTMassageDatum( &pszDatumName );
dfSemiMajor = psDefn->SemiMajor;
if( psDefn->SemiMajor == 0.0 )
{
pszSpheroidName = CPLStrdup("unretrievable - using WGS84");
dfSemiMajor = SRS_WGS84_SEMIMAJOR;
dfInvFlattening = SRS_WGS84_INVFLATTENING;
}
else
dfInvFlattening = OSRCalcInvFlattening(psDefn->SemiMajor,psDefn->SemiMinor);
oSRS.SetGeogCS( pszGeogName, pszDatumName,
pszSpheroidName, dfSemiMajor, dfInvFlattening,
pszPMName,
psDefn->PMLongToGreenwich / psDefn->UOMAngleInDegrees,
pszAngularUnits,
psDefn->UOMAngleInDegrees * 0.0174532925199433 );
if( psDefn->GCS != KvUserDefined )
oSRS.SetAuthority( "GEOGCS", "EPSG", psDefn->GCS );
if( psDefn->Datum != KvUserDefined )
oSRS.SetAuthority( "DATUM", "EPSG", psDefn->Datum );
if( psDefn->Ellipsoid != KvUserDefined )
oSRS.SetAuthority( "SPHEROID", "EPSG", psDefn->Ellipsoid );
CPLFree( pszGeogName );
CPLFree( pszDatumName );
CPLFree( pszPMName );
CPLFree( pszSpheroidName );
CPLFree( pszAngularUnits );
/* ==================================================================== */
/* Handle projection parameters. */
/* ==================================================================== */
if( psDefn->Model == ModelTypeProjected )
{
/* -------------------------------------------------------------------- */
/* Make a local copy of parms, and convert back into the */
/* angular units of the GEOGCS and the linear units of the */
/* projection. */
/* -------------------------------------------------------------------- */
double adfParm[10];
int i;
for( i = 0; i < MIN(10,psDefn->nParms); i++ )
adfParm[i] = psDefn->ProjParm[i];
adfParm[0] /= psDefn->UOMAngleInDegrees;
adfParm[1] /= psDefn->UOMAngleInDegrees;
adfParm[2] /= psDefn->UOMAngleInDegrees;
adfParm[3] /= psDefn->UOMAngleInDegrees;
adfParm[5] /= psDefn->UOMLengthInMeters;
adfParm[6] /= psDefn->UOMLengthInMeters;
/* -------------------------------------------------------------------- */
/* Translation the fundamental projection. */
/* -------------------------------------------------------------------- */
switch( psDefn->CTProjection )
{
case CT_TransverseMercator:
oSRS.SetTM( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_TransvMercator_SouthOriented:
oSRS.SetTMSO( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_Mercator:
oSRS.SetMercator( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_ObliqueStereographic:
oSRS.SetOS( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_Stereographic:
oSRS.SetOS( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_ObliqueMercator: /* hotine */
oSRS.SetHOM( adfParm[0], adfParm[1],
adfParm[2], adfParm[3],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_EquidistantConic:
oSRS.SetEC( adfParm[0], adfParm[1],
adfParm[2], adfParm[3],
adfParm[5], adfParm[6] );
break;
case CT_CassiniSoldner:
oSRS.SetCS( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Polyconic:
oSRS.SetPolyconic( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_AzimuthalEquidistant:
oSRS.SetAE( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_MillerCylindrical:
oSRS.SetMC( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Equirectangular:
oSRS.SetEquirectangular( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Gnomonic:
oSRS.SetGnomonic( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_LambertAzimEqualArea:
oSRS.SetLAEA( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Orthographic:
oSRS.SetOrthographic( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Robinson:
oSRS.SetRobinson( adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_Sinusoidal:
oSRS.SetSinusoidal( adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_VanDerGrinten:
oSRS.SetVDG( adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_PolarStereographic:
oSRS.SetPS( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_LambertConfConic_2SP:
oSRS.SetLCC( adfParm[2], adfParm[3],
adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
case CT_LambertConfConic_1SP:
oSRS.SetLCC1SP( adfParm[0], adfParm[1],
adfParm[4],
adfParm[5], adfParm[6] );
break;
case CT_AlbersEqualArea:
oSRS.SetACEA( adfParm[0], adfParm[1],
adfParm[2], adfParm[3],
adfParm[5], adfParm[6] );
break;
case CT_NewZealandMapGrid:
oSRS.SetNZMG( adfParm[0], adfParm[1],
adfParm[5], adfParm[6] );
break;
}
/* -------------------------------------------------------------------- */
/* Set projection units. */
/* -------------------------------------------------------------------- */
char *pszUnitsName = NULL;
GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszUnitsName, NULL );
if( pszUnitsName != NULL && psDefn->UOMLength != KvUserDefined )
{
oSRS.SetLinearUnits( pszUnitsName, psDefn->UOMLengthInMeters );
oSRS.SetAuthority( "PROJCS|UNIT", "EPSG", psDefn->UOMLength );
}
else
oSRS.SetLinearUnits( "unknown", psDefn->UOMLengthInMeters );
GTIFFreeMemory( pszUnitsName );
}
/* -------------------------------------------------------------------- */
/* Return the WKT serialization of the object. */
/* -------------------------------------------------------------------- */
char *pszWKT;
oSRS.FixupOrdering();
if( oSRS.exportToWkt( &pszWKT ) == OGRERR_NONE )
return pszWKT;
else
return NULL;
}
#ifdef MRSID_ESDK
/************************************************************************/
/* ==================================================================== */
/* MrSIDDummyImageReader */
/* */
/* This is a helper class to wrap GDAL calls in MrSID interface. */
/* ==================================================================== */
/************************************************************************/
class MrSIDDummyImageReader : public LTIImageReader
{
public:
MrSIDDummyImageReader( GDALDataset *poSrcDS );
~MrSIDDummyImageReader();
LT_STATUS initialize();
lt_int64 getPhysicalFileSize(void) const { return 0; };
private:
GDALDataset *poDS;
GDALDataType eDataType;
LTIDataType eSampleType;
const LTIPixel *poPixel;
double adfGeoTransform[6];
virtual LT_STATUS decodeStrip( LTISceneBuffer& stripBuffer,
const LTIScene& stripScene );
virtual LT_STATUS decodeBegin( const LTIScene& )
{ return LT_STS_Success; };
virtual LT_STATUS decodeEnd() { return LT_STS_Success; };
};
/************************************************************************/
/* MrSIDDummyImageReader() */
/************************************************************************/
MrSIDDummyImageReader::MrSIDDummyImageReader( GDALDataset *poSrcDS ) :
LTIImageReader(), poDS(poSrcDS)
{
poPixel = NULL;
}
/************************************************************************/
/* ~MrSIDDummyImageReader() */
/************************************************************************/
MrSIDDummyImageReader::~MrSIDDummyImageReader()
{
if ( poPixel )
delete poPixel;
}
/************************************************************************/
/* initialize() */
/************************************************************************/
LT_STATUS MrSIDDummyImageReader::initialize()
{
LT_STATUS eStat = LT_STS_Uninit;
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
if ( !LT_SUCCESS(eStat = LTIImageReader::init()) )
return eStat;
#else
if ( !LT_SUCCESS(eStat = LTIImageReader::initialize()) )
return eStat;
#endif
lt_uint16 nBands = (lt_uint16)poDS->GetRasterCount();
LTIColorSpace eColorSpace = LTI_COLORSPACE_RGB;
switch ( nBands )
{
case 1:
eColorSpace = LTI_COLORSPACE_GRAYSCALE;
break;
case 3:
eColorSpace = LTI_COLORSPACE_RGB;
break;
default:
eColorSpace = LTI_COLORSPACE_MULTISPECTRAL;
break;
}
eDataType = poDS->GetRasterBand(1)->GetRasterDataType();
switch ( eDataType )
{
case GDT_UInt16:
eSampleType = LTI_DATATYPE_UINT16;
break;
case GDT_Int16:
eSampleType = LTI_DATATYPE_SINT16;
break;
case GDT_UInt32:
eSampleType = LTI_DATATYPE_UINT32;
break;
case GDT_Int32:
eSampleType = LTI_DATATYPE_SINT32;
break;
case GDT_Float32:
eSampleType = LTI_DATATYPE_FLOAT32;
break;
case GDT_Float64:
eSampleType = LTI_DATATYPE_FLOAT64;
break;
case GDT_Byte:
default:
eSampleType = LTI_DATATYPE_UINT8;
break;
}
poPixel = new LTIDLLPixel<LTIPixel>( eColorSpace, nBands, eSampleType );
if ( !LT_SUCCESS(setPixelProps(*poPixel)) )
return LT_STS_Failure;
if ( !LT_SUCCESS(setDimensions(poDS->GetRasterXSize(),
poDS->GetRasterYSize())) )
return LT_STS_Failure;
if ( poDS->GetGeoTransform( adfGeoTransform ) == CE_None )
{
#ifdef MRSID_SDK_40
LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
adfGeoTransform[3] + adfGeoTransform[5] / 2,
adfGeoTransform[1], adfGeoTransform[5],
adfGeoTransform[2], adfGeoTransform[4], NULL,
poDS->GetProjectionRef() );
#else
LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
adfGeoTransform[3] + adfGeoTransform[5] / 2,
adfGeoTransform[1], adfGeoTransform[5],
adfGeoTransform[2], adfGeoTransform[4],
poDS->GetProjectionRef() );
#endif
if ( !LT_SUCCESS(setGeoCoord( oGeo )) )
return LT_STS_Failure;
}
/*int bSuccess;
double dfNoDataValue = poDS->GetNoDataValue( &bSuccess );
if ( bSuccess )
{
LTIPixel oNoDataPixel( *poPixel );
lt_uint16 iBand;
for (iBand = 0; iBand < (lt_uint16)poDS->GetRasterCount(); iBand++)
oNoDataPixel.setSampleValueFloat32( iBand, dfNoDataValue );
if ( !LT_SUCCESS(setNoDataPixel( &oNoDataPixel )) )
return LT_STS_Failure;
}*/
setDefaultDynamicRange();
#if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
setClassicalMetadata();
#endif
return LT_STS_Success;
}
/************************************************************************/
/* decodeStrip() */
/************************************************************************/
LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer& stripData,
const LTIScene& stripScene)
{
const lt_int32 nXOff = stripScene.getUpperLeftCol();
const lt_int32 nYOff = stripScene.getUpperLeftRow();
const lt_int32 nBufXSize = stripScene.getNumCols();
const lt_int32 nBufYSize = stripScene.getNumRows();
const lt_int32 nDataBufXSize = stripData.getTotalNumCols();
const lt_int32 nDataBufYSize = stripData.getTotalNumRows();
const lt_uint16 nBands = poPixel->getNumBands();
void *pData = CPLMalloc(nDataBufXSize * nDataBufYSize * poPixel->getNumBytes());
if ( !pData )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDummyImageReader::decodeStrip(): "
"Cannot allocate enough space for scene buffer" );
return LT_STS_Failure;
}
poDS->RasterIO( GF_Read, nXOff, nYOff, nBufXSize, nBufYSize,
pData, nBufXSize, nBufYSize, eDataType, nBands, NULL,
0, 0, 0, NULL );
stripData.importDataBSQ( pData );
CPLFree( pData );
return LT_STS_Success;
}
/************************************************************************/
/* FlushCache() */
/************************************************************************/
void MrSIDDataset::FlushCache()
{
GDALDataset::FlushCache();
}
/************************************************************************/
/* MrSIDCreateCopy() */
/************************************************************************/
static GDALDataset *
MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress, void * pProgressData )
{
const char* pszVersion = CSLFetchNameValue(papszOptions, "VERSION");
#ifdef MRSID_HAVE_MG4WRITE
int iVersion = pszVersion ? atoi(pszVersion) : 4;
#else
int iVersion = pszVersion ? atoi(pszVersion) : 3;
#endif
LT_STATUS eStat = LT_STS_Uninit;
#ifdef DEBUG
bool bMeter = false;
#else
bool bMeter = true;
#endif
if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
{
CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
"MrSID driver ignores color table. "
"The source raster band will be considered as grey level.\n"
"Consider using color table expansion (-expand option in gdal_translate)\n");
if (bStrict)
return NULL;
}
MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDProgress.setProgressStatus failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
// Create the file.
MrSIDDummyImageReader oImageReader( poSrcDS );
if( LT_FAILURE( eStat = oImageReader.initialize() ) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDummyImageReader.Initialize failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
LTIGeoFileImageWriter *poImageWriter = NULL;
switch (iVersion)
{
case 2: {
// Output Mrsid Version 2 file.
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
LTIDLLDefault<MG2ImageWriter> *poMG2ImageWriter;
poMG2ImageWriter = new LTIDLLDefault<MG2ImageWriter>;
eStat = poMG2ImageWriter->initialize(&oImageReader);
#else
LTIDLLWriter<MG2ImageWriter> *poMG2ImageWriter;
poMG2ImageWriter = new LTIDLLWriter<MG2ImageWriter>(&oImageReader);
eStat = poMG2ImageWriter->initialize();
#endif
if( LT_FAILURE( eStat ) )
{
delete poMG2ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG2ImageWriter.initialize() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
eStat = poMG2ImageWriter->setEncodingApplication("MrSID Driver",
GDALVersionInfo("--version"));
if( LT_FAILURE( eStat ) )
{
delete poMG2ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG2ImageWriter.setEncodingApplication() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#endif
poMG2ImageWriter->setUsageMeterEnabled(bMeter);
poMG2ImageWriter->params().setBlockSize(poMG2ImageWriter->params().getBlockSize());
// check for compression option
const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
if( pszValue != NULL )
poMG2ImageWriter->params().setCompressionRatio( (float)CPLAtof(pszValue) );
poImageWriter = poMG2ImageWriter;
break; }
case 3: {
// Output Mrsid Version 3 file.
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
LTIDLLDefault<MG3ImageWriter> *poMG3ImageWriter;
poMG3ImageWriter = new LTIDLLDefault<MG3ImageWriter>;
eStat = poMG3ImageWriter->initialize(&oImageReader);
#else
LTIDLLWriter<MG3ImageWriter> *poMG3ImageWriter;
poMG3ImageWriter = new LTIDLLWriter<MG3ImageWriter>(&oImageReader);
eStat = poMG3ImageWriter->initialize();
#endif
if( LT_FAILURE( eStat ) )
{
delete poMG3ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG3ImageWriter.initialize() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
eStat = poMG3ImageWriter->setEncodingApplication("MrSID Driver",
GDALVersionInfo("--version"));
if( LT_FAILURE( eStat ) )
{
delete poMG3ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG3ImageWriter.setEncodingApplication() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#endif
// usage meter should only be disabled for debugging
poMG3ImageWriter->setUsageMeterEnabled(bMeter);
#if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
// Set 64-bit Interface for large files.
poMG3ImageWriter->setFileStream64(true);
#endif
// set 2 pass optimizer option
if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
poMG3ImageWriter->params().setTwoPassOptimizer( true );
// set filesize in KB
const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
if( pszValue != NULL )
poMG3ImageWriter->params().setTargetFilesize( atoi(pszValue) );
poImageWriter = poMG3ImageWriter;
break; }
#ifdef MRSID_HAVE_MG4WRITE
case 4: {
// Output Mrsid Version 4 file.
LTIDLLDefault<MG4ImageWriter> *poMG4ImageWriter;
poMG4ImageWriter = new LTIDLLDefault<MG4ImageWriter>;
eStat = poMG4ImageWriter->initialize(&oImageReader, NULL, NULL);
if( LT_FAILURE( eStat ) )
{
delete poMG4ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG3ImageWriter.initialize() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
eStat = poMG4ImageWriter->setEncodingApplication("MrSID Driver",
GDALVersionInfo("--version"));
if( LT_FAILURE( eStat ) )
{
delete poMG4ImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG3ImageWriter.setEncodingApplication() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
// usage meter should only be disabled for debugging
poMG4ImageWriter->setUsageMeterEnabled(bMeter);
// set 2 pass optimizer option
if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
poMG4ImageWriter->params().setTwoPassOptimizer( true );
// set filesize in KB
const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
if( pszValue != NULL )
poMG4ImageWriter->params().setTargetFilesize( atoi(pszValue) );
poImageWriter = poMG4ImageWriter;
break; }
#endif /* MRSID_HAVE_MG4WRITE */
default:
CPLError( CE_Failure, CPLE_AppDefined,
"Invalid MrSID generation specified (VERSION=%s).",
pszVersion );
return NULL;
}
// set output filename
poImageWriter->setOutputFileSpec( pszFilename );
// set progress delegate
poImageWriter->setProgressDelegate(&oProgressDelegate);
// set defaults
poImageWriter->setStripHeight(poImageWriter->getStripHeight());
// set MrSID world file
if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
poImageWriter->setWorldFileSupport( true );
// write the scene
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
if( LT_FAILURE( eStat = poImageWriter->write( oScene ) ) )
{
delete poImageWriter;
CPLError( CE_Failure, CPLE_AppDefined,
"MG2ImageWriter.write() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
delete poImageWriter;
/* -------------------------------------------------------------------- */
/* Re-open dataset, and copy any auxiliary pam information. */
/* -------------------------------------------------------------------- */
GDALPamDataset *poDS = (GDALPamDataset *)
GDALOpen( pszFilename, GA_ReadOnly );
if( poDS )
poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
return poDS;
}
#ifdef MRSID_J2K
/************************************************************************/
/* JP2CreateCopy() */
/************************************************************************/
static GDALDataset *
JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
int bStrict, char ** papszOptions,
GDALProgressFunc pfnProgress, void * pProgressData )
{
#ifdef DEBUG
bool bMeter = false;
#else
bool bMeter = true;
#endif
int nXSize = poSrcDS->GetRasterXSize();
int nYSize = poSrcDS->GetRasterYSize();
LT_STATUS eStat;
if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
{
CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
"MrSID driver ignores color table. "
"The source raster band will be considered as grey level.\n"
"Consider using color table expansion (-expand option in gdal_translate)\n");
if (bStrict)
return NULL;
}
MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDProgress.setProgressStatus failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
// Create the file.
MrSIDDummyImageReader oImageReader( poSrcDS );
eStat = oImageReader.initialize();
if( eStat != LT_STS_Success )
{
CPLError( CE_Failure, CPLE_AppDefined,
"MrSIDDummyImageReader.Initialize failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#if !defined(MRSID_POST5)
J2KImageWriter oImageWriter(&oImageReader);
eStat = oImageWriter.initialize();
#elif !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
JP2WriterManager oImageWriter(&oImageReader);
eStat = oImageWriter.initialize();
#else
JP2WriterManager oImageWriter;
eStat = oImageWriter.initialize(&oImageReader);
#endif
if( eStat != LT_STS_Success )
{
CPLError( CE_Failure, CPLE_AppDefined,
"J2KImageWriter.Initialize failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
#if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
// Set 64-bit Interface for large files.
oImageWriter.setFileStream64(true);
#endif
oImageWriter.setUsageMeterEnabled(bMeter);
// set output filename
oImageWriter.setOutputFileSpec( pszFilename );
// set progress delegate
oImageWriter.setProgressDelegate(&oProgressDelegate);
// Set defaults
//oImageWriter.setStripHeight(oImageWriter.getStripHeight());
// set MrSID world file
if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
oImageWriter.setWorldFileSupport( true );
// check for compression option
const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
if( pszValue != NULL )
oImageWriter.params().setCompressionRatio( (float)CPLAtof(pszValue) );
pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
if( pszValue != NULL )
{
LTFileSpec xmlprofile(pszValue);
eStat = oImageWriter.params().readProfile(xmlprofile);
if( eStat != LT_STS_Success )
{
CPLError( CE_Failure, CPLE_AppDefined,
"JPCWriterParams.readProfile failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
}
// write the scene
const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
eStat = oImageWriter.write( oScene );
if( eStat != LT_STS_Success )
{
CPLError( CE_Failure, CPLE_AppDefined,
"J2KImageWriter.write() failed.\n%s",
getLastStatusString( eStat ) );
return NULL;
}
/* -------------------------------------------------------------------- */
/* Re-open dataset, and copy any auxiliary pam information. */
/* -------------------------------------------------------------------- */
GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
GDALPamDataset *poDS = (GDALPamDataset*) JP2Open(&oOpenInfo);
if( poDS )
poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
return poDS;
}
#endif /* MRSID_J2K */
#endif /* MRSID_ESDK */
/************************************************************************/
/* GDALRegister_MrSID() */
/************************************************************************/
void GDALRegister_MrSID()
{
GDALDriver *poDriver;
if (! GDAL_CHECK_VERSION("MrSID driver"))
return;
/* -------------------------------------------------------------------- */
/* MrSID driver. */
/* -------------------------------------------------------------------- */
if( GDALGetDriverByName( "MrSID" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "MrSID" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"Multi-resolution Seamless Image Database (MrSID)" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_mrsid.html" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sid" );
#ifdef MRSID_ESDK
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
"Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
"<CreationOptionList>"
// Version 2 Options
" <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
// Version 3 Options
" <Option name='TWOPASS' type='int' description='Use twopass optimizer algorithm'/>"
" <Option name='FILESIZE' type='int' description='Set target file size (0 implies lossless compression)'/>"
// Version 2 and 3 Option
" <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
// Version Type
" <Option name='VERSION' type='int' description='Valid versions are 2 and 3, default = 3'/>"
"</CreationOptionList>" );
poDriver->pfnCreateCopy = MrSIDCreateCopy;
#else
/* In read-only mode, we support VirtualIO. I don't think this is the case */
/* for MrSIDCreateCopy() */
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
#endif
poDriver->pfnIdentify = MrSIDIdentify;
poDriver->pfnOpen = MrSIDOpen;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
/* -------------------------------------------------------------------- */
/* JP2MRSID driver. */
/* -------------------------------------------------------------------- */
#ifdef MRSID_J2K
if( GDALGetDriverByName( "JP2MrSID" ) == NULL )
{
poDriver = new GDALDriver();
poDriver->SetDescription( "JP2MrSID" );
poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
"MrSID JPEG2000" );
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_jp2mrsid.html" );
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
#ifdef MRSID_ESDK
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
"Byte Int16 UInt16" );
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
"<CreationOptionList>"
" <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
" <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
" <Option name='XMLPROFILE' type='string' description='Use named xml profile file'/>"
"</CreationOptionList>" );
poDriver->pfnCreateCopy = JP2CreateCopy;
#else
/* In read-only mode, we support VirtualIO. I don't think this is the case */
/* for JP2CreateCopy() */
poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
#endif
poDriver->pfnIdentify = JP2Identify;
poDriver->pfnOpen = JP2Open;
GetGDALDriverManager()->RegisterDriver( poDriver );
}
#endif /* def MRSID_J2K */
}
#if defined(MRSID_USE_TIFFSYMS_WORKAROUND)
extern "C" {
/* This is not pretty but I am not sure how else to get the plugin to build
* against the ESDK. ESDK symbol dependencies bring in __TIFFmemcpy and
* __gtiff_size, which are not exported from gdal.dll. Rather than link these
* symbols from the ESDK distribution of GDAL, or link in the entire gdal.lib
* statically, it seemed safer and smaller to bring in just the objects that
* wouldsatisfy these symbols from the enclosing GDAL build. However, doing
* so pulls in a few more dependencies. /Gy and /OPT:REF did not seem to help
* things, so I have implemented no-op versions of these symbols since they
* do not actually get called. If the MrSID ESDK ever comes to require the
* actual versions of these functions, we'll hope duplicate symbol errors will
* bring attention back to this problem.
*/
void TIFFClientOpen() {}
void TIFFError() {}
void TIFFGetField() {}
void TIFFSetField() {}
}
#endif