1
/******************************************************************************
2
* $Id: ecwdataset.cpp 17906 2009-10-26 19:47:21Z rouault $
5
* Purpose: ECW (ERMapper Wavelet Compression Format) Driver
6
* Author: Frank Warmerdam, warmerdam@pobox.com
8
******************************************************************************
9
* Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
11
* Permission is hereby granted, free of charge, to any person obtaining a
12
* copy of this software and associated documentation files (the "Software"),
13
* to deal in the Software without restriction, including without limitation
14
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
15
* and/or sell copies of the Software, and to permit persons to whom the
16
* Software is furnished to do so, subject to the following conditions:
18
* The above copyright notice and this permission notice shall be included
19
* in all copies or substantial portions of the Software.
21
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
* DEALINGS IN THE SOFTWARE.
28
****************************************************************************/
31
#include "gdaljp2metadata.h"
32
#include "ogr_spatialref.h"
33
#include "cpl_string.h"
35
#include "vsiiostream.h"
36
#include "cpl_multiproc.h"
37
#include "cpl_minixml.h"
39
#include "ogr_geometry.h"
41
CPL_CVSID("$Id: ecwdataset.cpp 17906 2009-10-26 19:47:21Z rouault $");
45
static const unsigned char jpc_header[] = {0xff,0x4f};
46
static const unsigned char jp2_header[] =
47
{0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
49
static void *hECWDatasetMutex = NULL;
50
static int bNCSInitialized = FALSE;
53
CPLErr CPL_DLL GTIFMemBufFromWkt( const char *pszWKT,
54
const double *padfGeoTransform,
55
int nGCPCount, const GDAL_GCP *pasGCPList,
56
int *pnSize, unsigned char **ppabyBuffer );
57
CPLErr CPL_DLL GTIFWktFromMemBuf( int nSize, unsigned char *pabyBuffer,
58
char **ppszWKT, double *padfGeoTransform,
59
int *pnGCPCount, GDAL_GCP **ppasGCPList );
62
void ECWInitialize( void );
64
GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
66
/************************************************************************/
67
/* ==================================================================== */
69
/* ==================================================================== */
70
/************************************************************************/
74
class CPL_DLL ECWDataset : public GDALPamDataset
76
friend class ECWRasterBand;
78
CNCSJP2FileView *poFileView;
79
NCSFileViewFileInfoEx *psFileInfo;
81
GDALDataType eRasterDataType;
82
NCSEcwCellType eNCSRequestDataType;
84
int bUsingCustomStream;
86
// Current view window.
88
int nWinXOff, nWinYOff, nWinXSize, nWinYSize;
89
int nWinBufXSize, nWinBufYSize;
95
int bGeoTransformValid;
96
double adfGeoTransform[6];
101
char **papszGMLMetadata;
103
void ECW2WKTProjection();
105
void CleanupWindow();
106
int TryWinRasterIO( GDALRWFlag, int, int, int, int,
107
GByte *, int, int, GDALDataType,
108
int, int *, int, int, int );
109
CPLErr LoadNextLine();
112
ECWDataset(int bIsJPEG2000);
115
static GDALDataset *Open( GDALOpenInfo *, int bIsJPEG2000 );
116
static int IdentifyJPEG2000( GDALOpenInfo * poOpenInfo );
117
static GDALDataset *OpenJPEG2000( GDALOpenInfo * );
118
static int IdentifyECW( GDALOpenInfo * poOpenInfo );
119
static GDALDataset *OpenECW( GDALOpenInfo * );
121
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
122
void *, int, int, GDALDataType,
123
int, int *, int, int, int );
125
virtual CPLErr GetGeoTransform( double * );
126
virtual const char *GetProjectionRef();
128
virtual int GetGCPCount();
129
virtual const char *GetGCPProjection();
130
virtual const GDAL_GCP *GetGCPs();
132
virtual char **GetMetadata( const char * pszDomain = "" );
134
virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
135
int nBufXSize, int nBufYSize,
137
int nBandCount, int *panBandList,
138
char **papszOptions );
141
/************************************************************************/
142
/* ==================================================================== */
144
/* ==================================================================== */
145
/************************************************************************/
147
class ECWRasterBand : public GDALPamRasterBand
149
friend class ECWDataset;
151
// NOTE: poDS may be altered for NITF/JPEG2000 files!
154
GDALColorInterp eBandInterp;
156
virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
157
void *, int, int, GDALDataType,
162
ECWRasterBand( ECWDataset *, int );
165
virtual CPLErr IReadBlock( int, int, void * );
166
virtual int HasArbitraryOverviews() { return TRUE; }
167
virtual GDALColorInterp GetColorInterpretation();
168
virtual CPLErr SetColorInterpretation( GDALColorInterp );
170
virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
171
int nBufXSize, int nBufYSize,
172
GDALDataType eDT, char **papszOptions );
175
/************************************************************************/
176
/* ECWRasterBand() */
177
/************************************************************************/
179
ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand )
186
eDataType = poDS->eRasterDataType;
187
nBlockXSize = poDS->GetRasterXSize();
190
/* -------------------------------------------------------------------- */
191
/* Work out band color interpretation. */
192
/* -------------------------------------------------------------------- */
193
if( poDS->psFileInfo->eColorSpace == NCSCS_NONE )
194
eBandInterp = GCI_Undefined;
195
else if( poDS->psFileInfo->eColorSpace == NCSCS_GREYSCALE )
196
eBandInterp = GCI_GrayIndex;
197
else if( poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND )
198
eBandInterp = GCI_Undefined;
199
else if( poDS->psFileInfo->eColorSpace == NCSCS_sRGB )
202
eBandInterp = GCI_RedBand;
203
else if( nBand == 2 )
204
eBandInterp = GCI_GreenBand;
205
else if( nBand == 3 )
206
eBandInterp = GCI_BlueBand;
208
eBandInterp = GCI_Undefined;
210
else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
212
if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
215
eBandInterp = GCI_RedBand;
216
else if( nBand == 2 )
217
eBandInterp = GCI_GreenBand;
218
else if( nBand == 3 )
219
eBandInterp = GCI_BlueBand;
221
eBandInterp = GCI_Undefined;
226
eBandInterp = GCI_YCbCr_YBand;
227
else if( nBand == 2 )
228
eBandInterp = GCI_YCbCr_CbBand;
229
else if( nBand == 3 )
230
eBandInterp = GCI_YCbCr_CrBand;
232
eBandInterp = GCI_Undefined;
236
eBandInterp = GCI_Undefined;
239
/************************************************************************/
240
/* ~ECWRasterBand() */
241
/************************************************************************/
243
ECWRasterBand::~ECWRasterBand()
249
/************************************************************************/
250
/* GetColorInterpretation() */
251
/************************************************************************/
253
GDALColorInterp ECWRasterBand::GetColorInterpretation()
259
/************************************************************************/
260
/* SetColorInterpretation() */
262
/* This would normally just be used by folks using the ECW code */
263
/* to read JP2 streams in other formats (such as NITF) and */
264
/* providing their own color interpretation regardless of what */
265
/* ECW might think the stream itself says. */
266
/************************************************************************/
268
CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
271
eBandInterp = eNewInterp;
276
/************************************************************************/
278
/************************************************************************/
280
CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
281
int nBufXSize, int nBufYSize,
283
char **papszOptions )
285
return poGDS->AdviseRead( nXOff, nYOff, nXSize, nYSize,
286
nBufXSize, nBufYSize, eDT,
287
1, &nBand, papszOptions );
290
/************************************************************************/
292
/************************************************************************/
294
CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
295
int nXOff, int nYOff, int nXSize, int nYSize,
296
void * pData, int nBufXSize, int nBufYSize,
297
GDALDataType eBufType,
298
int nPixelSpace, int nLineSpace )
302
int nNewXSize = nBufXSize, nNewYSize = nBufYSize;
303
GByte *pabyWorkBuffer = NULL;
305
/* -------------------------------------------------------------------- */
306
/* Try to do it based on existing "advised" access. */
307
/* -------------------------------------------------------------------- */
308
if( poGDS->TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
309
(GByte *) pData, nBufXSize, nBufYSize,
311
nPixelSpace, nLineSpace, 0 ) )
314
/* -------------------------------------------------------------------- */
315
/* We will drop down to the block oriented API if only a single */
316
/* scanline was requested. This is based on the assumption that */
317
/* doing lots of single scanline windows is expensive. */
318
/* -------------------------------------------------------------------- */
322
CPLDebug( "ECWRasterBand",
323
"RasterIO(%d,%d,%d,%d -> %dx%d) - redirected.",
324
nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
326
return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
327
pData, nBufXSize, nBufYSize,
328
eBufType, nPixelSpace, nLineSpace );
331
CPLDebug( "ECWRasterBand",
332
"RasterIO(nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)",
333
nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
336
if ( nXSize < nBufXSize )
339
if ( nYSize < nBufYSize )
342
/* -------------------------------------------------------------------- */
343
/* Default line and pixel spacing if needed. */
344
/* -------------------------------------------------------------------- */
345
if ( nPixelSpace == 0 )
346
nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
348
if ( nLineSpace == 0 )
349
nLineSpace = nPixelSpace * nBufXSize;
351
/* -------------------------------------------------------------------- */
352
/* Can we perform direct loads, or must we load into a working */
353
/* buffer, and transform? */
354
/* -------------------------------------------------------------------- */
355
int nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
357
bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
358
&& nNewXSize == nBufXSize && nNewYSize == nBufYSize;
360
pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
362
/* -------------------------------------------------------------------- */
363
/* Establish access at the desired resolution. */
364
/* -------------------------------------------------------------------- */
367
poGDS->CleanupWindow();
370
oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
374
nNewXSize, nNewYSize );
375
if( oErr.GetErrorNumber() != NCS_SUCCESS )
377
CPLFree( pabyWorkBuffer );
378
char* pszErrorMessage = oErr.GetErrorMessage();
379
CPLError( CE_Failure, CPLE_AppDefined,
380
"%s", pszErrorMessage );
381
NCSFree(pszErrorMessage);
386
/* -------------------------------------------------------------------- */
387
/* Read back one scanline at a time, till request is satisfied. */
388
/* Supersampling is not supported by the ECW API, so we will do */
390
/* -------------------------------------------------------------------- */
391
double dfSrcYInc = (double)nNewYSize / nBufYSize;
392
double dfSrcXInc = (double)nNewXSize / nBufXSize;
393
int iSrcLine, iDstLine;
395
for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
397
NCSEcwReadStatus eRStatus;
398
int iDstLineOff = iDstLine * nLineSpace;
399
unsigned char *pabySrcBuf;
402
pabySrcBuf = ((GByte *)pData) + iDstLineOff;
404
pabySrcBuf = pabyWorkBuffer;
406
if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
408
eRStatus = poGDS->poFileView->ReadLineBIL(
409
poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
411
if( eRStatus != NCSECW_READ_OK )
413
CPLFree( pabyWorkBuffer );
414
CPLError( CE_Failure, CPLE_AppDefined,
415
"NCScbmReadViewLineBIL failed." );
421
if ( nNewXSize == nBufXSize )
423
GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType,
425
((GByte *)pData) + iDstLine * nLineSpace,
426
eBufType, nPixelSpace, nBufXSize );
432
for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
434
GDALCopyWords( pabyWorkBuffer
435
+ nRawPixelSize*((int)(iPixel*dfSrcXInc)),
436
poGDS->eRasterDataType, nRawPixelSize,
437
(GByte *)pData + iDstLineOff
438
+ iPixel * nPixelSpace,
439
eBufType, nPixelSpace, 1 );
448
// Just copy the previous line in this case
449
GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
450
eBufType, nPixelSpace,
451
(GByte *)pData + iDstLineOff,
452
eBufType, nPixelSpace, nBufXSize );
456
CPLFree( pabyWorkBuffer );
461
/************************************************************************/
463
/************************************************************************/
465
CPLErr ECWRasterBand::IReadBlock( int, int nBlockYOff, void * pImage )
468
CPLErr eErr = CE_None;
470
if( poGDS->TryWinRasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1,
471
(GByte *) pImage, nBlockXSize, 1,
472
eDataType, 1, &nBand, 0, 0, 0 ) )
475
eErr = AdviseRead( 0, nBlockYOff, nRasterXSize, nRasterYSize - nBlockYOff,
476
nRasterXSize, nRasterYSize - nBlockYOff,
478
if( eErr != CE_None )
481
if( poGDS->TryWinRasterIO( GF_Read, 0, nBlockYOff, nBlockXSize, 1,
482
(GByte *) pImage, nBlockXSize, 1,
483
eDataType, 1, &nBand, 0, 0, 0 ) )
486
CPLError( CE_Failure, CPLE_AppDefined,
487
"TryWinRasterIO() failed for blocked scanline %d of band %d.",
492
/************************************************************************/
493
/* ==================================================================== */
495
/* ==================================================================== */
496
/************************************************************************/
499
/************************************************************************/
501
/************************************************************************/
503
ECWDataset::ECWDataset(int bIsJPEG2000)
506
bUsingCustomStream = FALSE;
507
pszProjection = NULL;
510
panWinBandList = NULL;
511
eRasterDataType = GDT_Byte;
514
papszGMLMetadata = NULL;
516
bGeoTransformValid = FALSE;
517
adfGeoTransform[0] = 0.0;
518
adfGeoTransform[1] = 1.0;
519
adfGeoTransform[2] = 0.0;
520
adfGeoTransform[3] = 0.0;
521
adfGeoTransform[4] = 0.0;
522
adfGeoTransform[5] = 1.0;
524
poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
527
/************************************************************************/
529
/************************************************************************/
531
ECWDataset::~ECWDataset()
536
CPLFree( pszProjection );
537
CSLDestroy( papszGMLMetadata );
541
GDALDeinitGCPs( nGCPCount, pasGCPList );
542
CPLFree( pasGCPList );
545
/* -------------------------------------------------------------------- */
546
/* Release / dereference iostream. */
547
/* -------------------------------------------------------------------- */
548
// The underlying iostream of the CNCSJP2FileView (poFileView) object may
549
// also be the underlying iostream of other CNCSJP2FileView (poFileView)
550
// objects. Consequently, when we delete the CNCSJP2FileView (poFileView)
551
// object, we must decrement the nFileViewCount attribute of the underlying
552
// VSIIOStream object, and only delete the VSIIOStream object when
553
// nFileViewCount is equal to zero.
555
CPLMutexHolder oHolder( &hECWDatasetMutex );
557
if( poFileView != NULL )
559
VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
561
poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
564
if( bUsingCustomStream )
566
if( --poUnderlyingIOStream->nFileViewCount == 0 )
567
delete poUnderlyingIOStream;
572
/************************************************************************/
574
/************************************************************************/
576
CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
577
int nBufXSize, int nBufYSize,
579
int nBandCount, int *panBandList,
580
char **papszOptions )
583
int *panAdjustedBandList = NULL;
586
"ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
587
nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
589
if( nBufXSize > nXSize || nBufYSize > nYSize )
591
CPLError( CE_Warning, CPLE_AppDefined,
592
"Supersampling not directly supported by ECW toolkit,\n"
593
"ignoring AdviseRead() request." );
597
/* -------------------------------------------------------------------- */
598
/* Adjust band numbers to be zero based. */
599
/* -------------------------------------------------------------------- */
600
panAdjustedBandList = (int *)
601
CPLMalloc(sizeof(int) * nBandCount );
602
for( int ii= 0; ii < nBandCount; ii++ )
603
panAdjustedBandList[ii] = panBandList[ii] - 1;
605
/* -------------------------------------------------------------------- */
606
/* Cleanup old window cache information. */
607
/* -------------------------------------------------------------------- */
610
/* -------------------------------------------------------------------- */
611
/* Set the new requested window. */
612
/* -------------------------------------------------------------------- */
615
oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList,
617
nXOff + nXSize-1, nYOff + nYSize-1,
618
nBufXSize, nBufYSize );
620
CPLFree( panAdjustedBandList );
621
if( oErr.GetErrorNumber() != NCS_SUCCESS )
623
char* pszErrorMessage = oErr.GetErrorMessage();
624
CPLError( CE_Failure, CPLE_AppDefined,
625
"%s", pszErrorMessage );
626
NCSFree(pszErrorMessage);
633
/* -------------------------------------------------------------------- */
634
/* Record selected window. */
635
/* -------------------------------------------------------------------- */
640
nWinBufXSize = nBufXSize;
641
nWinBufYSize = nBufYSize;
643
panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
644
memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
645
nWinBandCount = nBandCount;
649
/* -------------------------------------------------------------------- */
650
/* Allocate current scanline buffer. */
651
/* -------------------------------------------------------------------- */
652
papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
653
for( int iBand = 0; iBand < nWinBandCount; iBand++ )
654
papCurLineBuf[iBand] =
655
CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
660
/************************************************************************/
661
/* TryWinRasterIO() */
663
/* Try to satisfy the given request based on the currently */
664
/* defined window. Return TRUE on success or FALSE on */
665
/* failure. On failure, the caller should satisfy the request */
666
/* another way (not report an error). */
667
/************************************************************************/
669
int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag,
670
int nXOff, int nYOff, int nXSize, int nYSize,
671
GByte *pabyData, int nBufXSize, int nBufYSize,
673
int nBandCount, int *panBandList,
674
int nPixelSpace, int nLineSpace,
680
/* -------------------------------------------------------------------- */
681
/* Provide default buffer organization. */
682
/* -------------------------------------------------------------------- */
683
if( nPixelSpace == 0 )
684
nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
685
if( nLineSpace == 0 )
686
nLineSpace = nPixelSpace * nBufXSize;
687
if( nBandSpace == 0 )
688
nBandSpace = nLineSpace * nBufYSize;
690
/* -------------------------------------------------------------------- */
691
/* Do some simple tests to see if the current window can */
692
/* satisfy our requirement. */
693
/* -------------------------------------------------------------------- */
697
if( nXOff != nWinXOff || nXSize != nWinXSize )
700
if( nBufXSize != nWinBufXSize )
703
for( iBand = 0; iBand < nBandCount; iBand++ )
705
for( i = 0; i < nWinBandCount; i++ )
707
if( panWinBandList[iBand] == panBandList[iBand] )
711
if( i == nWinBandCount )
715
if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
718
/* -------------------------------------------------------------------- */
719
/* Now we try more subtle tests. */
720
/* -------------------------------------------------------------------- */
722
static int nDebugCount = 0;
724
if( nDebugCount < 30 )
725
CPLDebug( "ECWDataset",
726
"TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.",
727
nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
729
if( nDebugCount == 29 )
730
CPLDebug( "ECWDataset", "No more TryWinRasterIO messages will be reported" );
735
/* -------------------------------------------------------------------- */
736
/* Actually load data one buffer line at a time. */
737
/* -------------------------------------------------------------------- */
740
for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
742
float fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
744
(int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
746
if( iWinLine == nWinBufLoaded + 1 )
749
if( iWinLine != nWinBufLoaded )
752
/* -------------------------------------------------------------------- */
753
/* Copy out all our target bands. */
754
/* -------------------------------------------------------------------- */
756
for( iBand = 0; iBand < nBandCount; iBand++ )
758
for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
760
if( panWinBandList[iWinBand] == panBandList[iBand] )
764
GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
765
GDALGetDataTypeSize( eRasterDataType ) / 8,
766
pabyData + nBandSpace * iBand
767
+ iBufLine * nLineSpace, eDT, nPixelSpace,
775
/************************************************************************/
777
/************************************************************************/
779
CPLErr ECWDataset::LoadNextLine()
785
if( nWinBufLoaded == nWinBufYSize-1 )
791
NCSEcwReadStatus eRStatus;
792
eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, nWinBandCount,
794
if( eRStatus != NCSECW_READ_OK )
802
/************************************************************************/
803
/* CleanupWindow() */
804
/************************************************************************/
806
void ECWDataset::CleanupWindow()
813
CPLFree( panWinBandList );
814
panWinBandList = NULL;
816
for( int iBand = 0; iBand < nWinBandCount; iBand++ )
817
CPLFree( papCurLineBuf[iBand] );
818
CPLFree( papCurLineBuf );
819
papCurLineBuf = NULL;
822
/************************************************************************/
824
/************************************************************************/
826
CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
827
int nXOff, int nYOff, int nXSize, int nYSize,
828
void * pData, int nBufXSize, int nBufYSize,
829
GDALDataType eBufType,
830
int nBandCount, int *panBandMap,
831
int nPixelSpace, int nLineSpace, int nBandSpace)
834
/* -------------------------------------------------------------------- */
835
/* Try to do it based on existing "advised" access. */
836
/* -------------------------------------------------------------------- */
837
if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
838
(GByte *) pData, nBufXSize, nBufYSize,
839
eBufType, nBandCount, panBandMap,
840
nPixelSpace, nLineSpace, nBandSpace ) )
843
/* -------------------------------------------------------------------- */
844
/* If we are requesting a single line at 1:1, we do a multi-band */
845
/* AdviseRead() and then TryWinRasterIO() again. */
846
/* -------------------------------------------------------------------- */
847
if( nYSize == 1 && nBufYSize == 1 && nBandCount > 1 )
851
eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
852
nBufXSize, GetRasterYSize() - nYOff, eBufType,
853
nBandCount, panBandMap, NULL );
855
&& TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
856
(GByte *) pData, nBufXSize, nBufYSize,
857
eBufType, nBandCount, panBandMap,
858
nPixelSpace, nLineSpace, nBandSpace ) )
862
/* -------------------------------------------------------------------- */
863
/* If we are supersampling we need to fall into the general */
864
/* purpose logic. We also use the general logic if we are in */
865
/* some cases unlikely to benefit from interleaved access. */
867
/* The one case we would like to handle better here is the */
868
/* nBufYSize == 1 case (requesting a scanline at a time). We */
869
/* should eventually have some logic similiar to the band by */
870
/* band case where we post a big window for the view, and allow */
871
/* sequential reads. */
872
/* -------------------------------------------------------------------- */
873
if( nXSize < nBufXSize || nYSize < nBufYSize || nYSize == 1
874
|| nBandCount > 100 || nBandCount == 1 || nBufYSize == 1
875
|| nBandCount > GetRasterCount() )
878
GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
879
pData, nBufXSize, nBufYSize,
881
nBandCount, panBandMap,
882
nPixelSpace, nLineSpace, nBandSpace);
885
CPLDebug( "ECWDataset",
886
"RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.",
887
nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
889
/* -------------------------------------------------------------------- */
891
/* -------------------------------------------------------------------- */
892
UINT32 anBandIndices[100];
897
for( i = 0; i < nBandCount; i++ )
898
anBandIndices[i] = panBandMap[i] - 1;
902
oErr = poFileView->SetView( nBandCount, anBandIndices,
906
nBufXSize, nBufYSize );
907
eNCSErr = oErr.GetErrorNumber();
909
if( eNCSErr != NCS_SUCCESS )
911
CPLError( CE_Failure, CPLE_AppDefined,
912
"%s", NCSGetErrorText(eNCSErr) );
917
/* -------------------------------------------------------------------- */
918
/* Setup working scanline, and the pointers into it. */
919
/* -------------------------------------------------------------------- */
920
int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
921
GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
923
GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
925
for( i = 0; i < nBandCount; i++ )
926
papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
928
/* -------------------------------------------------------------------- */
929
/* Read back all the data for the requested view. */
930
/* -------------------------------------------------------------------- */
931
for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
933
NCSEcwReadStatus eRStatus;
935
eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType, nBandCount,
936
(void **) papabyBIL );
937
if( eRStatus != NCSECW_READ_OK )
939
CPLFree( papabyBIL );
940
CPLFree( pabyBILScanline );
941
CPLError( CE_Failure, CPLE_AppDefined,
942
"NCScbmReadViewLineBIL failed." );
946
for( i = 0; i < nBandCount; i++ )
949
pabyBILScanline + i * nDataTypeSize * nBufXSize,
950
eRasterDataType, nDataTypeSize,
951
((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i,
952
eBufType, nPixelSpace,
957
CPLFree( pabyBILScanline );
958
CPLFree( papabyBIL );
963
/************************************************************************/
964
/* IdentifyJPEG2000() */
966
/* Open method that only supports JPEG2000 files. */
967
/************************************************************************/
969
int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
972
if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
975
else if( poOpenInfo->nHeaderBytes >= 16
976
&& (memcmp( poOpenInfo->pabyHeader, jpc_header,
977
sizeof(jpc_header) ) == 0
978
|| memcmp( poOpenInfo->pabyHeader, jp2_header,
979
sizeof(jp2_header) ) == 0) )
986
/************************************************************************/
989
/* Open method that only supports JPEG2000 files. */
990
/************************************************************************/
992
GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
995
if (!IdentifyJPEG2000(poOpenInfo))
998
return Open( poOpenInfo, TRUE );
1001
/************************************************************************/
1004
/* Identify method that only supports ECW files. */
1005
/************************************************************************/
1007
int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
1010
/* -------------------------------------------------------------------- */
1011
/* This has to either be a file on disk ending in .ecw or a */
1012
/* ecwp: protocol url. */
1013
/* -------------------------------------------------------------------- */
1014
if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
1015
|| poOpenInfo->nHeaderBytes == 0)
1016
&& !EQUALN(poOpenInfo->pszFilename,"ecwp:",5) )
1022
/************************************************************************/
1025
/* Open method that only supports ECW files. */
1026
/************************************************************************/
1028
GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
1031
if (!IdentifyECW(poOpenInfo))
1034
return Open( poOpenInfo, FALSE );
1037
/************************************************************************/
1039
/************************************************************************/
1041
GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
1044
CNCSJP2FileView *poFileView = NULL;
1048
FILE *fpVSIL = NULL;
1049
VSIIOStream *poIOStream = NULL;
1050
int bUsingCustomStream = FALSE;
1054
/* -------------------------------------------------------------------- */
1055
/* This will disable automatic conversion of YCbCr to RGB by */
1057
/* -------------------------------------------------------------------- */
1058
if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
1059
NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
1061
/* -------------------------------------------------------------------- */
1062
/* Handle special case of a JPEG2000 data stream in another file. */
1063
/* -------------------------------------------------------------------- */
1064
int bIsVirtualFile = FALSE;
1066
if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) ||
1069
GIntBig subfile_offset=-1, subfile_size=-1;
1070
const char *real_filename = NULL;
1072
if (EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12))
1074
char** papszTokens = CSLTokenizeString2(poOpenInfo->pszFilename + 12, ",", 0);
1075
if (CSLCount(papszTokens) >= 2)
1077
subfile_offset = CPLScanUIntBig(papszTokens[0], strlen(papszTokens[0]));
1078
subfile_size = CPLScanUIntBig(papszTokens[1], strlen(papszTokens[1]));
1082
CPLError( CE_Failure, CPLE_OpenFailed,
1083
"Failed to parse J2K_SUBFILE specification." );
1084
CSLDestroy(papszTokens);
1087
CSLDestroy(papszTokens);
1089
real_filename = strstr(poOpenInfo->pszFilename,",");
1090
if( real_filename != NULL )
1091
real_filename = strstr(real_filename+1,",");
1092
if( real_filename != NULL )
1096
CPLError( CE_Failure, CPLE_OpenFailed,
1097
"Failed to parse J2K_SUBFILE specification." );
1104
real_filename = poOpenInfo->pszFilename;
1108
fpVSIL = VSIFOpenL( real_filename, "rb" );
1109
if( fpVSIL == NULL )
1111
CPLError( CE_Failure, CPLE_OpenFailed,
1112
"Failed to open %s.", real_filename );
1116
if( hECWDatasetMutex == NULL )
1118
hECWDatasetMutex = CPLCreateMutex();
1120
else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
1122
CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
1126
CPLDebug( "ECW", "Got mutex." );
1128
poIOStream = new VSIIOStream();
1129
poIOStream->Access( fpVSIL, FALSE, real_filename,
1130
subfile_offset, subfile_size );
1132
poFileView = new CNCSJP2FileView();
1133
oErr = poFileView->Open( poIOStream, false );
1135
// The CNCSJP2FileView (poFileView) object may not use the iostream
1136
// (poIOStream) passed to the CNCSJP2FileView::Open() method if an
1137
// iostream is already available to the ECW JPEG 2000 SDK for a given
1138
// file. Consequently, if the iostream passed to
1139
// CNCSJP2FileView::Open() does not become the underlying iostream
1140
// of the CNCSJP2FileView object, then it should be deleted.
1142
// In addition, the underlying iostream of the CNCSJP2FileView object
1143
// should not be deleted until all CNCSJP2FileView objects using the
1144
// underlying iostream are deleted. Consequently, each time a
1145
// CNCSJP2FileView object is created, the nFileViewCount attribute
1146
// of the underlying VSIIOStream object must be incremented for use
1147
// in the ECWDataset destructor.
1149
VSIIOStream * poUnderlyingIOStream =
1150
((VSIIOStream *)(poFileView->GetStream()));
1152
if ( poUnderlyingIOStream )
1153
poUnderlyingIOStream->nFileViewCount++;
1155
if ( poIOStream != poUnderlyingIOStream )
1161
bUsingCustomStream = TRUE;
1164
CPLReleaseMutex( hECWDatasetMutex );
1166
if( oErr.GetErrorNumber() != NCS_SUCCESS )
1171
char* pszErrorMessage = oErr.GetErrorMessage();
1172
CPLError( CE_Failure, CPLE_AppDefined,
1173
"%s", pszErrorMessage );
1174
NCSFree(pszErrorMessage);
1180
/* -------------------------------------------------------------------- */
1181
/* This has to either be a file on disk ending in .ecw or a */
1182
/* ecwp: protocol url. */
1183
/* -------------------------------------------------------------------- */
1184
else if( poOpenInfo->nHeaderBytes >= 16
1185
&& (memcmp( poOpenInfo->pabyHeader, jpc_header,
1186
sizeof(jpc_header) ) == 0
1187
|| memcmp( poOpenInfo->pabyHeader, jp2_header,
1188
sizeof(jp2_header) ) == 0) )
1190
/* accept JPEG2000 files */
1192
else if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
1193
|| poOpenInfo->nHeaderBytes == 0)
1194
&& !EQUALN(poOpenInfo->pszFilename,"ecwp:",5) )
1197
/* -------------------------------------------------------------------- */
1198
/* Open the client interface. */
1199
/* -------------------------------------------------------------------- */
1200
if( poFileView == NULL )
1202
poFileView = new CNCSFile();
1203
oErr = poFileView->Open( (char *) poOpenInfo->pszFilename, FALSE );
1204
eErr = oErr.GetErrorNumber();
1205
CPLDebug( "ECW", "NCScbmOpenFileView(%s): eErr = %d",
1206
poOpenInfo->pszFilename, (int) eErr );
1207
if( eErr != NCS_SUCCESS )
1211
/* If the file is not a 'real' file but recognized as a */
1212
/* virtual file by the VSIL API, try again by using a */
1213
/* VSIIOStream object, like in the J2K_SUBFILE case */
1216
if (!bIsVirtualFile &&
1217
VSIStat(poOpenInfo->pszFilename, &sBuf) != 0 &&
1218
VSIStatL(poOpenInfo->pszFilename, &sBufL) == 0)
1220
bIsVirtualFile = TRUE;
1224
CPLError( CE_Failure, CPLE_AppDefined,
1225
"%s", NCSGetErrorText(eErr) );
1230
if( poOpenInfo->eAccess == GA_Update )
1232
CPLError( CE_Failure, CPLE_NotSupported,
1233
"The DIMAP driver does not support update access to existing"
1238
/* -------------------------------------------------------------------- */
1239
/* Create a corresponding GDALDataset. */
1240
/* -------------------------------------------------------------------- */
1243
poDS = new ECWDataset(bIsJPEG2000);
1245
poDS->poFileView = poFileView;
1247
if( fpVSIL != NULL )
1248
poDS->nPamFlags |= GPF_DISABLED;
1250
poDS->bUsingCustomStream = bUsingCustomStream;
1252
/* -------------------------------------------------------------------- */
1253
/* Fetch general file information. */
1254
/* -------------------------------------------------------------------- */
1255
poDS->psFileInfo = poFileView->GetFileInfo();
1257
CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
1258
" OriginXY=%g,%g CellIncrementXY=%g,%g\n",
1259
poDS->psFileInfo->nSizeX,
1260
poDS->psFileInfo->nSizeY,
1261
poDS->psFileInfo->nBands,
1262
poDS->psFileInfo->fOriginX,
1263
poDS->psFileInfo->fOriginY,
1264
poDS->psFileInfo->fCellIncrementX,
1265
poDS->psFileInfo->fCellIncrementY );
1267
/* -------------------------------------------------------------------- */
1268
/* Establish raster info. */
1269
/* -------------------------------------------------------------------- */
1270
poDS->nRasterXSize = poDS->psFileInfo->nSizeX;
1271
poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
1273
/* -------------------------------------------------------------------- */
1274
/* Establish the GDAL data type that corresponds. A few NCS */
1275
/* data types have no direct corresponding value in GDAL so we */
1276
/* will coerce to something sufficiently similar. */
1277
/* -------------------------------------------------------------------- */
1278
poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
1279
switch( poDS->psFileInfo->eCellType )
1282
poDS->eRasterDataType = GDT_Byte;
1286
poDS->eRasterDataType = GDT_UInt16;
1291
poDS->eRasterDataType = GDT_UInt32;
1292
poDS->eNCSRequestDataType = NCSCT_UINT32;
1297
poDS->eRasterDataType = GDT_Int16;
1298
poDS->eNCSRequestDataType = NCSCT_INT16;
1303
poDS->eRasterDataType = GDT_Int32;
1304
poDS->eNCSRequestDataType = NCSCT_INT32;
1308
poDS->eRasterDataType = GDT_Float32;
1312
poDS->eRasterDataType = GDT_Float64;
1316
/* -------------------------------------------------------------------- */
1317
/* Create band information objects. */
1318
/* -------------------------------------------------------------------- */
1319
for( i=0; i < poDS->psFileInfo->nBands; i++ )
1320
poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
1322
/* -------------------------------------------------------------------- */
1323
/* Look for supporting coordinate system information. */
1324
/* -------------------------------------------------------------------- */
1325
GDALJP2Metadata oJP2Geo;
1327
if( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
1329
poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
1330
poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
1331
memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
1332
sizeof(double) * 6 );
1333
poDS->nGCPCount = oJP2Geo.nGCPCount;
1334
poDS->pasGCPList = oJP2Geo.pasGCPList;
1335
oJP2Geo.pasGCPList = NULL;
1336
oJP2Geo.nGCPCount = 0;
1340
poDS->ECW2WKTProjection();
1343
/* -------------------------------------------------------------------- */
1344
/* Check for world file for ecw files. */
1345
/* -------------------------------------------------------------------- */
1346
if( !poDS->bGeoTransformValid
1347
&& EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw") )
1349
poDS->bGeoTransformValid |=
1350
GDALReadWorldFile( poOpenInfo->pszFilename, ".eww",
1351
poDS->adfGeoTransform )
1352
|| GDALReadWorldFile( poOpenInfo->pszFilename, ".ecww",
1353
poDS->adfGeoTransform )
1354
|| GDALReadWorldFile( poOpenInfo->pszFilename, ".wld",
1355
poDS->adfGeoTransform );
1358
/* -------------------------------------------------------------------- */
1359
/* Initialize any PAM information. */
1360
/* -------------------------------------------------------------------- */
1361
poDS->SetDescription( poOpenInfo->pszFilename );
1364
/* -------------------------------------------------------------------- */
1365
/* Confirm the requested access is supported. */
1366
/* -------------------------------------------------------------------- */
1367
if( poOpenInfo->eAccess == GA_Update )
1370
CPLError( CE_Failure, CPLE_NotSupported,
1371
"The ECW driver does not support update access to existing"
1379
/************************************************************************/
1381
/************************************************************************/
1383
int ECWDataset::GetGCPCount()
1386
if( nGCPCount != 0 )
1389
return GDALPamDataset::GetGCPCount();
1392
/************************************************************************/
1393
/* GetGCPProjection() */
1394
/************************************************************************/
1396
const char *ECWDataset::GetGCPProjection()
1400
return pszProjection;
1402
return GDALPamDataset::GetGCPProjection();
1405
/************************************************************************/
1407
/************************************************************************/
1409
const GDAL_GCP *ECWDataset::GetGCPs()
1412
if( nGCPCount != 0 )
1415
return GDALPamDataset::GetGCPs();
1418
/************************************************************************/
1419
/* GetProjectionRef() */
1421
/* We let PAM coordinate system override the one stored inside */
1423
/************************************************************************/
1425
const char *ECWDataset::GetProjectionRef()
1428
const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
1430
if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
1431
return pszProjection;
1436
/************************************************************************/
1437
/* GetGeoTransform() */
1439
/* Only return the native geotransform if we appear to be */
1440
/* returning the native coordinate system, otherwise defer to */
1441
/* the PAM geotransform. */
1442
/************************************************************************/
1444
CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
1447
if( (GetProjectionRef() != pszProjection
1448
&& strlen(GetProjectionRef()) > 0)
1449
|| !bGeoTransformValid )
1451
return GDALPamDataset::GetGeoTransform( padfTransform );
1455
memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1460
/************************************************************************/
1462
/************************************************************************/
1464
char **ECWDataset::GetMetadata( const char *pszDomain )
1467
if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
1468
return GDALPamDataset::GetMetadata( pszDomain );
1470
return papszGMLMetadata;
1473
/************************************************************************/
1474
/* ECW2WKTProjection() */
1476
/* Set the dataset pszProjection string in OGC WKT format by */
1477
/* looking up the ECW (GDT) coordinate system info in */
1478
/* ecw_cs.dat support data file. */
1480
/* This code is likely still broken in some circumstances. For */
1481
/* instance, I haven't been careful about changing the linear */
1482
/* projection parameters (false easting/northing) if the units */
1483
/* is feet. Lots of cases missing here, and in ecw_cs.dat. */
1484
/************************************************************************/
1486
void ECWDataset::ECW2WKTProjection()
1489
if( psFileInfo == NULL )
1492
/* -------------------------------------------------------------------- */
1493
/* Capture Geotransform. */
1495
/* We will try to ignore the provided file information if it is */
1496
/* origin (0,0) and pixel size (1,1). I think sometimes I have */
1497
/* also seen pixel increments of 0 on invalid datasets. */
1498
/* -------------------------------------------------------------------- */
1499
if( psFileInfo->fOriginX != 0.0
1500
|| psFileInfo->fOriginY != 0.0
1501
|| (psFileInfo->fCellIncrementX != 0.0
1502
&& psFileInfo->fCellIncrementX != 1.0)
1503
|| (psFileInfo->fCellIncrementY != 0.0
1504
&& psFileInfo->fCellIncrementY != 1.0) )
1506
bGeoTransformValid = TRUE;
1508
adfGeoTransform[0] = psFileInfo->fOriginX;
1509
adfGeoTransform[1] = psFileInfo->fCellIncrementX;
1510
adfGeoTransform[2] = 0.0;
1512
adfGeoTransform[3] = psFileInfo->fOriginY;
1513
adfGeoTransform[4] = 0.0;
1514
adfGeoTransform[5] = psFileInfo->fCellIncrementY;
1517
/* -------------------------------------------------------------------- */
1518
/* do we have projection and datum? */
1519
/* -------------------------------------------------------------------- */
1520
CPLDebug( "ECW", "projection=%s, datum=%s",
1521
psFileInfo->szProjection, psFileInfo->szDatum );
1523
if( EQUAL(psFileInfo->szProjection,"RAW") )
1526
/* -------------------------------------------------------------------- */
1527
/* Set projection if we have it. */
1528
/* -------------------------------------------------------------------- */
1529
OGRSpatialReference oSRS;
1530
CPLString osUnits = "METERS";
1532
if( psFileInfo->eCellSizeUnits == ECW_CELL_UNITS_FEET )
1535
if( oSRS.importFromERM( psFileInfo->szProjection,
1536
psFileInfo->szDatum,
1537
osUnits ) != OGRERR_NONE )
1540
oSRS.exportToWkt( &pszProjection );
1543
#endif /* def FRMT_ecw */
1545
/************************************************************************/
1546
/* ECWInitialize() */
1548
/* Initialize NCS library. We try to defer this as late as */
1549
/* possible since de-initializing it seems to be expensive/slow */
1550
/* on some system. */
1551
/************************************************************************/
1553
void ECWInitialize()
1556
CPLMutexHolder oHolder( &hECWDatasetMutex );
1558
if( bNCSInitialized )
1562
bNCSInitialized = TRUE;
1564
const char *pszEcwCacheSize =
1565
CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
1567
if( pszEcwCacheSize != NULL )
1568
NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, atoi(pszEcwCacheSize) );
1571
/************************************************************************/
1572
/* GDALDeregister_ECW() */
1573
/************************************************************************/
1575
void GDALDeregister_ECW( GDALDriver * )
1578
/* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
1581
if( bNCSInitialized )
1583
bNCSInitialized = FALSE;
1587
if( hECWDatasetMutex != NULL )
1589
CPLDestroyMutex( hECWDatasetMutex );
1590
hECWDatasetMutex = NULL;
1595
/************************************************************************/
1596
/* GDALRegister_ECW() */
1597
/************************************************************************/
1599
void GDALRegister_ECW()
1603
GDALDriver *poDriver;
1605
if (! GDAL_CHECK_VERSION("ECW driver"))
1608
if( GDALGetDriverByName( "ECW" ) == NULL )
1610
poDriver = new GDALDriver();
1612
poDriver->SetDescription( "ECW" );
1613
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1614
"ERMapper Compressed Wavelets" );
1615
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1617
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
1619
poDriver->pfnIdentify = ECWDataset::IdentifyECW;
1620
poDriver->pfnOpen = ECWDataset::OpenECW;
1621
poDriver->pfnUnloadDriver = GDALDeregister_ECW;
1622
#ifdef HAVE_COMPRESS
1623
// The create method seems not to work properly.
1624
// poDriver->pfnCreate = ECWCreateECW;
1625
poDriver->pfnCreateCopy = ECWCreateCopyECW;
1626
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1628
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1629
"<CreationOptionList>"
1630
" <Option name='TARGET' type='float' description='Compression Percentage' />"
1631
" <Option name='PROJ' type='string' description='ERMapper Projection Name'/>"
1632
" <Option name='DATUM' type='string' description='ERMapper Datum Name' />"
1633
" <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
1634
"</CreationOptionList>" );
1637
GetGDALDriverManager()->RegisterDriver( poDriver );
1639
#endif /* def FRMT_ecw */
1642
/************************************************************************/
1643
/* GDALRegister_ECW_JP2ECW() */
1645
/* This function exists so that when built as a plugin, there */
1646
/* is a function that will register both drivers. */
1647
/************************************************************************/
1649
void GDALRegister_ECW_JP2ECW()
1653
GDALRegister_JP2ECW();
1656
/************************************************************************/
1657
/* ECWDatasetOpenJPEG2000() */
1658
/************************************************************************/
1659
GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
1661
return ECWDataset::OpenJPEG2000(poOpenInfo);
1664
/************************************************************************/
1665
/* GDALRegister_JP2ECW() */
1666
/************************************************************************/
1667
void GDALRegister_JP2ECW()
1671
GDALDriver *poDriver;
1673
if (! GDAL_CHECK_VERSION("JP2ECW driver"))
1676
if( GDALGetDriverByName( "JP2ECW" ) == NULL )
1678
poDriver = new GDALDriver();
1680
poDriver->SetDescription( "JP2ECW" );
1681
poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
1682
"ERMapper JPEG2000" );
1683
poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
1684
"frmt_jp2ecw.html" );
1685
poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
1687
poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
1688
poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
1689
#ifdef HAVE_COMPRESS
1690
poDriver->pfnCreate = ECWCreateJPEG2000;
1691
poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
1692
poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
1693
"Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
1694
poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
1695
"<CreationOptionList>"
1696
" <Option name='TARGET' type='float' description='Compression Percentage' />"
1697
" <Option name='PROJ' type='string' description='ERMapper Projection Name'/>"
1698
" <Option name='DATUM' type='string' description='ERMapper Datum Name' />"
1699
" <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
1700
" <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
1701
" <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
1702
" <Option name='PROFILE' type='string-select'>"
1703
" <Value>BASELINE_0</Value>"
1704
" <Value>BASELINE_1</Value>"
1705
" <Value>BASELINE_2</Value>"
1706
" <Value>NPJE</Value>"
1707
" <Value>EPJE</Value>"
1709
" <Option name='PROGRESSION' type='string-select'>"
1710
" <Value>LRCP</Value>"
1711
" <Value>RLCP</Value>"
1712
" <Value>RPCL</Value>"
1714
" <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
1715
" <Option name='LEVELS' type='int'/>"
1716
" <Option name='LAYERS' type='int'/>"
1717
" <Option name='PRECINCT_WIDTH' type='int'/>"
1718
" <Option name='PRECINCT_HEIGHT' type='int'/>"
1719
" <Option name='TILE_WIDTH' type='int'/>"
1720
" <Option name='TILE_HEIGHT' type='int'/>"
1721
" <Option name='INCLUDE_SOP' type='boolean'/>"
1722
" <Option name='INCLUDE_EPH' type='boolean'/>"
1723
" <Option name='DECOMPRESS_LAYERS' type='int'/>"
1724
" <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
1725
"</CreationOptionList>" );
1728
GetGDALDriverManager()->RegisterDriver( poDriver );
1730
#endif /* def FRMT_ecw */