1 : /******************************************************************************
2 : * $Id: ecwdataset.cpp 21486 2011-01-13 17:38:17Z warmerdam $
3 : *
4 : * Project: GDAL
5 : * Purpose: ECW (ERDAS Wavelet Compression Format) Driver Definitions
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001-2011, Frank Warmerdam <warmerdam@pobox.com>
10 : *
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:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
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 : ****************************************************************************/
29 :
30 : #ifndef GDAL_ECW_H_INCLUDED
31 : #define GDAL_ECW_H_INCLUDED
32 :
33 : #include "gdal_pam.h"
34 : #include "gdal_frmts.h"
35 : #include "gdaljp2metadata.h"
36 : #include "cpl_string.h"
37 : #include "cpl_conv.h"
38 : #include "cpl_multiproc.h"
39 : #include "cpl_vsi.h"
40 :
41 : #undef NOISY_DEBUG
42 :
43 : #ifdef FRMT_ecw
44 :
45 : // The following is needed on 4.x+ to enable rw support.
46 : #if defined(HAVE_COMPRESS)
47 : # define ECW_COMPRESS_RW_SDK_VERSION
48 : #endif
49 :
50 : #if defined(_MSC_VER)
51 : # pragma warning(disable:4800)
52 : #endif
53 :
54 : #include <NCSECWClient.h>
55 : #include <NCSECWCompressClient.h>
56 : #include <NCSErrors.h>
57 : #include <NCSFile.h>
58 : #include <NCSJP2FileView.h>
59 :
60 : /* By default, assume 3.3 SDK Version. */
61 : #if !defined(ECWSDK_VERSION)
62 : # define ECWSDK_VERSION 33
63 : #endif
64 :
65 : #if ECWSDK_VERSION < 40
66 :
67 : #if !defined(NO_COMPRESS)
68 : # define HAVE_COMPRESS
69 : #endif
70 :
71 : #else
72 : # include <ECWJP2BuildNumber.h>
73 : #if ECWSDK_VERSION>=50
74 : #include <NCSECWHeaderEditor.h>
75 : #include "NCSEcw/JP2/File.h"
76 : #else
77 : #include <HeaderEditor.h>
78 : #endif
79 : # define NCS_FASTCALL
80 : #endif
81 :
82 :
83 : #if ECWSDK_VERSION >= 40
84 : #define SDK_CAN_DO_SUPERSAMPLING 1
85 : #endif
86 :
87 : #ifndef NCSFILEBASE_H
88 : # include <NCSJP2FileView.h>
89 : #else
90 : # undef CNCSJP2FileView
91 : # define CNCSJP2FileView CNCSFile
92 : #endif
93 :
94 : void ECWInitialize( void );
95 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
96 :
97 : #ifdef HAVE_COMPRESS
98 : GDALDataset *
99 : ECWCreateCopyECW( const char * pszFilename, GDALDataset *poSrcDS,
100 : int bStrict, char ** papszOptions,
101 : GDALProgressFunc pfnProgress, void * pProgressData );
102 : GDALDataset *
103 : ECWCreateCopyJPEG2000( const char * pszFilename, GDALDataset *poSrcDS,
104 : int bStrict, char ** papszOptions,
105 : GDALProgressFunc pfnProgress, void * pProgressData );
106 :
107 : GDALDataset *
108 : ECWCreateECW( const char * pszFilename, int nXSize, int nYSize, int nBands,
109 : GDALDataType eType, char **papszOptions );
110 : GDALDataset *
111 : ECWCreateJPEG2000(const char *pszFilename, int nXSize, int nYSize, int nBands,
112 : GDALDataType eType, char **papszOptions );
113 : #endif
114 :
115 : void ECWReportError(CNCSError& oErr, const char* pszMsg = "");
116 :
117 : /************************************************************************/
118 : /* ==================================================================== */
119 : /* JP2Userbox */
120 : /* ==================================================================== */
121 : /************************************************************************/
122 : #ifdef HAVE_COMPRESS
123 : #if ECWSDK_VERSION>=50
124 : class JP2UserBox : public CNCSSDKBox {
125 : #else
126 : class JP2UserBox : public CNCSJP2Box {
127 : #endif
128 : private:
129 : int nDataLength;
130 : unsigned char *pabyData;
131 :
132 : public:
133 : JP2UserBox();
134 :
135 : virtual ~JP2UserBox();
136 :
137 : #if ECWSDK_VERSION >= 40
138 : virtual CNCSError Parse( NCS::JP2::CFile &JP2File,
139 : NCS::CIOStream &Stream);
140 : virtual CNCSError UnParse( NCS::JP2::CFile &JP2File,
141 : NCS::CIOStream &Stream);
142 : #else
143 : virtual CNCSError Parse(class CNCSJP2File &JP2File,
144 : CNCSJPCIOStream &Stream);
145 : virtual CNCSError UnParse(class CNCSJP2File &JP2File,
146 : CNCSJPCIOStream &Stream);
147 : #endif
148 : virtual void UpdateXLBox(void);
149 :
150 : void SetData( int nDataLength, const unsigned char *pabyDataIn );
151 :
152 : int GetDataLength() { return nDataLength; }
153 : unsigned char *GetData() { return pabyData; }
154 : };
155 : #endif /* def HAVE_COMPRESS */
156 :
157 : /************************************************************************/
158 : /* ==================================================================== */
159 : /* VSIIOStream */
160 : /* ==================================================================== */
161 : /************************************************************************/
162 :
163 : class VSIIOStream : public CNCSJPCIOStream
164 :
165 : {
166 : public:
167 :
168 : INT64 startOfJPData;
169 : INT64 lengthOfJPData;
170 : VSILFILE *fpVSIL;
171 : int bWritable;
172 : int nFileViewCount;
173 : char *pszFilename;
174 :
175 66 : VSIIOStream() {
176 66 : nFileViewCount = 0;
177 66 : startOfJPData = 0;
178 66 : lengthOfJPData = -1;
179 66 : fpVSIL = NULL;
180 66 : }
181 66 : virtual ~VSIIOStream() {
182 66 : Close();
183 66 : }
184 :
185 121 : virtual CNCSError Close() {
186 121 : CNCSError oErr = CNCSJPCIOStream::Close();
187 121 : if( fpVSIL != NULL )
188 : {
189 35 : VSIFCloseL( fpVSIL );
190 35 : fpVSIL = NULL;
191 : }
192 0 : return oErr;
193 : }
194 :
195 : #if ECWSDK_VERSION >= 40
196 : virtual VSIIOStream *Clone() {
197 : FILE *fpNewVSIL = VSIFOpenL( m_Name.a_str(), "rb" );
198 : if (fpNewVSIL == NULL)
199 : {
200 : return NULL;
201 : }
202 : else
203 : {
204 : VSIIOStream *pDst = new VSIIOStream();
205 : pDst->Access(fpNewVSIL, bWritable, m_Name.a_str(), startOfJPData, lengthOfJPData);
206 : return pDst;
207 : }
208 : }
209 : #endif /* ECWSDK_VERSION >= 4 */
210 :
211 35 : virtual CNCSError Access( VSILFILE *fpVSILIn, BOOLEAN bWrite,
212 : const char *pszFilename,
213 : INT64 start, INT64 size = -1) {
214 :
215 35 : fpVSIL = fpVSILIn;
216 35 : startOfJPData = start;
217 35 : lengthOfJPData = size;
218 35 : bWritable = bWrite;
219 35 : VSIFSeekL(fpVSIL, startOfJPData, SEEK_SET);
220 :
221 : // the filename is used to establish where to put temporary files.
222 : // if it does not have a path to a real directory, we will
223 : // substitute something.
224 35 : CPLString osFilenameUsed = pszFilename;
225 35 : CPLString osPath = CPLGetPath( pszFilename );
226 : struct stat sStatBuf;
227 35 : if( osPath != "" && stat( osPath, &sStatBuf ) != 0 )
228 : {
229 22 : osFilenameUsed = CPLGenerateTempFilename( NULL );
230 : // try to preserve the extension.
231 22 : if( strlen(CPLGetExtension(pszFilename)) > 0 )
232 : {
233 22 : osFilenameUsed += ".";
234 22 : osFilenameUsed += CPLGetExtension(pszFilename);
235 : }
236 22 : CPLDebug( "ECW", "Using filename '%s' for temporary directory determination purposes.", osFilenameUsed.c_str() );
237 : }
238 : return(CNCSJPCIOStream::Open((char *)osFilenameUsed.c_str(),
239 35 : (bool) bWrite));
240 : }
241 :
242 207 : virtual bool NCS_FASTCALL Seek() {
243 207 : return(true);
244 : }
245 :
246 877 : virtual bool NCS_FASTCALL Seek(INT64 offset, Origin origin = CURRENT) {
247 877 : bool success = false;
248 877 : switch(origin) {
249 : case START:
250 816 : success = (0 == VSIFSeekL(fpVSIL, offset+startOfJPData, SEEK_SET));
251 816 : break;
252 :
253 : case CURRENT:
254 0 : success = (0 == VSIFSeekL(fpVSIL, offset, SEEK_CUR));
255 0 : break;
256 :
257 : case END:
258 61 : success = (0 == VSIFSeekL(fpVSIL, offset, SEEK_END));
259 : break;
260 : }
261 877 : if( !success )
262 : CPLDebug( "ECW", "VSIIOStream::Seek(%d,%d) failed.",
263 1 : (int) offset, (int) origin );
264 877 : return(success);
265 : }
266 :
267 3715 : virtual INT64 NCS_FASTCALL Tell() {
268 3715 : return VSIFTellL( fpVSIL ) - startOfJPData;
269 : }
270 :
271 61 : virtual INT64 NCS_FASTCALL Size() {
272 61 : if( lengthOfJPData != -1 )
273 0 : return lengthOfJPData;
274 : else
275 : {
276 61 : INT64 curPos = Tell(), size;
277 :
278 61 : Seek( 0, END );
279 61 : size = Tell();
280 61 : Seek( curPos, START );
281 :
282 61 : return size;
283 : }
284 : }
285 :
286 6987 : virtual bool NCS_FASTCALL Read(void* buffer, UINT32 count) {
287 6987 : if( count == 0 )
288 366 : return true;
289 :
290 : // return(1 == VSIFReadL( buffer, count, 1, fpVSIL ) );
291 :
292 : // The following is a hack
293 6621 : if( VSIFReadL( buffer, count, 1, fpVSIL ) != 1 )
294 : {
295 : CPLDebug( "VSIIOSTREAM",
296 : "Read(%d) failed @ " CPL_FRMT_GIB ", ignoring failure.",
297 0 : count, (VSIFTellL( fpVSIL ) - startOfJPData) );
298 : }
299 :
300 6621 : return true;
301 : }
302 :
303 3312 : virtual bool NCS_FASTCALL Write(void* buffer, UINT32 count) {
304 3312 : if( count == 0 )
305 0 : return true;
306 3312 : if( 1 != VSIFWriteL(buffer, count, 1, fpVSIL) )
307 : {
308 : CPLDebug( "ECW", "VSIIOStream::Write(%d) failed.",
309 0 : (int) count );
310 0 : return false;
311 : }
312 : else
313 3312 : return true;
314 : }
315 : };
316 :
317 : /************************************************************************/
318 : /* ==================================================================== */
319 : /* ECWAsyncReader */
320 : /* ==================================================================== */
321 : /************************************************************************/
322 : class ECWDataset;
323 :
324 : #if ECWSDK_VERSION >= 40
325 :
326 : class ECWAsyncReader : public GDALAsyncReader
327 : {
328 : private:
329 : CNCSJP2FileView *poFileView;
330 : void *hMutex;
331 : int bUsingCustomStream;
332 :
333 : int bUpdateReady;
334 : int bComplete;
335 :
336 : static NCSEcwReadStatus RefreshCB( NCSFileView * );
337 : NCSEcwReadStatus ReadToBuffer();
338 :
339 : public:
340 : ECWAsyncReader();
341 : virtual ~ECWAsyncReader();
342 : virtual GDALAsyncStatusType GetNextUpdatedRegion(double dfTimeout,
343 : int* pnXBufOff,
344 : int* pnYBufOff,
345 : int* pnXBufSize,
346 : int* pnYBufSize);
347 :
348 : friend class ECWDataset;
349 : };
350 : #endif /* ECWSDK_VERSION >= 40 */
351 :
352 : /************************************************************************/
353 : /* ==================================================================== */
354 : /* ECWDataset */
355 : /* ==================================================================== */
356 : /************************************************************************/
357 :
358 : class ECWRasterBand;
359 :
360 : class CPL_DLL ECWDataset : public GDALPamDataset
361 : {
362 : friend class ECWRasterBand;
363 : friend class ECWAsyncReader;
364 :
365 : int bIsJPEG2000;
366 :
367 : CNCSJP2FileView *poFileView;
368 : NCSFileViewFileInfoEx *psFileInfo;
369 :
370 : GDALDataType eRasterDataType;
371 : NCSEcwCellType eNCSRequestDataType;
372 :
373 : int bUsingCustomStream;
374 :
375 : // Current view window.
376 : int bWinActive;
377 : int nWinXOff, nWinYOff, nWinXSize, nWinYSize;
378 : int nWinBufXSize, nWinBufYSize;
379 : int nWinBandCount;
380 : int *panWinBandList;
381 : int nWinBufLoaded;
382 : void **papCurLineBuf;
383 :
384 : int bGeoTransformValid;
385 : double adfGeoTransform[6];
386 : char *pszProjection;
387 : int nGCPCount;
388 : GDAL_GCP *pasGCPList;
389 :
390 : char **papszGMLMetadata;
391 :
392 : void ECW2WKTProjection();
393 :
394 : void CleanupWindow();
395 : int TryWinRasterIO( GDALRWFlag, int, int, int, int,
396 : GByte *, int, int, GDALDataType,
397 : int, int *, int, int, int );
398 : CPLErr LoadNextLine();
399 :
400 : static CNCSJP2FileView *OpenFileView( const char *pszDatasetName,
401 : bool bProgressive,
402 : int &bUsingCustomStream );
403 :
404 : int bHdrDirty;
405 : CPLString m_osDatumCode;
406 : CPLString m_osProjCode;
407 : CPLString m_osUnitsCode;
408 : int bGeoTransformChanged;
409 : int bProjectionChanged;
410 : int bProjCodeChanged;
411 : int bDatumCodeChanged;
412 : int bUnitsCodeChanged;
413 : void WriteHeader();
414 :
415 : int bUseOldBandRasterIOImplementation;
416 :
417 : CPLStringList oECWMetadataList;
418 : CPLErr ReadBands(void * pData, int nBufXSize, int nBufYSize,
419 : GDALDataType eBufType,
420 : int nBandCount,
421 : int nPixelSpace, int nLineSpace, int nBandSpace);
422 : CPLErr ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
423 : GDALDataType eBufType,
424 : int nBandCount,
425 : int nPixelSpace, int nLineSpace, int nBandSpace);
426 : public:
427 : ECWDataset(int bIsJPEG2000);
428 : ~ECWDataset();
429 :
430 : static GDALDataset *Open( GDALOpenInfo *, int bIsJPEG2000 );
431 : static int IdentifyJPEG2000( GDALOpenInfo * poOpenInfo );
432 : static GDALDataset *OpenJPEG2000( GDALOpenInfo * );
433 : static int IdentifyECW( GDALOpenInfo * poOpenInfo );
434 : static GDALDataset *OpenECW( GDALOpenInfo * );
435 :
436 : virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
437 : void *, int, int, GDALDataType,
438 : int, int *, int, int, int );
439 :
440 : virtual CPLErr GetGeoTransform( double * );
441 : virtual const char *GetProjectionRef();
442 :
443 : virtual int GetGCPCount();
444 : virtual const char *GetGCPProjection();
445 : virtual const GDAL_GCP *GetGCPs();
446 :
447 : virtual const char *GetMetadataItem( const char * pszName,
448 : const char * pszDomain = "" );
449 : virtual char **GetMetadata( const char * pszDomain = "" );
450 :
451 : virtual CPLErr SetGeoTransform( double * padfGeoTransform );
452 : virtual CPLErr SetProjection( const char* pszProjection );
453 : virtual CPLErr SetMetadataItem( const char * pszName,
454 : const char * pszValue,
455 : const char * pszDomain = "" );
456 : virtual CPLErr SetMetadata( char ** papszMetadata,
457 : const char * pszDomain = "" );
458 :
459 : virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
460 : int nBufXSize, int nBufYSize,
461 : GDALDataType eDT,
462 : int nBandCount, int *panBandList,
463 : char **papszOptions );
464 :
465 : // progressive methods
466 : #if ECWSDK_VERSION >= 40
467 : virtual GDALAsyncReader* BeginAsyncReader( int nXOff, int nYOff,
468 : int nXSize, int nYSize,
469 : void *pBuf,
470 : int nBufXSize, int nBufYSize,
471 : GDALDataType eBufType,
472 : int nBandCount, int* panBandMap,
473 : int nPixelSpace, int nLineSpace,
474 : int nBandSpace,
475 : char **papszOptions);
476 :
477 : virtual void EndAsyncReader(GDALAsyncReader *);
478 : #endif /* ECWSDK_VERSION > 40 */
479 : };
480 :
481 : /************************************************************************/
482 : /* ==================================================================== */
483 : /* ECWRasterBand */
484 : /* ==================================================================== */
485 : /************************************************************************/
486 :
487 : class ECWRasterBand : public GDALPamRasterBand
488 : {
489 : friend class ECWDataset;
490 :
491 : // NOTE: poDS may be altered for NITF/JPEG2000 files!
492 : ECWDataset *poGDS;
493 :
494 : GDALColorInterp eBandInterp;
495 :
496 : int iOverview; // -1 for base.
497 :
498 : std::vector<ECWRasterBand*> apoOverviews;
499 :
500 : //#if !defined(SDK_CAN_DO_SUPERSAMPLING)
501 : CPLErr OldIRasterIO( GDALRWFlag, int, int, int, int,
502 : void *, int, int, GDALDataType,
503 : int, int );
504 : //#endif
505 :
506 : virtual CPLErr IRasterIO( GDALRWFlag, int, int, int, int,
507 : void *, int, int, GDALDataType,
508 : int, int );
509 :
510 : public:
511 :
512 : ECWRasterBand( ECWDataset *, int, int = -1 );
513 : ~ECWRasterBand();
514 :
515 : virtual CPLErr IReadBlock( int, int, void * );
516 0 : virtual int HasArbitraryOverviews() { return apoOverviews.size() == 0; }
517 1 : virtual int GetOverviewCount() { return apoOverviews.size(); }
518 : virtual GDALRasterBand *GetOverview(int);
519 :
520 : virtual GDALColorInterp GetColorInterpretation();
521 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
522 :
523 : virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
524 : int nBufXSize, int nBufYSize,
525 : GDALDataType eDT, char **papszOptions );
526 : };
527 :
528 : int ECWTranslateFromWKT( const char *pszWKT,
529 : char *pszProjection,
530 : int nProjectionLen,
531 : char *pszDatum,
532 : int nDatumLen,
533 : char *pszUnits);
534 :
535 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits);
536 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits);
537 :
538 : #endif /* def FRMT_ecw */
539 :
540 : #endif /* ndef GDAL_ECW_H_INCLUDED */
|