1 : /******************************************************************************
2 : * $Id: ecwdataset.cpp 25292 2012-12-08 10:30:54Z rouault $
3 : *
4 : * Project: GDAL
5 : * Purpose: ECW (ERDAS Wavelet Compression Format) Driver
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001, 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 : #include "gdal_ecw.h"
31 : #include "cpl_minixml.h"
32 : #include "ogr_spatialref.h"
33 : #include "ogr_api.h"
34 : #include "ogr_geometry.h"
35 :
36 : CPL_CVSID("$Id: ecwdataset.cpp 25292 2012-12-08 10:30:54Z rouault $");
37 :
38 : #undef NOISY_DEBUG
39 :
40 : #ifdef FRMT_ecw
41 :
42 : static const unsigned char jpc_header[] = {0xff,0x4f};
43 : static const unsigned char jp2_header[] =
44 : {0x00,0x00,0x00,0x0c,0x6a,0x50,0x20,0x20,0x0d,0x0a,0x87,0x0a};
45 :
46 : static void *hECWDatasetMutex = NULL;
47 : static int bNCSInitialized = FALSE;
48 :
49 : void ECWInitialize( void );
50 :
51 : #define BLOCK_SIZE 256
52 :
53 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo);
54 :
55 : /************************************************************************/
56 : /* ECWReportError() */
57 : /************************************************************************/
58 :
59 3 : void ECWReportError(CNCSError& oErr, const char* pszMsg)
60 : {
61 : #if ECWSDK_VERSION<50
62 3 : char* pszErrorMessage = oErr.GetErrorMessage();
63 : CPLError( CE_Failure, CPLE_AppDefined,
64 3 : "%s%s", pszMsg, pszErrorMessage );
65 3 : NCSFree(pszErrorMessage);
66 : #else
67 : const char* pszErrorMessage = oErr.GetErrorMessage().a_str();
68 : CPLError( CE_Failure, CPLE_AppDefined,
69 : "%s%s", pszMsg, pszErrorMessage );
70 : #endif
71 3 : }
72 :
73 : /************************************************************************/
74 : /* ECWRasterBand() */
75 : /************************************************************************/
76 :
77 237 : ECWRasterBand::ECWRasterBand( ECWDataset *poDS, int nBand, int iOverview )
78 :
79 : {
80 237 : this->poDS = poDS;
81 237 : poGDS = poDS;
82 :
83 237 : this->iOverview = iOverview;
84 237 : this->nBand = nBand;
85 237 : eDataType = poDS->eRasterDataType;
86 :
87 237 : nRasterXSize = poDS->GetRasterXSize() / ( 1 << (iOverview+1));
88 237 : nRasterYSize = poDS->GetRasterYSize() / ( 1 << (iOverview+1));
89 :
90 237 : nBlockXSize = BLOCK_SIZE;
91 237 : nBlockYSize = BLOCK_SIZE;
92 :
93 : /* -------------------------------------------------------------------- */
94 : /* Work out band color interpretation. */
95 : /* -------------------------------------------------------------------- */
96 237 : if( poDS->psFileInfo->eColorSpace == NCSCS_NONE )
97 0 : eBandInterp = GCI_Undefined;
98 237 : else if( poDS->psFileInfo->eColorSpace == NCSCS_GREYSCALE )
99 37 : eBandInterp = GCI_GrayIndex;
100 200 : else if( poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND )
101 28 : eBandInterp = GCI_Undefined;
102 172 : else if( poDS->psFileInfo->eColorSpace == NCSCS_sRGB )
103 : {
104 172 : if( nBand == 1 )
105 57 : eBandInterp = GCI_RedBand;
106 115 : else if( nBand == 2 )
107 57 : eBandInterp = GCI_GreenBand;
108 58 : else if( nBand == 3 )
109 57 : eBandInterp = GCI_BlueBand;
110 1 : else if( nBand == 4 )
111 1 : eBandInterp = GCI_AlphaBand;
112 : else
113 0 : eBandInterp = GCI_Undefined;
114 : }
115 0 : else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
116 : {
117 0 : if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
118 : {
119 0 : if( nBand == 1 )
120 0 : eBandInterp = GCI_RedBand;
121 0 : else if( nBand == 2 )
122 0 : eBandInterp = GCI_GreenBand;
123 0 : else if( nBand == 3 )
124 0 : eBandInterp = GCI_BlueBand;
125 : else
126 0 : eBandInterp = GCI_Undefined;
127 : }
128 : else
129 : {
130 0 : if( nBand == 1 )
131 0 : eBandInterp = GCI_YCbCr_YBand;
132 0 : else if( nBand == 2 )
133 0 : eBandInterp = GCI_YCbCr_CbBand;
134 0 : else if( nBand == 3 )
135 0 : eBandInterp = GCI_YCbCr_CrBand;
136 : else
137 0 : eBandInterp = GCI_Undefined;
138 : }
139 : }
140 : else
141 0 : eBandInterp = GCI_Undefined;
142 :
143 : /* -------------------------------------------------------------------- */
144 : /* If this is the base level, create a set of overviews. */
145 : /* -------------------------------------------------------------------- */
146 237 : if( iOverview == -1 )
147 : {
148 : int i;
149 237 : for( i = 0;
150 : nRasterXSize / (1 << (i+1)) > 128
151 : && nRasterYSize / (1 << (i+1)) > 128;
152 : i++ )
153 : {
154 99 : apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
155 : }
156 : }
157 :
158 237 : if( (poDS->psFileInfo->pBands[nBand-1].nBits % 8) != 0 )
159 : SetMetadataItem("NBITS",
160 4 : CPLString().Printf("%d",poDS->psFileInfo->pBands[nBand-1].nBits),
161 4 : "IMAGE_STRUCTURE" );
162 237 : }
163 :
164 : /************************************************************************/
165 : /* ~ECWRasterBand() */
166 : /************************************************************************/
167 :
168 237 : ECWRasterBand::~ECWRasterBand()
169 :
170 : {
171 237 : FlushCache();
172 :
173 573 : while( apoOverviews.size() > 0 )
174 : {
175 99 : delete apoOverviews.back();
176 99 : apoOverviews.pop_back();
177 : }
178 237 : }
179 :
180 : /************************************************************************/
181 : /* GetOverview() */
182 : /************************************************************************/
183 :
184 2 : GDALRasterBand *ECWRasterBand::GetOverview( int iOverview )
185 :
186 : {
187 2 : if( iOverview >= 0 && iOverview < (int) apoOverviews.size() )
188 2 : return apoOverviews[iOverview];
189 : else
190 0 : return NULL;
191 : }
192 :
193 : /************************************************************************/
194 : /* GetColorInterpretation() */
195 : /************************************************************************/
196 :
197 61 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
198 :
199 : {
200 61 : return eBandInterp;
201 : }
202 :
203 : /************************************************************************/
204 : /* SetColorInterpretation() */
205 : /* */
206 : /* This would normally just be used by folks using the ECW code */
207 : /* to read JP2 streams in other formats (such as NITF) and */
208 : /* providing their own color interpretation regardless of what */
209 : /* ECW might think the stream itself says. */
210 : /************************************************************************/
211 :
212 0 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
213 :
214 : {
215 0 : eBandInterp = eNewInterp;
216 :
217 0 : return CE_None;
218 : }
219 :
220 : /************************************************************************/
221 : /* AdviseRead() */
222 : /************************************************************************/
223 :
224 0 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
225 : int nBufXSize, int nBufYSize,
226 : GDALDataType eDT,
227 : char **papszOptions )
228 : {
229 0 : int nResFactor = 1 << (iOverview+1);
230 :
231 : return poGDS->AdviseRead( nXOff * nResFactor,
232 : nYOff * nResFactor,
233 : nXSize * nResFactor,
234 : nYSize * nResFactor,
235 : nBufXSize, nBufYSize, eDT,
236 0 : 1, &nBand, papszOptions );
237 : }
238 :
239 : //#if !defined(SDK_CAN_DO_SUPERSAMPLING)
240 : /************************************************************************/
241 : /* OldIRasterIO() */
242 : /************************************************************************/
243 :
244 : /* This implementation of IRasterIO(), derived from the one of GDAL 1.9 */
245 : /* and older versions, is meant at making over-sampling */
246 : /* work with ECW SDK 3.3. Newer versions of the SDK can do super-sampling in their */
247 : /* SetView() call. */
248 :
249 1 : CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
250 : int nXOff, int nYOff, int nXSize, int nYSize,
251 : void * pData, int nBufXSize, int nBufYSize,
252 : GDALDataType eBufType,
253 : int nPixelSpace, int nLineSpace )
254 :
255 : {
256 : int iBand, bDirect;
257 1 : GByte *pabyWorkBuffer = NULL;
258 1 : int nResFactor = 1 << (iOverview+1);
259 :
260 1 : nXOff *= nResFactor;
261 1 : nYOff *= nResFactor;
262 1 : nXSize *= nResFactor;
263 1 : nYSize *= nResFactor;
264 :
265 : /* -------------------------------------------------------------------- */
266 : /* Try to do it based on existing "advised" access. */
267 : /* -------------------------------------------------------------------- */
268 1 : if( poGDS->TryWinRasterIO( eRWFlag,
269 : nXOff, nYOff,
270 : nXSize, nYSize,
271 : (GByte *) pData, nBufXSize, nBufYSize,
272 : eBufType, 1, &nBand,
273 : nPixelSpace, nLineSpace, 0 ) )
274 0 : return CE_None;
275 :
276 : /* -------------------------------------------------------------------- */
277 : /* The ECW SDK doesn't supersample, so adjust for this case. */
278 : /* -------------------------------------------------------------------- */
279 :
280 1 : int nNewXSize = nBufXSize, nNewYSize = nBufYSize;
281 :
282 1 : if ( nXSize < nBufXSize )
283 1 : nNewXSize = nXSize;
284 :
285 1 : if ( nYSize < nBufYSize )
286 1 : nNewYSize = nYSize;
287 :
288 : /* -------------------------------------------------------------------- */
289 : /* Can we perform direct loads, or must we load into a working */
290 : /* buffer, and transform? */
291 : /* -------------------------------------------------------------------- */
292 1 : int nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
293 :
294 : bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
295 1 : && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
296 1 : if( !bDirect )
297 1 : pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
298 :
299 : /* -------------------------------------------------------------------- */
300 : /* Establish access at the desired resolution. */
301 : /* -------------------------------------------------------------------- */
302 1 : CNCSError oErr;
303 :
304 1 : poGDS->CleanupWindow();
305 :
306 1 : iBand = nBand-1;
307 : oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
308 : nXOff, nYOff,
309 : nXOff + nXSize - 1,
310 : nYOff + nYSize - 1,
311 1 : nNewXSize, nNewYSize );
312 1 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
313 : {
314 0 : CPLFree( pabyWorkBuffer );
315 0 : ECWReportError(oErr);
316 :
317 0 : return CE_Failure;
318 : }
319 :
320 : /* -------------------------------------------------------------------- */
321 : /* Read back one scanline at a time, till request is satisfied. */
322 : /* Supersampling is not supported by the ECW API, so we will do */
323 : /* it ourselves. */
324 : /* -------------------------------------------------------------------- */
325 1 : double dfSrcYInc = (double)nNewYSize / nBufYSize;
326 1 : double dfSrcXInc = (double)nNewXSize / nBufXSize;
327 : int iSrcLine, iDstLine;
328 :
329 801 : for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
330 : {
331 : NCSEcwReadStatus eRStatus;
332 800 : int iDstLineOff = iDstLine * nLineSpace;
333 : unsigned char *pabySrcBuf;
334 :
335 800 : if( bDirect )
336 0 : pabySrcBuf = ((GByte *)pData) + iDstLineOff;
337 : else
338 800 : pabySrcBuf = pabyWorkBuffer;
339 :
340 1200 : if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
341 : {
342 : eRStatus = poGDS->poFileView->ReadLineBIL(
343 400 : poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
344 :
345 400 : if( eRStatus != NCSECW_READ_OK )
346 : {
347 0 : CPLFree( pabyWorkBuffer );
348 0 : CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
349 : CPLError( CE_Failure, CPLE_AppDefined,
350 0 : "NCScbmReadViewLineBIL failed." );
351 0 : return CE_Failure;
352 : }
353 :
354 400 : if( !bDirect )
355 : {
356 400 : if ( nNewXSize == nBufXSize )
357 : {
358 : GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType,
359 : nRawPixelSize,
360 : ((GByte *)pData) + iDstLine * nLineSpace,
361 0 : eBufType, nPixelSpace, nBufXSize );
362 : }
363 : else
364 : {
365 : int iPixel;
366 :
367 320400 : for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
368 : {
369 : GDALCopyWords( pabyWorkBuffer
370 : + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
371 : poGDS->eRasterDataType, nRawPixelSize,
372 : (GByte *)pData + iDstLineOff
373 : + iPixel * nPixelSpace,
374 320000 : eBufType, nPixelSpace, 1 );
375 : }
376 : }
377 : }
378 :
379 400 : iSrcLine++;
380 : }
381 : else
382 : {
383 : // Just copy the previous line in this case
384 : GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
385 : eBufType, nPixelSpace,
386 : (GByte *)pData + iDstLineOff,
387 400 : eBufType, nPixelSpace, nBufXSize );
388 : }
389 : }
390 :
391 1 : CPLFree( pabyWorkBuffer );
392 :
393 1 : return CE_None;
394 : }
395 : //#endif !defined(SDK_CAN_DO_SUPERSAMPLING)
396 :
397 : /************************************************************************/
398 : /* IRasterIO() */
399 : /************************************************************************/
400 :
401 12741 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
402 : int nXOff, int nYOff, int nXSize, int nYSize,
403 : void * pData, int nBufXSize, int nBufYSize,
404 : GDALDataType eBufType,
405 : int nPixelSpace, int nLineSpace )
406 : {
407 : /* -------------------------------------------------------------------- */
408 : /* Default line and pixel spacing if needed. */
409 : /* -------------------------------------------------------------------- */
410 12741 : if ( nPixelSpace == 0 )
411 0 : nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
412 :
413 12741 : if ( nLineSpace == 0 )
414 0 : nLineSpace = nPixelSpace * nBufXSize;
415 :
416 : CPLDebug( "ECWRasterBand",
417 : "RasterIO(nBand=%d,iOverview=%d,nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)",
418 12741 : nBand, iOverview, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
419 :
420 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
421 12741 : if( poGDS->bUseOldBandRasterIOImplementation )
422 : {
423 : return OldIRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
424 : pData, nBufXSize, nBufYSize,
425 : eBufType,
426 1 : nPixelSpace, nLineSpace );
427 : }
428 :
429 : #endif
430 :
431 12740 : int nResFactor = 1 << (iOverview+1);
432 :
433 : return poGDS->IRasterIO(eRWFlag,
434 : nXOff * nResFactor,
435 : nYOff * nResFactor,
436 : (nXSize == nRasterXSize) ? poGDS->nRasterXSize : nXSize * nResFactor,
437 : (nYSize == nRasterYSize) ? poGDS->nRasterYSize : nYSize * nResFactor,
438 : pData, nBufXSize, nBufYSize,
439 : eBufType, 1, &nBand,
440 12740 : nPixelSpace, nLineSpace, nLineSpace*nBufYSize);
441 : }
442 :
443 : /************************************************************************/
444 : /* IReadBlock() */
445 : /************************************************************************/
446 :
447 1 : CPLErr ECWRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
448 :
449 : {
450 1 : int nXOff = nBlockXOff * nBlockXSize,
451 1 : nYOff = nBlockYOff * nBlockYSize,
452 1 : nXSize = nBlockXSize,
453 1 : nYSize = nBlockYSize;
454 :
455 1 : if( nXOff + nXSize > nRasterXSize )
456 0 : nXSize = nRasterXSize - nXOff;
457 1 : if( nYOff + nYSize > nRasterYSize )
458 0 : nYSize = nRasterYSize - nYOff;
459 :
460 1 : int nPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
461 1 : int nLineSpace = nPixelSpace * nBlockXSize;
462 : return IRasterIO( GF_Read,
463 : nXOff, nYOff, nXSize, nYSize,
464 : pImage, nXSize, nYSize,
465 1 : eDataType, nPixelSpace, nLineSpace );
466 : }
467 :
468 : /************************************************************************/
469 : /* ==================================================================== */
470 : /* ECWDataset */
471 : /* ==================================================================== */
472 : /************************************************************************/
473 :
474 :
475 : /************************************************************************/
476 : /* ECWDataset() */
477 : /************************************************************************/
478 :
479 68 : ECWDataset::ECWDataset(int bIsJPEG2000)
480 :
481 : {
482 68 : this->bIsJPEG2000 = bIsJPEG2000;
483 68 : bUsingCustomStream = FALSE;
484 68 : pszProjection = NULL;
485 68 : poFileView = NULL;
486 68 : bWinActive = FALSE;
487 68 : panWinBandList = NULL;
488 68 : eRasterDataType = GDT_Byte;
489 68 : nGCPCount = 0;
490 68 : pasGCPList = NULL;
491 68 : papszGMLMetadata = NULL;
492 :
493 68 : bGeoTransformValid = FALSE;
494 68 : adfGeoTransform[0] = 0.0;
495 68 : adfGeoTransform[1] = 1.0;
496 68 : adfGeoTransform[2] = 0.0;
497 68 : adfGeoTransform[3] = 0.0;
498 68 : adfGeoTransform[4] = 0.0;
499 68 : adfGeoTransform[5] = 1.0;
500 :
501 68 : bHdrDirty = FALSE;
502 68 : bGeoTransformChanged = FALSE;
503 68 : bProjectionChanged = FALSE;
504 68 : bProjCodeChanged = FALSE;
505 68 : bDatumCodeChanged = FALSE;
506 68 : bUnitsCodeChanged = FALSE;
507 :
508 68 : bUseOldBandRasterIOImplementation = FALSE;
509 :
510 68 : poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
511 68 : }
512 :
513 : /************************************************************************/
514 : /* ~ECWDataset() */
515 : /************************************************************************/
516 :
517 68 : ECWDataset::~ECWDataset()
518 :
519 : {
520 68 : FlushCache();
521 68 : CleanupWindow();
522 :
523 : /* -------------------------------------------------------------------- */
524 : /* Release / dereference iostream. */
525 : /* -------------------------------------------------------------------- */
526 : // The underlying iostream of the CNCSJP2FileView (poFileView) object may
527 : // also be the underlying iostream of other CNCSJP2FileView (poFileView)
528 : // objects. Consequently, when we delete the CNCSJP2FileView (poFileView)
529 : // object, we must decrement the nFileViewCount attribute of the underlying
530 : // VSIIOStream object, and only delete the VSIIOStream object when
531 : // nFileViewCount is equal to zero.
532 :
533 68 : CPLMutexHolder oHolder( &hECWDatasetMutex );
534 :
535 68 : if( poFileView != NULL )
536 : {
537 68 : VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
538 :
539 68 : poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
540 68 : delete poFileView;
541 :
542 68 : if( bUsingCustomStream )
543 : {
544 15 : if( --poUnderlyingIOStream->nFileViewCount == 0 )
545 15 : delete poUnderlyingIOStream;
546 : }
547 : }
548 :
549 : /* WriteHeader() must be called after closing the file handle to work */
550 : /* on Windows */
551 68 : if( bHdrDirty )
552 3 : WriteHeader();
553 :
554 68 : CPLFree( pszProjection );
555 68 : CSLDestroy( papszGMLMetadata );
556 :
557 68 : if( nGCPCount > 0 )
558 : {
559 4 : GDALDeinitGCPs( nGCPCount, pasGCPList );
560 4 : CPLFree( pasGCPList );
561 68 : }
562 68 : }
563 :
564 : /************************************************************************/
565 : /* SetGeoTransform() */
566 : /************************************************************************/
567 :
568 6 : CPLErr ECWDataset::SetGeoTransform( double * padfGeoTransform )
569 : {
570 6 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
571 5 : return GDALPamDataset::SetGeoTransform(padfGeoTransform);
572 :
573 2 : if ( !bGeoTransformValid ||
574 1 : adfGeoTransform[0] != padfGeoTransform[0] ||
575 0 : adfGeoTransform[1] != padfGeoTransform[1] ||
576 0 : adfGeoTransform[2] != padfGeoTransform[2] ||
577 0 : adfGeoTransform[3] != padfGeoTransform[3] ||
578 0 : adfGeoTransform[4] != padfGeoTransform[4] ||
579 0 : adfGeoTransform[5] != padfGeoTransform[5] )
580 : {
581 1 : memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
582 1 : bGeoTransformValid = TRUE;
583 1 : bHdrDirty = TRUE;
584 1 : bGeoTransformChanged = TRUE;
585 : }
586 :
587 1 : return CE_None;
588 : }
589 :
590 : /************************************************************************/
591 : /* SetProjection() */
592 : /************************************************************************/
593 :
594 6 : CPLErr ECWDataset::SetProjection( const char* pszProjectionIn )
595 : {
596 6 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
597 5 : return GDALPamDataset::SetProjection(pszProjectionIn);
598 :
599 1 : if ( !( (pszProjection == NULL && pszProjectionIn == NULL) ||
600 : (pszProjection != NULL && pszProjectionIn != NULL &&
601 : strcmp(pszProjection, pszProjectionIn) == 0) ) )
602 : {
603 1 : CPLFree(pszProjection);
604 1 : pszProjection = pszProjectionIn ? CPLStrdup(pszProjectionIn) : NULL;
605 1 : bHdrDirty = TRUE;
606 1 : bProjectionChanged = TRUE;
607 : }
608 :
609 1 : return CE_None;
610 : }
611 :
612 : /************************************************************************/
613 : /* SetMetadataItem() */
614 : /************************************************************************/
615 :
616 3 : CPLErr ECWDataset::SetMetadataItem( const char * pszName,
617 : const char * pszValue,
618 : const char * pszDomain )
619 : {
620 3 : if ( !bIsJPEG2000 && eAccess == GA_Update &&
621 : (pszDomain == NULL || EQUAL(pszDomain, "") ||
622 : (pszDomain != NULL && EQUAL(pszDomain, "ECW"))) &&
623 : pszName != NULL &&
624 : (strcmp(pszName, "PROJ") == 0 || strcmp( pszName, "DATUM") == 0 ||
625 : strcmp( pszName, "UNITS") == 0 ) )
626 : {
627 3 : CPLString osNewVal = pszValue ? pszValue : "";
628 3 : if (osNewVal.size() > 31)
629 0 : osNewVal.resize(31);
630 3 : if (strcmp(pszName, "PROJ") == 0)
631 : {
632 1 : bProjCodeChanged = (osNewVal != m_osProjCode);
633 1 : m_osProjCode = osNewVal;
634 1 : bHdrDirty |= bProjCodeChanged;
635 : }
636 2 : else if (strcmp( pszName, "DATUM") == 0)
637 : {
638 1 : bDatumCodeChanged |= (osNewVal != m_osDatumCode);
639 1 : m_osDatumCode = osNewVal;
640 1 : bHdrDirty |= bDatumCodeChanged;
641 : }
642 : else
643 : {
644 1 : bUnitsCodeChanged |= (osNewVal != m_osUnitsCode);
645 1 : m_osUnitsCode = osNewVal;
646 1 : bHdrDirty |= bUnitsCodeChanged;
647 : }
648 3 : return CE_None;
649 : }
650 : else
651 0 : return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
652 : }
653 :
654 : /************************************************************************/
655 : /* SetMetadata() */
656 : /************************************************************************/
657 :
658 15 : CPLErr ECWDataset::SetMetadata( char ** papszMetadata,
659 : const char * pszDomain )
660 : {
661 15 : if ( (pszDomain == NULL || EQUAL(pszDomain, "") || EQUAL(pszDomain, "ECW")) &&
662 : (CSLFetchNameValue(papszMetadata, "PROJ") != NULL ||
663 : CSLFetchNameValue(papszMetadata, "DATUM") != NULL ||
664 : CSLFetchNameValue(papszMetadata, "UNITS") != NULL) )
665 : {
666 0 : CPLStringList osNewMetadata;
667 0 : char** papszIter = papszMetadata;
668 0 : while(*papszIter)
669 : {
670 0 : if (strncmp(*papszIter, "PROJ=", 5) == 0 ||
671 : strncmp(*papszIter, "DATUM=", 6) == 0 ||
672 : strncmp(*papszIter, "UNITS=", 6) == 0)
673 : {
674 0 : char* pszKey = NULL;
675 0 : const char* pszValue = CPLParseNameValue(*papszIter, &pszKey );
676 0 : SetMetadataItem(pszKey, pszValue, pszDomain);
677 0 : CPLFree(pszKey);
678 : }
679 : else
680 0 : osNewMetadata.AddString(*papszIter);
681 0 : papszIter ++;
682 : }
683 0 : if (osNewMetadata.size() != 0)
684 0 : return GDALPamDataset::SetMetadata(osNewMetadata.List(), pszDomain);
685 : else
686 0 : return CE_None;
687 : }
688 : else
689 15 : return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
690 : }
691 :
692 : /************************************************************************/
693 : /* WriteHeader() */
694 : /************************************************************************/
695 :
696 3 : void ECWDataset::WriteHeader()
697 : {
698 3 : if (!bHdrDirty)
699 0 : return;
700 :
701 3 : CPLAssert(eAccess == GA_Update);
702 3 : CPLAssert(!bIsJPEG2000);
703 :
704 3 : bHdrDirty = FALSE;
705 :
706 3 : NCSEcwEditInfo *psEditInfo = NULL;
707 : NCSError eErr;
708 :
709 : /* Load original header info */
710 : #if ECWSDK_VERSION<50
711 3 : eErr = NCSEcwEditReadInfo((char*) GetDescription(), &psEditInfo);
712 : #else
713 : eErr = NCSEcwEditReadInfo( NCS::CString::Utf8Decode(GetDescription()).c_str(), &psEditInfo);
714 : #endif
715 3 : if (eErr != NCS_SUCCESS)
716 : {
717 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditReadInfo() failed");
718 0 : return;
719 : }
720 :
721 : /* To avoid potential cross-heap issues, we keep the original */
722 : /* strings, and restore them before freeing the structure */
723 3 : char* pszOriginalCode = psEditInfo->szDatum;
724 3 : char* pszOriginalProj = psEditInfo->szProjection;
725 :
726 : /* Alter the structure with user modified information */
727 : char szProjCode[32], szDatumCode[32], szUnits[32];
728 3 : if (bProjectionChanged)
729 : {
730 1 : if (ECWTranslateFromWKT( pszProjection, szProjCode, sizeof(szProjCode),
731 : szDatumCode, sizeof(szDatumCode), szUnits ) )
732 : {
733 1 : psEditInfo->szDatum = szDatumCode;
734 1 : psEditInfo->szProjection = szProjCode;
735 1 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
736 1 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
737 1 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
738 : CPLDebug("ECW", "Rewrite UNITS : %s",
739 1 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
740 : }
741 : }
742 :
743 3 : if (bDatumCodeChanged)
744 : {
745 1 : psEditInfo->szDatum = (char*) ((m_osDatumCode.size()) ? m_osDatumCode.c_str() : "RAW");
746 1 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
747 : }
748 3 : if (bProjCodeChanged)
749 : {
750 1 : psEditInfo->szProjection = (char*) ((m_osProjCode.size()) ? m_osProjCode.c_str() : "RAW");
751 1 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
752 : }
753 3 : if (bUnitsCodeChanged)
754 : {
755 1 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(m_osUnitsCode.c_str());
756 : CPLDebug("ECW", "Rewrite UNITS : %s",
757 1 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
758 : }
759 :
760 3 : if (bGeoTransformChanged)
761 : {
762 1 : psEditInfo->fOriginX = adfGeoTransform[0];
763 1 : psEditInfo->fCellIncrementX = adfGeoTransform[1];
764 1 : psEditInfo->fOriginY = adfGeoTransform[3];
765 1 : psEditInfo->fCellIncrementY = adfGeoTransform[5];
766 1 : CPLDebug("ECW", "Rewrite Geotransform");
767 : }
768 :
769 : /* Write modified header info */
770 : #if ECWSDK_VERSION<50
771 3 : eErr = NCSEcwEditWriteInfo((char*) GetDescription(), psEditInfo, NULL, NULL, NULL);
772 : #else
773 : eErr = NCSEcwEditWriteInfo( NCS::CString::Utf8Decode(GetDescription()).c_str(), psEditInfo, NULL, NULL, NULL);
774 : #endif
775 3 : if (eErr != NCS_SUCCESS)
776 : {
777 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditWriteInfo() failed");
778 : }
779 :
780 : /* Restore original pointers before free'ing */
781 3 : psEditInfo->szDatum = pszOriginalCode;
782 3 : psEditInfo->szProjection = pszOriginalProj;
783 :
784 3 : NCSEcwEditFreeInfo(psEditInfo);
785 : }
786 :
787 : /************************************************************************/
788 : /* AdviseRead() */
789 : /************************************************************************/
790 :
791 32 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
792 : int nBufXSize, int nBufYSize,
793 : GDALDataType eDT,
794 : int nBandCount, int *panBandList,
795 : char **papszOptions )
796 :
797 : {
798 32 : int *panAdjustedBandList = NULL;
799 :
800 : CPLDebug( "ECW",
801 : "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
802 32 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
803 :
804 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
805 32 : if( nBufXSize > nXSize || nBufYSize > nYSize )
806 : {
807 : CPLError( CE_Warning, CPLE_AppDefined,
808 : "Supersampling not directly supported by ECW toolkit,\n"
809 0 : "ignoring AdviseRead() request." );
810 0 : return CE_Warning;
811 : }
812 : #endif
813 :
814 : /* -------------------------------------------------------------------- */
815 : /* Adjust band numbers to be zero based. */
816 : /* -------------------------------------------------------------------- */
817 : panAdjustedBandList = (int *)
818 32 : CPLMalloc(sizeof(int) * nBandCount );
819 66 : for( int ii= 0; ii < nBandCount; ii++ )
820 34 : panAdjustedBandList[ii] = panBandList[ii] - 1;
821 :
822 : /* -------------------------------------------------------------------- */
823 : /* Cleanup old window cache information. */
824 : /* -------------------------------------------------------------------- */
825 32 : CleanupWindow();
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Set the new requested window. */
829 : /* -------------------------------------------------------------------- */
830 32 : CNCSError oErr;
831 :
832 : oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList,
833 : nXOff, nYOff,
834 : nXOff + nXSize-1, nYOff + nYSize-1,
835 32 : nBufXSize, nBufYSize );
836 :
837 32 : CPLFree( panAdjustedBandList );
838 32 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
839 : {
840 0 : ECWReportError(oErr);
841 :
842 0 : bWinActive = FALSE;
843 0 : return CE_Failure;
844 : }
845 :
846 32 : bWinActive = TRUE;
847 :
848 : /* -------------------------------------------------------------------- */
849 : /* Record selected window. */
850 : /* -------------------------------------------------------------------- */
851 32 : nWinXOff = nXOff;
852 32 : nWinYOff = nYOff;
853 32 : nWinXSize = nXSize;
854 32 : nWinYSize = nYSize;
855 32 : nWinBufXSize = nBufXSize;
856 32 : nWinBufYSize = nBufYSize;
857 :
858 32 : panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
859 32 : memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
860 32 : nWinBandCount = nBandCount;
861 :
862 32 : nWinBufLoaded = -1;
863 :
864 : /* -------------------------------------------------------------------- */
865 : /* Allocate current scanline buffer. */
866 : /* -------------------------------------------------------------------- */
867 32 : papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
868 66 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
869 34 : papCurLineBuf[iBand] =
870 34 : CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
871 :
872 32 : return CE_None;
873 : }
874 :
875 : /************************************************************************/
876 : /* TryWinRasterIO() */
877 : /* */
878 : /* Try to satisfy the given request based on the currently */
879 : /* defined window. Return TRUE on success or FALSE on */
880 : /* failure. On failure, the caller should satisfy the request */
881 : /* another way (not report an error). */
882 : /************************************************************************/
883 :
884 13178 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag,
885 : int nXOff, int nYOff, int nXSize, int nYSize,
886 : GByte *pabyData, int nBufXSize, int nBufYSize,
887 : GDALDataType eDT,
888 : int nBandCount, int *panBandList,
889 : int nPixelSpace, int nLineSpace,
890 : int nBandSpace )
891 :
892 : {
893 : int iBand, i;
894 :
895 : /* -------------------------------------------------------------------- */
896 : /* Provide default buffer organization. */
897 : /* -------------------------------------------------------------------- */
898 13178 : if( nPixelSpace == 0 )
899 0 : nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
900 13178 : if( nLineSpace == 0 )
901 0 : nLineSpace = nPixelSpace * nBufXSize;
902 13178 : if( nBandSpace == 0 )
903 1 : nBandSpace = nLineSpace * nBufYSize;
904 :
905 : /* -------------------------------------------------------------------- */
906 : /* Do some simple tests to see if the current window can */
907 : /* satisfy our requirement. */
908 : /* -------------------------------------------------------------------- */
909 : #ifdef NOISY_DEBUG
910 : CPLDebug( "ECW", "TryWinRasterIO(%d,%d,%d,%d,%d,%d)",
911 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
912 : #endif
913 :
914 13178 : if( !bWinActive )
915 48 : return FALSE;
916 :
917 13130 : if( nXOff != nWinXOff || nXSize != nWinXSize )
918 0 : return FALSE;
919 :
920 13130 : if( nBufXSize != nWinBufXSize )
921 0 : return FALSE;
922 :
923 27052 : for( iBand = 0; iBand < nBandCount; iBand++ )
924 : {
925 15138 : for( i = 0; i < nWinBandCount; i++ )
926 : {
927 15130 : if( panWinBandList[i] == panBandList[iBand] )
928 13922 : break;
929 : }
930 :
931 13930 : if( i == nWinBandCount )
932 8 : return FALSE;
933 : }
934 :
935 13122 : if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
936 0 : return FALSE;
937 :
938 : /* -------------------------------------------------------------------- */
939 : /* Now we try more subtle tests. */
940 : /* -------------------------------------------------------------------- */
941 : {
942 : static int nDebugCount = 0;
943 :
944 13122 : if( nDebugCount < 30 )
945 : CPLDebug( "ECW",
946 : "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.",
947 30 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
948 :
949 13122 : if( nDebugCount == 29 )
950 1 : CPLDebug( "ECW", "No more TryWinRasterIO messages will be reported" );
951 :
952 13122 : nDebugCount++;
953 : }
954 :
955 : /* -------------------------------------------------------------------- */
956 : /* Actually load data one buffer line at a time. */
957 : /* -------------------------------------------------------------------- */
958 : int iBufLine;
959 :
960 26244 : for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
961 : {
962 13122 : double fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
963 : int iWinLine =
964 13122 : (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
965 :
966 13122 : if( iWinLine == nWinBufLoaded + 1 )
967 13122 : LoadNextLine();
968 :
969 13122 : if( iWinLine != nWinBufLoaded )
970 0 : return FALSE;
971 :
972 : /* -------------------------------------------------------------------- */
973 : /* Copy out all our target bands. */
974 : /* -------------------------------------------------------------------- */
975 : int iWinBand;
976 27044 : for( iBand = 0; iBand < nBandCount; iBand++ )
977 : {
978 15122 : for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
979 : {
980 15122 : if( panWinBandList[iWinBand] == panBandList[iBand] )
981 13922 : break;
982 : }
983 :
984 : GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
985 : GDALGetDataTypeSize( eRasterDataType ) / 8,
986 : pabyData + nBandSpace * iBand
987 : + iBufLine * nLineSpace, eDT, nPixelSpace,
988 13922 : nBufXSize );
989 : }
990 : }
991 :
992 13122 : return TRUE;
993 : }
994 :
995 : /************************************************************************/
996 : /* LoadNextLine() */
997 : /************************************************************************/
998 :
999 13122 : CPLErr ECWDataset::LoadNextLine()
1000 :
1001 : {
1002 13122 : if( !bWinActive )
1003 0 : return CE_Failure;
1004 :
1005 13122 : if( nWinBufLoaded == nWinBufYSize-1 )
1006 : {
1007 0 : CleanupWindow();
1008 0 : return CE_Failure;
1009 : }
1010 :
1011 : NCSEcwReadStatus eRStatus;
1012 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
1013 : (UINT16) nWinBandCount,
1014 13122 : papCurLineBuf );
1015 13122 : if( eRStatus != NCSECW_READ_OK )
1016 0 : return CE_Failure;
1017 :
1018 13122 : nWinBufLoaded++;
1019 :
1020 13122 : return CE_None;
1021 : }
1022 :
1023 : /************************************************************************/
1024 : /* CleanupWindow() */
1025 : /************************************************************************/
1026 :
1027 123 : void ECWDataset::CleanupWindow()
1028 :
1029 : {
1030 123 : if( !bWinActive )
1031 91 : return;
1032 :
1033 32 : bWinActive = FALSE;
1034 32 : CPLFree( panWinBandList );
1035 32 : panWinBandList = NULL;
1036 :
1037 66 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
1038 34 : CPLFree( papCurLineBuf[iBand] );
1039 32 : CPLFree( papCurLineBuf );
1040 32 : papCurLineBuf = NULL;
1041 : }
1042 :
1043 : /************************************************************************/
1044 : /* IRasterIO() */
1045 : /************************************************************************/
1046 :
1047 13146 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
1048 : int nXOff, int nYOff, int nXSize, int nYSize,
1049 : void * pData, int nBufXSize, int nBufYSize,
1050 : GDALDataType eBufType,
1051 : int nBandCount, int *panBandMap,
1052 : int nPixelSpace, int nLineSpace, int nBandSpace)
1053 :
1054 : {
1055 13146 : if( nBandCount > 100 )
1056 0 : return CE_Failure;
1057 :
1058 13146 : if( bUseOldBandRasterIOImplementation )
1059 : /* Sanity check. Shouldn't happen */
1060 0 : return CE_Failure;
1061 :
1062 : /* -------------------------------------------------------------------- */
1063 : /* ECW SDK 3.3 has a bug with the ECW format when we query the */
1064 : /* number of bands of the dataset, but not in the "natural order". */
1065 : /* It ignores the content of panBandMap. (#4234) */
1066 : /* -------------------------------------------------------------------- */
1067 : #if ECWSDK_VERSION < 40
1068 13146 : if( !bIsJPEG2000 && nBandCount == nBands )
1069 : {
1070 : int i;
1071 405 : int bDoBandIRasterIO = FALSE;
1072 1620 : for( i = 0; i < nBandCount; i++ )
1073 : {
1074 1215 : if( panBandMap[i] != i + 1 )
1075 : {
1076 2 : bDoBandIRasterIO = TRUE;
1077 : }
1078 : }
1079 405 : if( bDoBandIRasterIO )
1080 : {
1081 : return GDALDataset::IRasterIO(
1082 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
1083 : pData, nBufXSize, nBufYSize,
1084 : eBufType,
1085 : nBandCount, panBandMap,
1086 1 : nPixelSpace, nLineSpace, nBandSpace);
1087 : }
1088 : }
1089 : #endif
1090 :
1091 : /* -------------------------------------------------------------------- */
1092 : /* Try to do it based on existing "advised" access. */
1093 : /* -------------------------------------------------------------------- */
1094 13145 : if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1095 : (GByte *) pData, nBufXSize, nBufYSize,
1096 : eBufType, nBandCount, panBandMap,
1097 : nPixelSpace, nLineSpace, nBandSpace ) )
1098 13090 : return CE_None;
1099 :
1100 : /* -------------------------------------------------------------------- */
1101 : /* If we are requesting a single line at 1:1, we do a multi-band */
1102 : /* AdviseRead() and then TryWinRasterIO() again. */
1103 : /* */
1104 : /* Except for reading a 1x1 window when reading a scanline might */
1105 : /* be longer. */
1106 : /* -------------------------------------------------------------------- */
1107 55 : if( nXSize == 1 && nYSize == 1 && nBufXSize == 1 && nBufYSize == 1 )
1108 : {
1109 : /* do nothing */
1110 : }
1111 :
1112 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
1113 : /* -------------------------------------------------------------------- */
1114 : /* If we are supersampling we need to fall into the general */
1115 : /* purpose logic. */
1116 : /* -------------------------------------------------------------------- */
1117 51 : else if( nXSize < nBufXSize || nYSize < nBufYSize )
1118 : {
1119 1 : bUseOldBandRasterIOImplementation = TRUE;
1120 : CPLErr eErr =
1121 : GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1122 : pData, nBufXSize, nBufYSize,
1123 : eBufType,
1124 : nBandCount, panBandMap,
1125 1 : nPixelSpace, nLineSpace, nBandSpace);
1126 1 : bUseOldBandRasterIOImplementation = FALSE;
1127 1 : return eErr;
1128 : }
1129 : #endif
1130 :
1131 50 : else if( nBufYSize == 1 )
1132 : {
1133 : //JTO: this is tricky, because it expects the rest of the image with this bufer width to be
1134 : //read. The prefered way to achieve this behaviour would be to call AdviseRead before call IRasterIO.
1135 : //ERO; indeed, the logic could be improved to detect successive pattern of single line reading
1136 : //before doing an AdviseRead.
1137 : CPLErr eErr;
1138 :
1139 : eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
1140 : nBufXSize, (nRasterYSize - nYOff) / nYSize, eBufType,
1141 32 : nBandCount, panBandMap, NULL );
1142 32 : if( eErr == CE_None
1143 : && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1144 : (GByte *) pData, nBufXSize, nBufYSize,
1145 : eBufType, nBandCount, panBandMap,
1146 : nPixelSpace, nLineSpace, nBandSpace ) )
1147 32 : return CE_None;
1148 : }
1149 :
1150 : CPLDebug( "ECW",
1151 : "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.",
1152 22 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1153 :
1154 : /* -------------------------------------------------------------------- */
1155 : /* Setup view. */
1156 : /* -------------------------------------------------------------------- */
1157 : UINT32 anBandIndices[100];
1158 : int i;
1159 : NCSError eNCSErr;
1160 22 : CNCSError oErr;
1161 :
1162 54 : for( i = 0; i < nBandCount; i++ )
1163 32 : anBandIndices[i] = panBandMap[i] - 1;
1164 :
1165 22 : CleanupWindow();
1166 :
1167 : oErr = poFileView->SetView( nBandCount, anBandIndices,
1168 : nXOff, nYOff,
1169 : nXOff + nXSize - 1,
1170 : nYOff + nYSize - 1,
1171 22 : nBufXSize, nBufYSize );
1172 22 : eNCSErr = oErr.GetErrorNumber();
1173 :
1174 22 : if( eNCSErr != NCS_SUCCESS )
1175 : {
1176 : CPLError( CE_Failure, CPLE_AppDefined,
1177 0 : "%s", NCSGetErrorText(eNCSErr) );
1178 :
1179 0 : return CE_Failure;
1180 : }
1181 :
1182 : return ReadBands(pData, nBufXSize, nBufYSize, eBufType,
1183 22 : nBandCount, nPixelSpace, nLineSpace, nBandSpace);
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* ReadBandsDirectly() */
1188 : /************************************************************************/
1189 :
1190 21 : CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
1191 : GDALDataType eBufType,
1192 : int nBandCount,
1193 : int nPixelSpace, int nLineSpace, int nBandSpace)
1194 : {
1195 : CPLDebug( "ECW",
1196 : "ReadBandsDirectly(-> %dx%d) - reading lines directly.",
1197 21 : nBufXSize, nBufYSize);
1198 :
1199 21 : CPLErr eErr = CE_None;
1200 21 : UINT8 **pBIL = (UINT8**)NCSMalloc(nBandCount * sizeof(UINT8*), FALSE);
1201 21 : UINT32 *pBandList = (UINT32*)NCSMalloc(nBandCount * sizeof(UINT32), FALSE);
1202 21 : int iBandSpace = nPixelSpace*nBufXSize*nBufYSize;
1203 50 : for(int nB = 0; nB < nBandCount; nB++)
1204 : {
1205 29 : pBIL[nB] = ((UINT8*)pData) + (iBandSpace*nB);//for any bit depth
1206 29 : pBandList[nB] = nB;
1207 : }
1208 :
1209 5293 : for(int nR = 0; nR < nBufYSize; nR++)
1210 : {
1211 5272 : if (poFileView->ReadLineBIL(eNCSRequestDataType, nBandCount, (void**)pBIL) != NCSECW_READ_OK)
1212 : {
1213 0 : eErr = CE_Failure;
1214 0 : break;
1215 : }
1216 12146 : for(int nB = 0; nB < nBandCount; nB++)
1217 : {
1218 6874 : pBIL[nB] += nLineSpace;
1219 : }
1220 : }
1221 21 : if(pBIL)
1222 : {
1223 21 : NCSFree(pBIL);
1224 : }
1225 21 : if(pBandList)
1226 : {
1227 21 : NCSFree(pBandList);
1228 : }
1229 21 : return eErr;
1230 : }
1231 :
1232 : /************************************************************************/
1233 : /* ReadBands() */
1234 : /************************************************************************/
1235 :
1236 22 : CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
1237 : GDALDataType eBufType,
1238 : int nBandCount,
1239 : int nPixelSpace, int nLineSpace, int nBandSpace)
1240 : {
1241 : int i;
1242 : /* -------------------------------------------------------------------- */
1243 : /* Setup working scanline, and the pointers into it. */
1244 : /* -------------------------------------------------------------------- */
1245 22 : int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
1246 22 : bool bDirect = (eBufType == eRasterDataType && nDataTypeSize == nPixelSpace);
1247 22 : if (bDirect)
1248 : {
1249 : return ReadBandsDirectly(pData, nBufXSize, nBufYSize, eBufType,
1250 21 : nBandCount, nPixelSpace, nLineSpace, nBandSpace);
1251 : }
1252 : CPLDebug( "ECW",
1253 : "ReadBands(-> %dx%d) - reading lines using GDALCopyWords.",
1254 1 : nBufXSize, nBufYSize);
1255 :
1256 1 : CPLErr eErr = CE_None;
1257 : GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
1258 1 : nBandCount);
1259 1 : GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
1260 :
1261 4 : for( i = 0; i < nBandCount; i++ )
1262 3 : papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
1263 :
1264 : /* -------------------------------------------------------------------- */
1265 : /* Read back all the data for the requested view. */
1266 : /* -------------------------------------------------------------------- */
1267 41 : for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
1268 : {
1269 : NCSEcwReadStatus eRStatus;
1270 :
1271 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
1272 : (UINT16) nBandCount,
1273 40 : (void **) papabyBIL );
1274 40 : if( eRStatus != NCSECW_READ_OK )
1275 : {
1276 0 : eErr = CE_Failure;
1277 : CPLError( CE_Failure, CPLE_AppDefined,
1278 0 : "NCScbmReadViewLineBIL failed." );
1279 0 : break;
1280 : }
1281 :
1282 160 : for( i = 0; i < nBandCount; i++ )
1283 : {
1284 : GDALCopyWords(
1285 : pabyBILScanline + i * nDataTypeSize * nBufXSize,
1286 : eRasterDataType, nDataTypeSize,
1287 : ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i,
1288 : eBufType, nPixelSpace,
1289 120 : nBufXSize );
1290 : }
1291 : }
1292 :
1293 1 : CPLFree( pabyBILScanline );
1294 1 : CPLFree( papabyBIL );
1295 :
1296 1 : return eErr;
1297 : }
1298 :
1299 : /************************************************************************/
1300 : /* IdentifyJPEG2000() */
1301 : /* */
1302 : /* Open method that only supports JPEG2000 files. */
1303 : /************************************************************************/
1304 :
1305 12036 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
1306 :
1307 : {
1308 12036 : if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
1309 0 : return TRUE;
1310 :
1311 12036 : else if( poOpenInfo->nHeaderBytes >= 16
1312 : && (memcmp( poOpenInfo->pabyHeader, jpc_header,
1313 : sizeof(jpc_header) ) == 0
1314 : || memcmp( poOpenInfo->pabyHeader, jp2_header,
1315 : sizeof(jp2_header) ) == 0) )
1316 45 : return TRUE;
1317 :
1318 : else
1319 11991 : return FALSE;
1320 : }
1321 :
1322 : /************************************************************************/
1323 : /* OpenJPEG2000() */
1324 : /* */
1325 : /* Open method that only supports JPEG2000 files. */
1326 : /************************************************************************/
1327 :
1328 1963 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
1329 :
1330 : {
1331 1963 : if (!IdentifyJPEG2000(poOpenInfo))
1332 1918 : return NULL;
1333 :
1334 45 : return Open( poOpenInfo, TRUE );
1335 : }
1336 :
1337 : /************************************************************************/
1338 : /* IdentifyECW() */
1339 : /* */
1340 : /* Identify method that only supports ECW files. */
1341 : /************************************************************************/
1342 :
1343 12702 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
1344 :
1345 : {
1346 : /* -------------------------------------------------------------------- */
1347 : /* This has to either be a file on disk ending in .ecw or a */
1348 : /* ecwp: protocol url. */
1349 : /* -------------------------------------------------------------------- */
1350 12702 : if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
1351 : || poOpenInfo->nHeaderBytes == 0)
1352 : && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5)
1353 : && !EQUALN(poOpenInfo->pszFilename,"ecwps:",5) )
1354 12678 : return FALSE;
1355 :
1356 24 : return TRUE;
1357 : }
1358 :
1359 : /************************************************************************/
1360 : /* OpenECW() */
1361 : /* */
1362 : /* Open method that only supports ECW files. */
1363 : /************************************************************************/
1364 :
1365 2609 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
1366 :
1367 : {
1368 2609 : if (!IdentifyECW(poOpenInfo))
1369 2585 : return NULL;
1370 :
1371 24 : return Open( poOpenInfo, FALSE );
1372 : }
1373 :
1374 : /************************************************************************/
1375 : /* OpenFileView() */
1376 : /************************************************************************/
1377 :
1378 69 : CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
1379 : bool bProgressive,
1380 : int &bUsingCustomStream )
1381 :
1382 : {
1383 : /* -------------------------------------------------------------------- */
1384 : /* First we try to open it as a normal CNCSFile, letting the */
1385 : /* ECW SDK manage the IO itself. This will only work for real */
1386 : /* files, and ecwp: or ecwps: sources. */
1387 : /* -------------------------------------------------------------------- */
1388 69 : CNCSJP2FileView *poFileView = NULL;
1389 : NCSError eErr;
1390 69 : CNCSError oErr;
1391 :
1392 69 : bUsingCustomStream = FALSE;
1393 69 : poFileView = new CNCSFile();
1394 138 : oErr = poFileView->Open( (char *) pszDatasetName, bProgressive );
1395 69 : eErr = oErr.GetErrorNumber();
1396 :
1397 : /* -------------------------------------------------------------------- */
1398 : /* If that did not work, trying opening as a virtual file. */
1399 : /* -------------------------------------------------------------------- */
1400 69 : if( eErr != NCS_SUCCESS )
1401 : {
1402 : CPLDebug( "ECW",
1403 : "NCScbmOpenFileView(%s): eErr=%d, will try VSIL stream.",
1404 16 : pszDatasetName, (int) eErr );
1405 :
1406 16 : delete poFileView;
1407 :
1408 16 : VSILFILE *fpVSIL = VSIFOpenL( pszDatasetName, "rb" );
1409 16 : if( fpVSIL == NULL )
1410 : {
1411 : CPLError( CE_Failure, CPLE_OpenFailed,
1412 0 : "Failed to open %s.", pszDatasetName );
1413 0 : return NULL;
1414 : }
1415 :
1416 16 : if( hECWDatasetMutex == NULL )
1417 : {
1418 0 : hECWDatasetMutex = CPLCreateMutex();
1419 : }
1420 16 : else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
1421 : {
1422 0 : CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
1423 : }
1424 : else
1425 : {
1426 16 : CPLDebug( "ECW", "Got mutex." );
1427 : }
1428 16 : VSIIOStream *poIOStream = new VSIIOStream();
1429 32 : poIOStream->Access( fpVSIL, FALSE, pszDatasetName, 0, -1 );
1430 :
1431 16 : poFileView = new CNCSJP2FileView();
1432 32 : oErr = poFileView->Open( poIOStream, bProgressive );
1433 :
1434 : // The CNCSJP2FileView (poFileView) object may not use the iostream
1435 : // (poIOStream) passed to the CNCSJP2FileView::Open() method if an
1436 : // iostream is already available to the ECW JPEG 2000 SDK for a given
1437 : // file. Consequently, if the iostream passed to
1438 : // CNCSJP2FileView::Open() does not become the underlying iostream
1439 : // of the CNCSJP2FileView object, then it should be deleted.
1440 : //
1441 : // In addition, the underlying iostream of the CNCSJP2FileView object
1442 : // should not be deleted until all CNCSJP2FileView objects using the
1443 : // underlying iostream are deleted. Consequently, each time a
1444 : // CNCSJP2FileView object is created, the nFileViewCount attribute
1445 : // of the underlying VSIIOStream object must be incremented for use
1446 : // in the ECWDataset destructor.
1447 :
1448 : VSIIOStream * poUnderlyingIOStream =
1449 16 : ((VSIIOStream *)(poFileView->GetStream()));
1450 :
1451 16 : if ( poUnderlyingIOStream )
1452 15 : poUnderlyingIOStream->nFileViewCount++;
1453 :
1454 16 : if ( poIOStream != poUnderlyingIOStream )
1455 : {
1456 1 : delete poIOStream;
1457 : }
1458 : else
1459 : {
1460 15 : bUsingCustomStream = TRUE;
1461 : }
1462 :
1463 16 : CPLReleaseMutex( hECWDatasetMutex );
1464 :
1465 16 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
1466 : {
1467 1 : if (poFileView)
1468 1 : delete poFileView;
1469 1 : ECWReportError(oErr);
1470 :
1471 1 : return NULL;
1472 : }
1473 : }
1474 :
1475 68 : return poFileView;
1476 : }
1477 :
1478 : /************************************************************************/
1479 : /* Open() */
1480 : /************************************************************************/
1481 :
1482 69 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
1483 :
1484 : {
1485 69 : CNCSJP2FileView *poFileView = NULL;
1486 : int i;
1487 69 : int bUsingCustomStream = FALSE;
1488 69 : CPLString osFilename = poOpenInfo->pszFilename;
1489 :
1490 69 : ECWInitialize();
1491 :
1492 : /* -------------------------------------------------------------------- */
1493 : /* If we get a J2K_SUBFILE style name, convert it into the */
1494 : /* corresponding /vsisubfile/ path. */
1495 : /* */
1496 : /* From: J2K_SUBFILE:offset,size,filename */
1497 : /* To: /vsisubfile/offset_size,filename */
1498 : /* -------------------------------------------------------------------- */
1499 69 : if (EQUALN(osFilename,"J2K_SUBFILE:",12))
1500 : {
1501 0 : char** papszTokens = CSLTokenizeString2(osFilename.c_str()+12, ",", 0);
1502 0 : if (CSLCount(papszTokens) >= 2)
1503 : {
1504 : osFilename.Printf( "/vsisubfile/%s_%s,%s",
1505 0 : papszTokens[0], papszTokens[1], papszTokens[2]);
1506 : }
1507 : else
1508 : {
1509 : CPLError( CE_Failure, CPLE_OpenFailed,
1510 0 : "Failed to parse J2K_SUBFILE specification." );
1511 0 : CSLDestroy(papszTokens);
1512 0 : return NULL;
1513 : }
1514 0 : CSLDestroy(papszTokens);
1515 : }
1516 :
1517 : /* -------------------------------------------------------------------- */
1518 : /* Open the client interface. */
1519 : /* -------------------------------------------------------------------- */
1520 69 : poFileView = OpenFileView( osFilename, false, bUsingCustomStream );
1521 69 : if( poFileView == NULL )
1522 1 : return NULL;
1523 :
1524 : /* -------------------------------------------------------------------- */
1525 : /* Create a corresponding GDALDataset. */
1526 : /* -------------------------------------------------------------------- */
1527 : ECWDataset *poDS;
1528 :
1529 68 : poDS = new ECWDataset(bIsJPEG2000);
1530 68 : poDS->poFileView = poFileView;
1531 68 : poDS->eAccess = poOpenInfo->eAccess;
1532 :
1533 : // Disable .aux.xml writing for subfiles and such. Unfortunately
1534 : // this will also disable it in some cases where it might be
1535 : // applicable.
1536 68 : if( bUsingCustomStream )
1537 15 : poDS->nPamFlags |= GPF_DISABLED;
1538 :
1539 68 : poDS->bUsingCustomStream = bUsingCustomStream;
1540 :
1541 : /* -------------------------------------------------------------------- */
1542 : /* Fetch general file information. */
1543 : /* -------------------------------------------------------------------- */
1544 68 : poDS->psFileInfo = poFileView->GetFileInfo();
1545 :
1546 : CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
1547 : " OriginXY=%g,%g CellIncrementXY=%g,%g\n"
1548 : " ColorSpace=%d, eCellType=%d\n",
1549 : poDS->psFileInfo->nSizeX,
1550 : poDS->psFileInfo->nSizeY,
1551 : poDS->psFileInfo->nBands,
1552 : poDS->psFileInfo->fOriginX,
1553 : poDS->psFileInfo->fOriginY,
1554 : poDS->psFileInfo->fCellIncrementX,
1555 : poDS->psFileInfo->fCellIncrementY,
1556 : (int) poDS->psFileInfo->eColorSpace,
1557 68 : (int) poDS->psFileInfo->eCellType );
1558 :
1559 : /* -------------------------------------------------------------------- */
1560 : /* Establish raster info. */
1561 : /* -------------------------------------------------------------------- */
1562 68 : poDS->nRasterXSize = poDS->psFileInfo->nSizeX;
1563 68 : poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
1564 :
1565 : /* -------------------------------------------------------------------- */
1566 : /* Establish the GDAL data type that corresponds. A few NCS */
1567 : /* data types have no direct corresponding value in GDAL so we */
1568 : /* will coerce to something sufficiently similar. */
1569 : /* -------------------------------------------------------------------- */
1570 68 : poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
1571 68 : switch( poDS->psFileInfo->eCellType )
1572 : {
1573 : case NCSCT_UINT8:
1574 57 : poDS->eRasterDataType = GDT_Byte;
1575 57 : break;
1576 :
1577 : case NCSCT_UINT16:
1578 5 : poDS->eRasterDataType = GDT_UInt16;
1579 5 : break;
1580 :
1581 : case NCSCT_UINT32:
1582 : case NCSCT_UINT64:
1583 1 : poDS->eRasterDataType = GDT_UInt32;
1584 1 : poDS->eNCSRequestDataType = NCSCT_UINT32;
1585 1 : break;
1586 :
1587 : case NCSCT_INT8:
1588 : case NCSCT_INT16:
1589 3 : poDS->eRasterDataType = GDT_Int16;
1590 3 : poDS->eNCSRequestDataType = NCSCT_INT16;
1591 3 : break;
1592 :
1593 : case NCSCT_INT32:
1594 : case NCSCT_INT64:
1595 2 : poDS->eRasterDataType = GDT_Int32;
1596 2 : poDS->eNCSRequestDataType = NCSCT_INT32;
1597 2 : break;
1598 :
1599 : case NCSCT_IEEE4:
1600 0 : poDS->eRasterDataType = GDT_Float32;
1601 0 : break;
1602 :
1603 : case NCSCT_IEEE8:
1604 0 : poDS->eRasterDataType = GDT_Float64;
1605 : break;
1606 : }
1607 :
1608 : /* -------------------------------------------------------------------- */
1609 : /* Create band information objects. */
1610 : /* -------------------------------------------------------------------- */
1611 206 : for( i=0; i < poDS->psFileInfo->nBands; i++ )
1612 138 : poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
1613 :
1614 : /* -------------------------------------------------------------------- */
1615 : /* Look for supporting coordinate system information. */
1616 : /* -------------------------------------------------------------------- */
1617 68 : if( bIsJPEG2000 )
1618 : {
1619 45 : GDALJP2Metadata oJP2Geo;
1620 45 : if ( oJP2Geo.ReadAndParse( osFilename ) )
1621 : {
1622 25 : poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
1623 25 : poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
1624 : memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
1625 25 : sizeof(double) * 6 );
1626 25 : poDS->nGCPCount = oJP2Geo.nGCPCount;
1627 25 : poDS->pasGCPList = oJP2Geo.pasGCPList;
1628 25 : oJP2Geo.pasGCPList = NULL;
1629 25 : oJP2Geo.nGCPCount = 0;
1630 : }
1631 :
1632 45 : if (oJP2Geo.pszXMPMetadata)
1633 : {
1634 : char *apszMDList[2];
1635 1 : apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
1636 1 : apszMDList[1] = NULL;
1637 1 : poDS->SetMetadata(apszMDList, "xml:XMP");
1638 45 : }
1639 : }
1640 : else
1641 : {
1642 23 : poDS->ECW2WKTProjection();
1643 : }
1644 :
1645 : /* -------------------------------------------------------------------- */
1646 : /* Check for world file. */
1647 : /* -------------------------------------------------------------------- */
1648 68 : if( !poDS->bGeoTransformValid )
1649 : {
1650 : poDS->bGeoTransformValid |=
1651 : GDALReadWorldFile2( osFilename, NULL,
1652 : poDS->adfGeoTransform,
1653 : poOpenInfo->papszSiblingFiles, NULL )
1654 : || GDALReadWorldFile2( osFilename, ".wld",
1655 : poDS->adfGeoTransform,
1656 24 : poOpenInfo->papszSiblingFiles, NULL );
1657 : }
1658 :
1659 : /* -------------------------------------------------------------------- */
1660 : /* Initialize any PAM information. */
1661 : /* -------------------------------------------------------------------- */
1662 68 : poDS->SetDescription( osFilename );
1663 68 : poDS->TryLoadXML();
1664 :
1665 68 : return( poDS );
1666 : }
1667 :
1668 : /************************************************************************/
1669 : /* GetGCPCount() */
1670 : /************************************************************************/
1671 :
1672 7 : int ECWDataset::GetGCPCount()
1673 :
1674 : {
1675 7 : if( nGCPCount != 0 )
1676 3 : return nGCPCount;
1677 : else
1678 4 : return GDALPamDataset::GetGCPCount();
1679 : }
1680 :
1681 : /************************************************************************/
1682 : /* GetGCPProjection() */
1683 : /************************************************************************/
1684 :
1685 2 : const char *ECWDataset::GetGCPProjection()
1686 :
1687 : {
1688 2 : if( nGCPCount > 0 )
1689 2 : return pszProjection;
1690 : else
1691 0 : return GDALPamDataset::GetGCPProjection();
1692 : }
1693 :
1694 : /************************************************************************/
1695 : /* GetGCP() */
1696 : /************************************************************************/
1697 :
1698 3 : const GDAL_GCP *ECWDataset::GetGCPs()
1699 :
1700 : {
1701 3 : if( nGCPCount != 0 )
1702 2 : return pasGCPList;
1703 : else
1704 1 : return GDALPamDataset::GetGCPs();
1705 : }
1706 :
1707 : /************************************************************************/
1708 : /* GetProjectionRef() */
1709 : /* */
1710 : /* We let PAM coordinate system override the one stored inside */
1711 : /* our file. */
1712 : /************************************************************************/
1713 :
1714 43 : const char *ECWDataset::GetProjectionRef()
1715 :
1716 : {
1717 43 : const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
1718 :
1719 43 : if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
1720 28 : return pszProjection;
1721 : else
1722 15 : return pszPamPrj;
1723 : }
1724 :
1725 : /************************************************************************/
1726 : /* GetGeoTransform() */
1727 : /* */
1728 : /* Let the PAM geotransform override the native one if it is */
1729 : /* available. */
1730 : /************************************************************************/
1731 :
1732 29 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
1733 :
1734 : {
1735 29 : CPLErr eErr = GDALPamDataset::GetGeoTransform( padfTransform );
1736 :
1737 29 : if( eErr != CE_None && bGeoTransformValid )
1738 : {
1739 24 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1740 24 : return( CE_None );
1741 : }
1742 : else
1743 5 : return eErr;
1744 : }
1745 :
1746 : /************************************************************************/
1747 : /* GetMetadataItem() */
1748 : /************************************************************************/
1749 :
1750 14 : const char *ECWDataset::GetMetadataItem( const char * pszName,
1751 : const char * pszDomain )
1752 : {
1753 14 : if (!bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") && pszName != NULL)
1754 : {
1755 6 : if (EQUAL(pszName, "PROJ"))
1756 2 : return m_osProjCode.size() ? m_osProjCode.c_str() : "RAW";
1757 4 : if (EQUAL(pszName, "DATUM"))
1758 2 : return m_osDatumCode.size() ? m_osDatumCode.c_str() : "RAW";
1759 2 : if (EQUAL(pszName, "UNITS"))
1760 2 : return m_osUnitsCode.size() ? m_osUnitsCode.c_str() : "METERS";
1761 : }
1762 8 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
1763 : }
1764 :
1765 : /************************************************************************/
1766 : /* GetMetadata() */
1767 : /************************************************************************/
1768 :
1769 20 : char **ECWDataset::GetMetadata( const char *pszDomain )
1770 :
1771 : {
1772 20 : if( !bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") )
1773 : {
1774 0 : oECWMetadataList.Clear();
1775 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", GetMetadataItem("PROJ", "ECW")));
1776 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", GetMetadataItem("DATUM", "ECW")));
1777 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", GetMetadataItem("UNITS", "ECW")));
1778 0 : return oECWMetadataList.List();
1779 : }
1780 20 : else if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
1781 20 : return GDALPamDataset::GetMetadata( pszDomain );
1782 : else
1783 0 : return papszGMLMetadata;
1784 : }
1785 :
1786 : /************************************************************************/
1787 : /* ECW2WKTProjection() */
1788 : /* */
1789 : /* Set the dataset pszProjection string in OGC WKT format by */
1790 : /* looking up the ECW (GDT) coordinate system info in */
1791 : /* ecw_cs.dat support data file. */
1792 : /* */
1793 : /* This code is likely still broken in some circumstances. For */
1794 : /* instance, I haven't been careful about changing the linear */
1795 : /* projection parameters (false easting/northing) if the units */
1796 : /* is feet. Lots of cases missing here, and in ecw_cs.dat. */
1797 : /************************************************************************/
1798 :
1799 23 : void ECWDataset::ECW2WKTProjection()
1800 :
1801 : {
1802 23 : if( psFileInfo == NULL )
1803 0 : return;
1804 :
1805 : /* -------------------------------------------------------------------- */
1806 : /* Capture Geotransform. */
1807 : /* */
1808 : /* We will try to ignore the provided file information if it is */
1809 : /* origin (0,0) and pixel size (1,1). I think sometimes I have */
1810 : /* also seen pixel increments of 0 on invalid datasets. */
1811 : /* -------------------------------------------------------------------- */
1812 23 : if( psFileInfo->fOriginX != 0.0
1813 : || psFileInfo->fOriginY != 0.0
1814 : || (psFileInfo->fCellIncrementX != 0.0
1815 : && psFileInfo->fCellIncrementX != 1.0)
1816 : || (psFileInfo->fCellIncrementY != 0.0
1817 : && psFileInfo->fCellIncrementY != 1.0) )
1818 : {
1819 23 : bGeoTransformValid = TRUE;
1820 :
1821 23 : adfGeoTransform[0] = psFileInfo->fOriginX;
1822 23 : adfGeoTransform[1] = psFileInfo->fCellIncrementX;
1823 23 : adfGeoTransform[2] = 0.0;
1824 :
1825 23 : adfGeoTransform[3] = psFileInfo->fOriginY;
1826 23 : adfGeoTransform[4] = 0.0;
1827 23 : adfGeoTransform[5] = -fabs(psFileInfo->fCellIncrementY);
1828 : }
1829 :
1830 : /* -------------------------------------------------------------------- */
1831 : /* do we have projection and datum? */
1832 : /* -------------------------------------------------------------------- */
1833 23 : CPLString osUnits = ECWTranslateFromCellSizeUnits(psFileInfo->eCellSizeUnits);
1834 :
1835 : CPLDebug( "ECW", "projection=%s, datum=%s, units=%s",
1836 : psFileInfo->szProjection, psFileInfo->szDatum,
1837 23 : osUnits.c_str());
1838 :
1839 23 : if( EQUAL(psFileInfo->szProjection,"RAW") )
1840 : return;
1841 :
1842 : /* -------------------------------------------------------------------- */
1843 : /* Set projection if we have it. */
1844 : /* -------------------------------------------------------------------- */
1845 9 : OGRSpatialReference oSRS;
1846 :
1847 : /* For backward-compatible with previous behaviour. Should we only */
1848 : /* restrict to those 2 values ? */
1849 9 : if (psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_METERS &&
1850 : psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_FEET)
1851 0 : osUnits = ECWTranslateFromCellSizeUnits(ECW_CELL_UNITS_METERS);
1852 :
1853 9 : m_osDatumCode = psFileInfo->szDatum;
1854 9 : m_osProjCode = psFileInfo->szProjection;
1855 9 : m_osUnitsCode = osUnits;
1856 9 : if( oSRS.importFromERM( psFileInfo->szProjection,
1857 : psFileInfo->szDatum,
1858 : osUnits ) == OGRERR_NONE )
1859 : {
1860 9 : oSRS.exportToWkt( &pszProjection );
1861 : }
1862 :
1863 9 : CPLErrorReset(); /* see #4187 */
1864 : }
1865 :
1866 : /************************************************************************/
1867 : /* ECWTranslateFromWKT() */
1868 : /************************************************************************/
1869 :
1870 24 : int ECWTranslateFromWKT( const char *pszWKT,
1871 : char *pszProjection,
1872 : int nProjectionLen,
1873 : char *pszDatum,
1874 : int nDatumLen,
1875 : char *pszUnits)
1876 :
1877 : {
1878 24 : OGRSpatialReference oSRS;
1879 24 : char *pszWKTIn = (char *) pszWKT;
1880 :
1881 24 : strcpy( pszProjection, "RAW" );
1882 24 : strcpy( pszDatum, "RAW" );
1883 24 : strcpy( pszUnits, "METERS" );
1884 :
1885 24 : if( pszWKT == NULL || strlen(pszWKT) == 0 )
1886 1 : return FALSE;
1887 :
1888 23 : oSRS.importFromWkt( &pszWKTIn );
1889 :
1890 23 : if( oSRS.IsLocal() )
1891 0 : return TRUE;
1892 :
1893 : /* -------------------------------------------------------------------- */
1894 : /* Do we have an overall EPSG number for this coordinate system? */
1895 : /* -------------------------------------------------------------------- */
1896 23 : const char *pszAuthorityCode = NULL;
1897 23 : const char *pszAuthorityName = NULL;
1898 23 : UINT32 nEPSGCode = 0;
1899 :
1900 23 : if( oSRS.IsProjected() )
1901 : {
1902 6 : pszAuthorityCode = oSRS.GetAuthorityCode( "PROJCS" );
1903 6 : pszAuthorityName = oSRS.GetAuthorityName( "PROJCS" );
1904 : }
1905 17 : else if( oSRS.IsGeographic() )
1906 : {
1907 17 : pszAuthorityCode = oSRS.GetAuthorityCode( "GEOGCS" );
1908 17 : pszAuthorityName = oSRS.GetAuthorityName( "GEOGCS" );
1909 : }
1910 :
1911 23 : if( pszAuthorityName != NULL && EQUAL(pszAuthorityName,"EPSG")
1912 : && pszAuthorityCode != NULL && atoi(pszAuthorityCode) > 0 )
1913 18 : nEPSGCode = (UINT32) atoi(pszAuthorityCode);
1914 :
1915 23 : if( nEPSGCode != 0 )
1916 : {
1917 18 : char *pszEPSGProj = NULL, *pszEPSGDatum = NULL;
1918 18 : CNCSError oErr;
1919 :
1920 : oErr =
1921 : CNCSJP2FileView::GetProjectionAndDatum( atoi(pszAuthorityCode),
1922 18 : &pszEPSGProj, &pszEPSGDatum );
1923 :
1924 : CPLDebug( "ECW", "GetGDTProjDat(%d) = %s/%s",
1925 18 : atoi(pszAuthorityCode), pszEPSGProj, pszEPSGDatum );
1926 :
1927 18 : if( oErr.GetErrorNumber() == NCS_SUCCESS
1928 : && pszEPSGProj != NULL && pszEPSGDatum != NULL )
1929 : {
1930 18 : strncpy( pszProjection, pszEPSGProj, nProjectionLen );
1931 18 : strncpy( pszDatum, pszEPSGDatum, nDatumLen );
1932 18 : pszProjection[nProjectionLen - 1] = 0;
1933 18 : pszDatum[nDatumLen - 1] = 0;
1934 18 : NCSFree( pszEPSGProj );
1935 18 : NCSFree( pszEPSGDatum );
1936 18 : return TRUE;
1937 : }
1938 :
1939 0 : NCSFree( pszEPSGProj );
1940 0 : NCSFree( pszEPSGDatum );
1941 :
1942 : }
1943 :
1944 : /* -------------------------------------------------------------------- */
1945 : /* Fallback to translating based on the ecw_cs.wkt file, and */
1946 : /* various jiffy rules. */
1947 : /* -------------------------------------------------------------------- */
1948 :
1949 5 : return oSRS.exportToERM( pszProjection, pszDatum, pszUnits ) == OGRERR_NONE;
1950 : }
1951 :
1952 : /************************************************************************/
1953 : /* ECWTranslateToCellSizeUnits() */
1954 : /************************************************************************/
1955 :
1956 25 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits)
1957 : {
1958 25 : if (EQUAL(pszUnits, "METERS"))
1959 23 : return ECW_CELL_UNITS_METERS;
1960 2 : else if (EQUAL(pszUnits, "DEGREES"))
1961 0 : return ECW_CELL_UNITS_DEGREES;
1962 2 : else if (EQUAL(pszUnits, "FEET"))
1963 2 : return ECW_CELL_UNITS_FEET;
1964 0 : else if (EQUAL(pszUnits, "UNKNOWN"))
1965 0 : return ECW_CELL_UNITS_UNKNOWN;
1966 0 : else if (EQUAL(pszUnits, "INVALID"))
1967 0 : return ECW_CELL_UNITS_INVALID;
1968 : else
1969 : {
1970 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized value for UNITS : %s", pszUnits);
1971 0 : return ECW_CELL_UNITS_INVALID;
1972 : }
1973 : }
1974 :
1975 : /************************************************************************/
1976 : /* ECWTranslateFromCellSizeUnits() */
1977 : /************************************************************************/
1978 :
1979 49 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits)
1980 : {
1981 49 : if (eUnits == ECW_CELL_UNITS_METERS)
1982 45 : return "METERS";
1983 4 : else if (eUnits == ECW_CELL_UNITS_DEGREES)
1984 0 : return "DEGREES";
1985 4 : else if (eUnits == ECW_CELL_UNITS_FEET)
1986 4 : return "FEET";
1987 0 : else if (eUnits == ECW_CELL_UNITS_UNKNOWN)
1988 0 : return "UNKNOWN";
1989 : else
1990 0 : return "INVALID";
1991 : }
1992 :
1993 : #endif /* def FRMT_ecw */
1994 :
1995 : /************************************************************************/
1996 : /* ECWInitialize() */
1997 : /* */
1998 : /* Initialize NCS library. We try to defer this as late as */
1999 : /* possible since de-initializing it seems to be expensive/slow */
2000 : /* on some system. */
2001 : /************************************************************************/
2002 :
2003 119 : void ECWInitialize()
2004 :
2005 : {
2006 119 : CPLMutexHolder oHolder( &hECWDatasetMutex );
2007 :
2008 119 : if( bNCSInitialized )
2009 : return;
2010 :
2011 3 : NCSecwInit();
2012 3 : bNCSInitialized = TRUE;
2013 :
2014 : /* -------------------------------------------------------------------- */
2015 : /* This will disable automatic conversion of YCbCr to RGB by */
2016 : /* the toolkit. */
2017 : /* -------------------------------------------------------------------- */
2018 3 : if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
2019 0 : NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
2020 :
2021 : /* -------------------------------------------------------------------- */
2022 : /* Initialize cache memory limit. Default is apparently 1/4 RAM. */
2023 : /* -------------------------------------------------------------------- */
2024 : const char *pszEcwCacheSize =
2025 3 : CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
2026 3 : if( pszEcwCacheSize == NULL )
2027 3 : pszEcwCacheSize = CPLGetConfigOption("ECW_CACHE_MAXMEM",NULL);
2028 :
2029 3 : if( pszEcwCacheSize != NULL )
2030 0 : NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, (UINT32) atoi(pszEcwCacheSize) );
2031 :
2032 : /* -------------------------------------------------------------------- */
2033 : /* Allow configuration of a local cache based on configuration */
2034 : /* options. Setting the location turns things on. */
2035 : /* -------------------------------------------------------------------- */
2036 : const char *pszOpt;
2037 :
2038 : #if ECWSDK_VERSION >= 40
2039 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_SIZE_MB", NULL );
2040 : if( pszOpt )
2041 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_SIZE_MB, (INT32) atoi( pszOpt ) );
2042 :
2043 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_LOCATION", NULL );
2044 : if( pszOpt )
2045 : {
2046 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_LOCATION, pszOpt );
2047 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_ENABLED, (BOOLEAN) TRUE );
2048 : }
2049 : #endif
2050 :
2051 : /* -------------------------------------------------------------------- */
2052 : /* Various other configuration items. */
2053 : /* -------------------------------------------------------------------- */
2054 3 : pszOpt = CPLGetConfigOption( "ECWP_BLOCKING_TIME_MS", NULL );
2055 3 : if( pszOpt )
2056 : NCSecwSetConfig( NCSCFG_BLOCKING_TIME_MS,
2057 0 : (NCSTimeStampMs) atoi(pszOpt) );
2058 :
2059 : // I believe 10s means we wait for complete data back from
2060 : // ECWP almost all the time which is good for our blocking model.
2061 3 : pszOpt = CPLGetConfigOption( "ECWP_REFRESH_TIME_MS", "10000" );
2062 3 : if( pszOpt )
2063 : NCSecwSetConfig( NCSCFG_REFRESH_TIME_MS,
2064 3 : (NCSTimeStampMs) atoi(pszOpt) );
2065 :
2066 3 : pszOpt = CPLGetConfigOption( "ECW_TEXTURE_DITHER", NULL );
2067 3 : if( pszOpt )
2068 : NCSecwSetConfig( NCSCFG_TEXTURE_DITHER,
2069 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2070 :
2071 :
2072 3 : pszOpt = CPLGetConfigOption( "ECW_FORCE_FILE_REOPEN", NULL );
2073 3 : if( pszOpt )
2074 : NCSecwSetConfig( NCSCFG_FORCE_FILE_REOPEN,
2075 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2076 :
2077 3 : pszOpt = CPLGetConfigOption( "ECW_CACHE_MAXOPEN", NULL );
2078 3 : if( pszOpt )
2079 0 : NCSecwSetConfig( NCSCFG_CACHE_MAXOPEN, (UINT32) atoi(pszOpt) );
2080 :
2081 : #if ECWSDK_VERSION >= 40
2082 : pszOpt = CPLGetConfigOption( "ECW_AUTOGEN_J2I", NULL );
2083 : if( pszOpt )
2084 : NCSecwSetConfig( NCSCFG_JP2_AUTOGEN_J2I,
2085 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2086 :
2087 : pszOpt = CPLGetConfigOption( "ECW_OPTIMIZE_USE_NEAREST_NEIGHBOUR", NULL );
2088 : if( pszOpt )
2089 : NCSecwSetConfig( NCSCFG_OPTIMIZE_USE_NEAREST_NEIGHBOUR,
2090 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2091 :
2092 :
2093 : pszOpt = CPLGetConfigOption( "ECW_RESILIENT_DECODING", NULL );
2094 : if( pszOpt )
2095 : NCSecwSetConfig( NCSCFG_RESILIENT_DECODING,
2096 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2097 : #endif
2098 : }
2099 :
2100 : /************************************************************************/
2101 : /* GDALDeregister_ECW() */
2102 : /************************************************************************/
2103 :
2104 542 : void GDALDeregister_ECW( GDALDriver * )
2105 :
2106 : {
2107 : /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
2108 : /* Not worth it */
2109 : #ifdef notdef
2110 : if( bNCSInitialized )
2111 : {
2112 : bNCSInitialized = FALSE;
2113 : NCSecwShutdown();
2114 : }
2115 :
2116 : if( hECWDatasetMutex != NULL )
2117 : {
2118 : CPLDestroyMutex( hECWDatasetMutex );
2119 : hECWDatasetMutex = NULL;
2120 : }
2121 : #endif
2122 542 : }
2123 :
2124 : /************************************************************************/
2125 : /* GDALRegister_ECW() */
2126 : /************************************************************************/
2127 :
2128 : /* Needed for v4.3 and v5.0 */
2129 : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
2130 : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
2131 : #endif
2132 :
2133 582 : void GDALRegister_ECW()
2134 :
2135 : {
2136 : #ifdef FRMT_ecw
2137 : GDALDriver *poDriver;
2138 :
2139 582 : if (! GDAL_CHECK_VERSION("ECW driver"))
2140 0 : return;
2141 :
2142 582 : if( GDALGetDriverByName( "ECW" ) == NULL )
2143 : {
2144 561 : poDriver = new GDALDriver();
2145 :
2146 561 : poDriver->SetDescription( "ECW" );
2147 :
2148 561 : CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
2149 :
2150 : #ifdef NCS_ECWSDK_VERSION_STRING
2151 : osLongName += NCS_ECWSDK_VERSION_STRING;
2152 : #else
2153 561 : osLongName += "3.x";
2154 : #endif
2155 561 : osLongName += ")";
2156 :
2157 561 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2158 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2159 561 : "frmt_ecw.html" );
2160 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
2161 :
2162 561 : poDriver->pfnIdentify = ECWDataset::IdentifyECW;
2163 561 : poDriver->pfnOpen = ECWDataset::OpenECW;
2164 561 : poDriver->pfnUnloadDriver = GDALDeregister_ECW;
2165 : #ifdef HAVE_COMPRESS
2166 : // The create method seems not to work properly.
2167 : // poDriver->pfnCreate = ECWCreateECW;
2168 561 : poDriver->pfnCreateCopy = ECWCreateCopyECW;
2169 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2170 561 : "Byte" );
2171 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2172 : "<CreationOptionList>"
2173 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2174 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2175 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2176 :
2177 : #if ECWSDK_VERSION < 40
2178 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2179 : #else
2180 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2181 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2182 : #endif
2183 :
2184 : #if ECWSDK_VERSION >= 50
2185 : " <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW format version (2 or 3).' default='3'/>"
2186 : #endif
2187 :
2188 561 : "</CreationOptionList>" );
2189 : #else
2190 : /* In read-only mode, we support VirtualIO. This is not the case */
2191 : /* for ECWCreateCopyECW() */
2192 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2193 : #endif
2194 :
2195 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
2196 : }
2197 : #endif /* def FRMT_ecw */
2198 : }
2199 :
2200 : /************************************************************************/
2201 : /* GDALRegister_ECW_JP2ECW() */
2202 : /* */
2203 : /* This function exists so that when built as a plugin, there */
2204 : /* is a function that will register both drivers. */
2205 : /************************************************************************/
2206 :
2207 0 : void GDALRegister_ECW_JP2ECW()
2208 :
2209 : {
2210 0 : GDALRegister_ECW();
2211 0 : GDALRegister_JP2ECW();
2212 0 : }
2213 :
2214 : /************************************************************************/
2215 : /* ECWDatasetOpenJPEG2000() */
2216 : /************************************************************************/
2217 17 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
2218 : {
2219 17 : return ECWDataset::OpenJPEG2000(poOpenInfo);
2220 : }
2221 :
2222 : /************************************************************************/
2223 : /* GDALRegister_JP2ECW() */
2224 : /************************************************************************/
2225 582 : void GDALRegister_JP2ECW()
2226 :
2227 : {
2228 : #ifdef FRMT_ecw
2229 : GDALDriver *poDriver;
2230 :
2231 582 : if (! GDAL_CHECK_VERSION("JP2ECW driver"))
2232 0 : return;
2233 :
2234 582 : if( GDALGetDriverByName( "JP2ECW" ) == NULL )
2235 : {
2236 561 : poDriver = new GDALDriver();
2237 :
2238 561 : poDriver->SetDescription( "JP2ECW" );
2239 :
2240 561 : CPLString osLongName = "ERDAS JPEG2000 (SDK ";
2241 :
2242 : #ifdef NCS_ECWSDK_VERSION_STRING
2243 : osLongName += NCS_ECWSDK_VERSION_STRING;
2244 : #else
2245 561 : osLongName += "3.x";
2246 : #endif
2247 561 : osLongName += ")";
2248 :
2249 561 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2250 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2251 561 : "frmt_jp2ecw.html" );
2252 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
2253 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2254 :
2255 561 : poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
2256 561 : poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
2257 : #ifdef HAVE_COMPRESS
2258 561 : poDriver->pfnCreate = ECWCreateJPEG2000;
2259 561 : poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
2260 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2261 561 : "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
2262 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2263 : "<CreationOptionList>"
2264 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2265 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2266 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2267 : " <Option name='UNITS' type='string-select' description='ECW Projection Units'>"
2268 : " <Value>METERS</Value>"
2269 : " <Value>FEET</Value>"
2270 : " </Option>"
2271 :
2272 : #if ECWSDK_VERSION < 40
2273 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2274 : #else
2275 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2276 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2277 : #endif
2278 :
2279 : " <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
2280 : " <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
2281 : " <Option name='PROFILE' type='string-select'>"
2282 : " <Value>BASELINE_0</Value>"
2283 : " <Value>BASELINE_1</Value>"
2284 : " <Value>BASELINE_2</Value>"
2285 : " <Value>NPJE</Value>"
2286 : " <Value>EPJE</Value>"
2287 : " </Option>"
2288 : " <Option name='PROGRESSION' type='string-select'>"
2289 : " <Value>LRCP</Value>"
2290 : " <Value>RLCP</Value>"
2291 : " <Value>RPCL</Value>"
2292 : " </Option>"
2293 : " <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
2294 : " <Option name='LEVELS' type='int'/>"
2295 : " <Option name='LAYERS' type='int'/>"
2296 : " <Option name='PRECINCT_WIDTH' type='int'/>"
2297 : " <Option name='PRECINCT_HEIGHT' type='int'/>"
2298 : " <Option name='TILE_WIDTH' type='int'/>"
2299 : " <Option name='TILE_HEIGHT' type='int'/>"
2300 : " <Option name='INCLUDE_SOP' type='boolean'/>"
2301 : " <Option name='INCLUDE_EPH' type='boolean'/>"
2302 : " <Option name='DECOMPRESS_LAYERS' type='int'/>"
2303 : " <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
2304 561 : "</CreationOptionList>" );
2305 : #endif
2306 :
2307 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
2308 : }
2309 : #endif /* def FRMT_ecw */
2310 : }
|