1 : /******************************************************************************
2 : * $Id: ecwdataset.cpp 25804 2013-03-25 18:50:26Z 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 25804 2013-03-25 18:50:26Z 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 : {
100 37 : eBandInterp = GCI_GrayIndex;
101 : //we could also have alpha band.
102 37 : if ( strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_AllOpacity) == 0 || strcmp(poDS->psFileInfo->pBands[nBand-1].szDesc, NCS_BANDDESC_GreyscaleOpacity) ){
103 37 : eBandInterp = GCI_AlphaBand;
104 : }
105 200 : }else if (poDS->psFileInfo->eColorSpace == NCSCS_MULTIBAND ){
106 28 : eBandInterp = ECWGetColorInterpretationByName(poDS->psFileInfo->pBands[nBand-1].szDesc);
107 172 : }else if (poDS->psFileInfo->eColorSpace == NCSCS_sRGB){
108 : //color interpretation is the most important.
109 172 : if( nBand == 1 )
110 57 : eBandInterp = GCI_RedBand;
111 115 : else if( nBand == 2 )
112 57 : eBandInterp = GCI_GreenBand;
113 58 : else if( nBand == 3 )
114 57 : eBandInterp = GCI_BlueBand;
115 1 : else if (nBand == 4){
116 1 : eBandInterp = GCI_AlphaBand;
117 : }else {
118 0 : eBandInterp = GCI_Undefined;
119 : }
120 : }
121 0 : else if( poDS->psFileInfo->eColorSpace == NCSCS_YCbCr )
122 : {
123 0 : if( CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ))
124 : {
125 0 : if( nBand == 1 )
126 0 : eBandInterp = GCI_RedBand;
127 0 : else if( nBand == 2 )
128 0 : eBandInterp = GCI_GreenBand;
129 0 : else if( nBand == 3 )
130 0 : eBandInterp = GCI_BlueBand;
131 : else
132 0 : eBandInterp = GCI_Undefined;
133 : }
134 : else
135 : {
136 0 : if( nBand == 1 )
137 0 : eBandInterp = GCI_YCbCr_YBand;
138 0 : else if( nBand == 2 )
139 0 : eBandInterp = GCI_YCbCr_CbBand;
140 0 : else if( nBand == 3 )
141 0 : eBandInterp = GCI_YCbCr_CrBand;
142 : else
143 0 : eBandInterp = GCI_Undefined;
144 : }
145 : }
146 : else
147 0 : eBandInterp = GCI_Undefined;
148 :
149 : /* -------------------------------------------------------------------- */
150 : /* If this is the base level, create a set of overviews. */
151 : /* -------------------------------------------------------------------- */
152 237 : if( iOverview == -1 )
153 : {
154 : int i;
155 237 : for( i = 0;
156 : nRasterXSize / (1 << (i+1)) > 128
157 : && nRasterYSize / (1 << (i+1)) > 128;
158 : i++ )
159 : {
160 99 : apoOverviews.push_back( new ECWRasterBand( poDS, nBand, i ) );
161 : }
162 : }
163 :
164 237 : if( (poDS->psFileInfo->pBands[nBand-1].nBits % 8) != 0 )
165 : SetMetadataItem("NBITS",
166 4 : CPLString().Printf("%d",poDS->psFileInfo->pBands[nBand-1].nBits),
167 4 : "IMAGE_STRUCTURE" );
168 237 : }
169 :
170 : /************************************************************************/
171 : /* ~ECWRasterBand() */
172 : /************************************************************************/
173 :
174 237 : ECWRasterBand::~ECWRasterBand()
175 :
176 : {
177 237 : FlushCache();
178 :
179 573 : while( apoOverviews.size() > 0 )
180 : {
181 99 : delete apoOverviews.back();
182 99 : apoOverviews.pop_back();
183 : }
184 237 : }
185 :
186 : /************************************************************************/
187 : /* GetOverview() */
188 : /************************************************************************/
189 :
190 2 : GDALRasterBand *ECWRasterBand::GetOverview( int iOverview )
191 :
192 : {
193 2 : if( iOverview >= 0 && iOverview < (int) apoOverviews.size() )
194 2 : return apoOverviews[iOverview];
195 : else
196 0 : return NULL;
197 : }
198 :
199 : /************************************************************************/
200 : /* GetColorInterpretation() */
201 : /************************************************************************/
202 :
203 67 : GDALColorInterp ECWRasterBand::GetColorInterpretation()
204 :
205 : {
206 67 : return eBandInterp;
207 : }
208 :
209 : /************************************************************************/
210 : /* SetColorInterpretation() */
211 : /* */
212 : /* This would normally just be used by folks using the ECW code */
213 : /* to read JP2 streams in other formats (such as NITF) and */
214 : /* providing their own color interpretation regardless of what */
215 : /* ECW might think the stream itself says. */
216 : /************************************************************************/
217 :
218 12 : CPLErr ECWRasterBand::SetColorInterpretation( GDALColorInterp eNewInterp )
219 :
220 : {
221 12 : eBandInterp = eNewInterp;
222 :
223 12 : return CE_None;
224 : }
225 :
226 : /************************************************************************/
227 : /* AdviseRead() */
228 : /************************************************************************/
229 :
230 0 : CPLErr ECWRasterBand::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
231 : int nBufXSize, int nBufYSize,
232 : GDALDataType eDT,
233 : char **papszOptions )
234 : {
235 0 : int nResFactor = 1 << (iOverview+1);
236 :
237 : return poGDS->AdviseRead( nXOff * nResFactor,
238 : nYOff * nResFactor,
239 : nXSize * nResFactor,
240 : nYSize * nResFactor,
241 : nBufXSize, nBufYSize, eDT,
242 0 : 1, &nBand, papszOptions );
243 : }
244 :
245 : //statistics support:
246 : #if ECWSDK_VERSION >= 50
247 :
248 : /************************************************************************/
249 : /* GetDefaultHistogram() */
250 : /************************************************************************/
251 :
252 : CPLErr ECWRasterBand::GetDefaultHistogram( double *pdfMin, double *pdfMax,
253 : int *pnBuckets, int ** ppanHistogram,
254 : int bForce,
255 : GDALProgressFunc f, void *pProgressData){
256 :
257 : int bForceCoalesced = bForce;
258 : // If file version is smaller than 3, there will be no statistics in the file. But if it is version 3 or higher we don't want underlying implementation to compute histogram
259 : // so we set bForceCoalesced to FALSE.
260 : if (poGDS->psFileInfo->nFormatVersion >= 3){
261 : bForceCoalesced = FALSE;
262 : }
263 : // We check if we have PAM histogram. If we have them we return them. This will allow to override statistics stored in the file.
264 : CPLErr pamError = GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets, ppanHistogram, bForceCoalesced, f, pProgressData);
265 : if ( pamError == CE_None || poGDS->psFileInfo->nFormatVersion<3 ){
266 : return pamError;
267 : }
268 :
269 : NCS::CError error = poGDS->StatisticsEnsureInitialized();
270 : if (!error.Success()){
271 : CPLError( CE_Warning, CPLE_AppDefined,
272 : "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::GetDefaultHistogram. " );
273 : return CE_Failure;
274 : }
275 : GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
276 : if ( poGDS->pStatistics != NULL ){
277 : NCSBandStats& bandStats = poGDS->pStatistics->BandsStats[nBand-1];
278 : if ( bandStats.Histogram != NULL && bandStats.nHistBucketCount > 0 ){
279 : *pnBuckets = bandStats.nHistBucketCount;
280 : *ppanHistogram = (int *)VSIMalloc(bandStats.nHistBucketCount *sizeof(int));
281 : for (size_t i = 0; i < bandStats.nHistBucketCount; i++){
282 : (*ppanHistogram)[i] = (int) bandStats.Histogram[i];
283 : }
284 : }else{
285 : //no default histogram in file. We push it down for the logic of computation/returning warning.
286 : return GDALRasterBand::GetDefaultHistogram(pdfMin,pdfMax,pnBuckets,ppanHistogram,bForce,f, pProgressData);
287 : }
288 : if ( pdfMin != NULL ){
289 : *pdfMin = bandStats.fMinHist;
290 : }
291 : if ( pdfMax != NULL ){
292 : *pdfMax = bandStats.fMaxHist;
293 : }
294 : return CE_None;
295 : }else {
296 : //no default histogram in file. We push it down for the logic of computation/returning warning.
297 : return GDALRasterBand::GetDefaultHistogram(pdfMin,pdfMax,pnBuckets,ppanHistogram,bForce,f, pProgressData);
298 : }
299 : }
300 :
301 : /************************************************************************/
302 : /* SetDefaultHistogram() */
303 : /************************************************************************/
304 :
305 : CPLErr ECWRasterBand::SetDefaultHistogram( double dfMin, double dfMax,
306 : int nBuckets, int *panHistogram ){
307 : //Only version 3 supports saving statistics.
308 : if (poGDS->psFileInfo->nFormatVersion < 3){
309 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
310 : }
311 :
312 : //determine if there are statistics in PAM file.
313 : double dummy;
314 : int dummy_i;
315 : int *dummy_histogram;
316 : bool hasPAMDefaultHistogram = GDALPamRasterBand::GetDefaultHistogram(&dummy, &dummy, &dummy_i, &dummy_histogram, FALSE, NULL, NULL) == CE_None;
317 : if (hasPAMDefaultHistogram){
318 : VSIFree(dummy_histogram);
319 : }
320 :
321 : //ECW SDK ignores statistics for opacity bands. So we need to compute number of bands without opacity.
322 : GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
323 : UINT32 bucketCounts[256];
324 : std::fill_n(bucketCounts, nStatsBandCount, 0);
325 : bucketCounts[nStatsBandIndex] = nBuckets;
326 :
327 : NCS::CError error = poGDS->StatisticsEnsureInitialized();
328 : if (!error.Success()){
329 : CPLError( CE_Warning, CPLE_AppDefined,
330 : "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::SetDefaultHistogram. Default histogram will be written to PAM. " );
331 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
332 : }
333 :
334 : NCSFileStatistics *pStatistics = poGDS->pStatistics;
335 :
336 : if (pStatistics == NULL){
337 : error = NCSEcwInitStatistics(&pStatistics, nStatsBandCount, bucketCounts);
338 : poGDS->bStatisticsDirty = TRUE;
339 : poGDS->pStatistics = pStatistics;
340 : if (!error.Success()){
341 : CPLError( CE_Warning, CPLE_AppDefined,
342 : "NCSEcwInitStatistics failed in ECWRasterBand::SetDefaultHistogram." );
343 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
344 : }
345 : //no error statistics properly initialized but there were no statistics previously.
346 : }else{
347 : //is there a room for our band already?
348 : //This should account for following cases:
349 : //1. Existing histogram (for this or different band) has smaller bucket count.
350 : //2. There is no existing histogram but statistics are set for one or more bands (pStatistics->nHistBucketCounts is zero).
351 : if (pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount != nBuckets){
352 : //no. There is no room. We need more!
353 : NCSFileStatistics *pNewStatistics = NULL;
354 : for (size_t i=0;i<pStatistics->nNumberOfBands;i++){
355 : bucketCounts[i] = pStatistics->BandsStats[i].nHistBucketCount;
356 : }
357 : bucketCounts[nStatsBandIndex] = nBuckets;
358 : if (nBuckets < (int)pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount){
359 : pStatistics->BandsStats[nStatsBandIndex].nHistBucketCount = nBuckets;
360 : }
361 : error = NCSEcwInitStatistics(&pNewStatistics, nStatsBandCount, bucketCounts);
362 : if (!error.Success()){
363 : CPLError( CE_Warning, CPLE_AppDefined,
364 : "NCSEcwInitStatistics failed in ECWRasterBand::SetDefaultHistogram (realocate)." );
365 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
366 : }
367 : //we need to copy existing statistics.
368 : error = NCSEcwCopyStatistics(&pNewStatistics, pStatistics);
369 : if (!error.Success()){
370 : CPLError( CE_Warning, CPLE_AppDefined,
371 : "NCSEcwCopyStatistics failed in ECWRasterBand::SetDefaultHistogram." );
372 : NCSEcwFreeStatistics(pNewStatistics);
373 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
374 : }
375 : pNewStatistics->nNumberOfBands = nStatsBandCount;
376 : NCSEcwFreeStatistics(pStatistics);
377 : pStatistics = pNewStatistics;
378 : poGDS->pStatistics = pStatistics;
379 : poGDS->bStatisticsDirty = TRUE;
380 : }
381 : }
382 :
383 : //at this point we have allocated statistics structure.
384 : pStatistics->BandsStats[nStatsBandIndex].fMinHist = (IEEE4) dfMin;
385 : pStatistics->BandsStats[nStatsBandIndex].fMaxHist = (IEEE4) dfMax;
386 : for (int i=0;i<nBuckets;i++){
387 : pStatistics->BandsStats[nStatsBandIndex].Histogram[i] = (UINT64)panHistogram[i];
388 : }
389 :
390 : if (hasPAMDefaultHistogram){
391 : CPLError( CE_Debug, CPLE_AppDefined,
392 : "PAM default histogram will be overwritten." );
393 : return GDALPamRasterBand::SetDefaultHistogram(dfMin, dfMax, nBuckets, panHistogram);
394 : }
395 : return CE_None;
396 : }
397 :
398 : /************************************************************************/
399 : /* GetBandIndexAndCountForStatistics() */
400 : /************************************************************************/
401 :
402 : void ECWRasterBand::GetBandIndexAndCountForStatistics(int &bandIndex, int &bandCount){
403 : bandIndex = nBand-1;
404 : bandCount = poGDS->nBands;
405 : for (int i=0;i<poGDS->nBands;i++){
406 : if (poDS->GetRasterBand(i+1)->GetColorInterpretation() == GCI_AlphaBand){
407 : bandCount--;
408 : if ( i < nBand-1 ){
409 : bandIndex--;
410 : }
411 : }
412 :
413 : }
414 : }
415 :
416 : /************************************************************************/
417 : /* GetStatistics() */
418 : /************************************************************************/
419 :
420 : CPLErr ECWRasterBand::GetStatistics( int bApproxOK, int bForce,
421 : double *pdfMin, double *pdfMax,
422 : double *pdfMean, double *padfStdDev ){
423 : int bForceCoalesced = bForce;
424 : // If file version is smaller than 3, there will be no statistics in the file. But if it is version 3 or higher we don't want underlying implementation to compute histogram
425 : // so we set bForceCoalesced to FALSE.
426 : if (poGDS->psFileInfo->nFormatVersion >= 3){
427 : bForceCoalesced = FALSE;
428 : }
429 : // We check if we have PAM histogram. If we have them we return them. This will allow to override statistics stored in the file.
430 : CPLErr pamError = GDALPamRasterBand::GetStatistics(bApproxOK, bForceCoalesced, pdfMin, pdfMax, pdfMean, padfStdDev);
431 : if ( pamError == CE_None || poGDS->psFileInfo->nFormatVersion<3 ){
432 : return pamError;
433 : }
434 :
435 : NCS::CError error = poGDS->StatisticsEnsureInitialized();
436 : if (!error.Success()){
437 : CPLError( CE_Failure, CPLE_AppDefined,
438 : "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::GetStatistic. " );
439 : return CE_Failure;
440 : }
441 : GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
442 : if ( poGDS->pStatistics != NULL ){
443 :
444 : NCSBandStats& bandStats = poGDS->pStatistics->BandsStats[nStatsBandIndex];
445 : if ( pdfMin != NULL ){
446 : *pdfMin = bandStats.fMinVal;
447 : }
448 : if ( pdfMax != NULL ){
449 : *pdfMax = bandStats.fMaxVal;
450 : }
451 : if ( pdfMean != NULL ){
452 : *pdfMean = bandStats.fMeanVal;
453 : }
454 : if ( padfStdDev != NULL ){
455 : *padfStdDev = bandStats.fStandardDev;
456 : }
457 : return CE_None;
458 : }else {
459 : return CE_Warning;
460 : }
461 :
462 : }
463 :
464 : /************************************************************************/
465 : /* SetStatistics() */
466 : /************************************************************************/
467 :
468 : CPLErr ECWRasterBand::SetStatistics( double dfMin, double dfMax,
469 : double dfMean, double dfStdDev ){
470 : if (poGDS->psFileInfo->nFormatVersion < 3){
471 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
472 : }
473 : double dummy;
474 : bool hasPAMStatistics = GDALPamRasterBand::GetStatistics(TRUE, FALSE, &dummy, &dummy, &dummy, &dummy) == CE_None;
475 :
476 : NCS::CError error = poGDS->StatisticsEnsureInitialized();
477 : if (!error.Success()){
478 : CPLError( CE_Warning, CPLE_AppDefined,
479 : "ECWRDataset::StatisticsEnsureInitialized failed in ECWRasterBand::SetStatistic. Statistics will be written to PAM. " );
480 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
481 : }
482 : GetBandIndexAndCountForStatistics(nStatsBandIndex, nStatsBandCount);
483 : if (poGDS->pStatistics == NULL){
484 : error = NCSEcwInitStatistics(&poGDS->pStatistics, nStatsBandCount, NULL);
485 : if (!error.Success()){
486 : CPLError( CE_Warning, CPLE_AppDefined,
487 : "NCSEcwInitStatistics failed in ECWRasterBand::SetStatistic. Statistics will be written to PAM." );
488 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
489 : }
490 : }
491 :
492 : poGDS->pStatistics->BandsStats[nStatsBandIndex].fMinVal = (IEEE4) dfMin;
493 : poGDS->pStatistics->BandsStats[nStatsBandIndex].fMaxVal = (IEEE4)dfMax;
494 : poGDS->pStatistics->BandsStats[nStatsBandIndex].fMeanVal = (IEEE4)dfMean;
495 : poGDS->pStatistics->BandsStats[nStatsBandIndex].fStandardDev = (IEEE4)dfStdDev;
496 : poGDS->bStatisticsDirty = TRUE;
497 : //if we have PAM statistics we need to save them as well. Better option would be to remove them from PAM file but I don't know how to do that without messing in PAM internals.
498 : if ( hasPAMStatistics ){
499 : CPLError( CE_Debug, CPLE_AppDefined,
500 : "PAM statistics will be overwritten." );
501 : return GDALPamRasterBand::SetStatistics(dfMin, dfMax, dfMean, dfStdDev);
502 : }
503 : return CE_None;
504 :
505 : }
506 : #endif
507 :
508 : //#if !defined(SDK_CAN_DO_SUPERSAMPLING)
509 : /************************************************************************/
510 : /* OldIRasterIO() */
511 : /************************************************************************/
512 :
513 : /* This implementation of IRasterIO(), derived from the one of GDAL 1.9 */
514 : /* and older versions, is meant at making over-sampling */
515 : /* work with ECW SDK 3.3. Newer versions of the SDK can do super-sampling in their */
516 : /* SetView() call. */
517 :
518 1 : CPLErr ECWRasterBand::OldIRasterIO( GDALRWFlag eRWFlag,
519 : int nXOff, int nYOff, int nXSize, int nYSize,
520 : void * pData, int nBufXSize, int nBufYSize,
521 : GDALDataType eBufType,
522 : int nPixelSpace, int nLineSpace )
523 :
524 : {
525 : int iBand, bDirect;
526 1 : GByte *pabyWorkBuffer = NULL;
527 1 : int nResFactor = 1 << (iOverview+1);
528 :
529 1 : nXOff *= nResFactor;
530 1 : nYOff *= nResFactor;
531 1 : nXSize *= nResFactor;
532 1 : nYSize *= nResFactor;
533 :
534 : /* -------------------------------------------------------------------- */
535 : /* Try to do it based on existing "advised" access. */
536 : /* -------------------------------------------------------------------- */
537 1 : if( poGDS->TryWinRasterIO( eRWFlag,
538 : nXOff, nYOff,
539 : nXSize, nYSize,
540 : (GByte *) pData, nBufXSize, nBufYSize,
541 : eBufType, 1, &nBand,
542 : nPixelSpace, nLineSpace, 0 ) )
543 0 : return CE_None;
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* The ECW SDK doesn't supersample, so adjust for this case. */
547 : /* -------------------------------------------------------------------- */
548 :
549 1 : int nNewXSize = nBufXSize, nNewYSize = nBufYSize;
550 :
551 1 : if ( nXSize < nBufXSize )
552 1 : nNewXSize = nXSize;
553 :
554 1 : if ( nYSize < nBufYSize )
555 1 : nNewYSize = nYSize;
556 :
557 : /* -------------------------------------------------------------------- */
558 : /* Can we perform direct loads, or must we load into a working */
559 : /* buffer, and transform? */
560 : /* -------------------------------------------------------------------- */
561 1 : int nRawPixelSize = GDALGetDataTypeSize(poGDS->eRasterDataType) / 8;
562 :
563 : bDirect = nPixelSpace == 1 && eBufType == GDT_Byte
564 1 : && nNewXSize == nBufXSize && nNewYSize == nBufYSize;
565 1 : if( !bDirect )
566 1 : pabyWorkBuffer = (GByte *) CPLMalloc(nNewXSize * nRawPixelSize);
567 :
568 : /* -------------------------------------------------------------------- */
569 : /* Establish access at the desired resolution. */
570 : /* -------------------------------------------------------------------- */
571 1 : CNCSError oErr;
572 :
573 1 : poGDS->CleanupWindow();
574 :
575 1 : iBand = nBand-1;
576 : oErr = poGDS->poFileView->SetView( 1, (unsigned int *) (&iBand),
577 : nXOff, nYOff,
578 : nXOff + nXSize - 1,
579 : nYOff + nYSize - 1,
580 1 : nNewXSize, nNewYSize );
581 1 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
582 : {
583 0 : CPLFree( pabyWorkBuffer );
584 0 : ECWReportError(oErr);
585 :
586 0 : return CE_Failure;
587 : }
588 :
589 : /* -------------------------------------------------------------------- */
590 : /* Read back one scanline at a time, till request is satisfied. */
591 : /* Supersampling is not supported by the ECW API, so we will do */
592 : /* it ourselves. */
593 : /* -------------------------------------------------------------------- */
594 1 : double dfSrcYInc = (double)nNewYSize / nBufYSize;
595 1 : double dfSrcXInc = (double)nNewXSize / nBufXSize;
596 : int iSrcLine, iDstLine;
597 :
598 801 : for( iSrcLine = 0, iDstLine = 0; iDstLine < nBufYSize; iDstLine++ )
599 : {
600 : NCSEcwReadStatus eRStatus;
601 800 : int iDstLineOff = iDstLine * nLineSpace;
602 : unsigned char *pabySrcBuf;
603 :
604 800 : if( bDirect )
605 0 : pabySrcBuf = ((GByte *)pData) + iDstLineOff;
606 : else
607 800 : pabySrcBuf = pabyWorkBuffer;
608 :
609 1200 : if ( nNewYSize == nBufYSize || iSrcLine == (int)(iDstLine * dfSrcYInc) )
610 : {
611 : eRStatus = poGDS->poFileView->ReadLineBIL(
612 400 : poGDS->eNCSRequestDataType, 1, (void **) &pabySrcBuf );
613 :
614 400 : if( eRStatus != NCSECW_READ_OK )
615 : {
616 0 : CPLFree( pabyWorkBuffer );
617 0 : CPLDebug( "ECW", "ReadLineBIL status=%d", (int) eRStatus );
618 : CPLError( CE_Failure, CPLE_AppDefined,
619 0 : "NCScbmReadViewLineBIL failed." );
620 0 : return CE_Failure;
621 : }
622 :
623 400 : if( !bDirect )
624 : {
625 400 : if ( nNewXSize == nBufXSize )
626 : {
627 : GDALCopyWords( pabyWorkBuffer, poGDS->eRasterDataType,
628 : nRawPixelSize,
629 : ((GByte *)pData) + iDstLine * nLineSpace,
630 0 : eBufType, nPixelSpace, nBufXSize );
631 : }
632 : else
633 : {
634 : int iPixel;
635 :
636 320400 : for ( iPixel = 0; iPixel < nBufXSize; iPixel++ )
637 : {
638 : GDALCopyWords( pabyWorkBuffer
639 : + nRawPixelSize*((int)(iPixel*dfSrcXInc)),
640 : poGDS->eRasterDataType, nRawPixelSize,
641 : (GByte *)pData + iDstLineOff
642 : + iPixel * nPixelSpace,
643 320000 : eBufType, nPixelSpace, 1 );
644 : }
645 : }
646 : }
647 :
648 400 : iSrcLine++;
649 : }
650 : else
651 : {
652 : // Just copy the previous line in this case
653 : GDALCopyWords( (GByte *)pData + (iDstLineOff - nLineSpace),
654 : eBufType, nPixelSpace,
655 : (GByte *)pData + iDstLineOff,
656 400 : eBufType, nPixelSpace, nBufXSize );
657 : }
658 : }
659 :
660 1 : CPLFree( pabyWorkBuffer );
661 :
662 1 : return CE_None;
663 : }
664 : //#endif !defined(SDK_CAN_DO_SUPERSAMPLING)
665 :
666 : /************************************************************************/
667 : /* IRasterIO() */
668 : /************************************************************************/
669 :
670 11774 : CPLErr ECWRasterBand::IRasterIO( GDALRWFlag eRWFlag,
671 : int nXOff, int nYOff, int nXSize, int nYSize,
672 : void * pData, int nBufXSize, int nBufYSize,
673 : GDALDataType eBufType,
674 : int nPixelSpace, int nLineSpace )
675 : {
676 11774 : if( eRWFlag == GF_Write )
677 0 : return CE_Failure;
678 :
679 : /* -------------------------------------------------------------------- */
680 : /* Default line and pixel spacing if needed. */
681 : /* -------------------------------------------------------------------- */
682 11774 : if ( nPixelSpace == 0 )
683 0 : nPixelSpace = GDALGetDataTypeSize( eBufType ) / 8;
684 :
685 11774 : if ( nLineSpace == 0 )
686 0 : nLineSpace = nPixelSpace * nBufXSize;
687 :
688 : CPLDebug( "ECWRasterBand",
689 : "RasterIO(nBand=%d,iOverview=%d,nXOff=%d,nYOff=%d,nXSize=%d,nYSize=%d -> %dx%d)",
690 11774 : nBand, iOverview, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
691 :
692 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
693 11774 : if( poGDS->bUseOldBandRasterIOImplementation )
694 : {
695 : return OldIRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
696 : pData, nBufXSize, nBufYSize,
697 : eBufType,
698 1 : nPixelSpace, nLineSpace );
699 : }
700 :
701 : #endif
702 :
703 11773 : int nResFactor = 1 << (iOverview+1);
704 :
705 : return poGDS->IRasterIO(eRWFlag,
706 : nXOff * nResFactor,
707 : nYOff * nResFactor,
708 : (nXSize == nRasterXSize) ? poGDS->nRasterXSize : nXSize * nResFactor,
709 : (nYSize == nRasterYSize) ? poGDS->nRasterYSize : nYSize * nResFactor,
710 : pData, nBufXSize, nBufYSize,
711 : eBufType, 1, &nBand,
712 11773 : nPixelSpace, nLineSpace, nLineSpace*nBufYSize);
713 : }
714 :
715 : /************************************************************************/
716 : /* IReadBlock() */
717 : /************************************************************************/
718 :
719 1 : CPLErr ECWRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff, void * pImage )
720 :
721 : {
722 1 : int nXOff = nBlockXOff * nBlockXSize,
723 1 : nYOff = nBlockYOff * nBlockYSize,
724 1 : nXSize = nBlockXSize,
725 1 : nYSize = nBlockYSize;
726 :
727 1 : if( nXOff + nXSize > nRasterXSize )
728 0 : nXSize = nRasterXSize - nXOff;
729 1 : if( nYOff + nYSize > nRasterYSize )
730 0 : nYSize = nRasterYSize - nYOff;
731 :
732 1 : int nPixelSpace = GDALGetDataTypeSize(eDataType) / 8;
733 1 : int nLineSpace = nPixelSpace * nBlockXSize;
734 : return IRasterIO( GF_Read,
735 : nXOff, nYOff, nXSize, nYSize,
736 : pImage, nXSize, nYSize,
737 1 : eDataType, nPixelSpace, nLineSpace );
738 : }
739 :
740 : /************************************************************************/
741 : /* ==================================================================== */
742 : /* ECWDataset */
743 : /* ==================================================================== */
744 : /************************************************************************/
745 :
746 :
747 : /************************************************************************/
748 : /* ECWDataset() */
749 : /************************************************************************/
750 :
751 68 : ECWDataset::ECWDataset(int bIsJPEG2000)
752 :
753 : {
754 68 : this->bIsJPEG2000 = bIsJPEG2000;
755 68 : bUsingCustomStream = FALSE;
756 68 : pszProjection = NULL;
757 68 : poFileView = NULL;
758 68 : bWinActive = FALSE;
759 68 : panWinBandList = NULL;
760 68 : eRasterDataType = GDT_Byte;
761 68 : nGCPCount = 0;
762 68 : pasGCPList = NULL;
763 68 : papszGMLMetadata = NULL;
764 :
765 68 : bGeoTransformValid = FALSE;
766 68 : adfGeoTransform[0] = 0.0;
767 68 : adfGeoTransform[1] = 1.0;
768 68 : adfGeoTransform[2] = 0.0;
769 68 : adfGeoTransform[3] = 0.0;
770 68 : adfGeoTransform[4] = 0.0;
771 68 : adfGeoTransform[5] = 1.0;
772 :
773 68 : bHdrDirty = FALSE;
774 68 : bGeoTransformChanged = FALSE;
775 68 : bProjectionChanged = FALSE;
776 68 : bProjCodeChanged = FALSE;
777 68 : bDatumCodeChanged = FALSE;
778 68 : bUnitsCodeChanged = FALSE;
779 :
780 68 : bUseOldBandRasterIOImplementation = FALSE;
781 : #if ECWSDK_VERSION>=50
782 :
783 : pStatistics = NULL;
784 : bStatisticsDirty = FALSE;
785 : bStatisticsInitialized = FALSE;
786 :
787 : #endif
788 :
789 68 : sCachedMultiBandIO.bEnabled = FALSE;
790 68 : sCachedMultiBandIO.nBandsTried = 0;
791 68 : sCachedMultiBandIO.nXOff = 0;
792 68 : sCachedMultiBandIO.nYOff = 0;
793 68 : sCachedMultiBandIO.nXSize = 0;
794 68 : sCachedMultiBandIO.nYSize = 0;
795 68 : sCachedMultiBandIO.nBufXSize = 0;
796 68 : sCachedMultiBandIO.nBufYSize = 0;
797 68 : sCachedMultiBandIO.eBufType = GDT_Unknown;
798 68 : sCachedMultiBandIO.pabyData = NULL;
799 :
800 68 : poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2ECW" : "ECW" );
801 68 : }
802 :
803 : /************************************************************************/
804 : /* ~ECWDataset() */
805 : /************************************************************************/
806 :
807 68 : ECWDataset::~ECWDataset()
808 :
809 : {
810 68 : FlushCache();
811 68 : CleanupWindow();
812 :
813 : /* -------------------------------------------------------------------- */
814 : /* Release / dereference iostream. */
815 : /* -------------------------------------------------------------------- */
816 : // The underlying iostream of the CNCSJP2FileView (poFileView) object may
817 : // also be the underlying iostream of other CNCSJP2FileView (poFileView)
818 : // objects. Consequently, when we delete the CNCSJP2FileView (poFileView)
819 : // object, we must decrement the nFileViewCount attribute of the underlying
820 : // VSIIOStream object, and only delete the VSIIOStream object when
821 : // nFileViewCount is equal to zero.
822 :
823 68 : CPLMutexHolder oHolder( &hECWDatasetMutex );
824 :
825 : // GDAL_CLOSE_JP2ECW_RESOURCE is set to NO by gdaldllmain.cpp/GDALDestroy() so as
826 : // to avoid an issue with the ECW SDK 3.3 where the destructor of CNCSJP2File::CNCSJP2FileVector CNCSJP2File::sm_Files;
827 : // static ressource allocated in NCJP2File.cpp can be called before GDALDestroy(), causing
828 : // ECW SDK resources ( CNCSJP2File files ) to be closed before we get here.
829 68 : if( poFileView != NULL &&
830 : (!bIsJPEG2000 || CSLTestBoolean(CPLGetConfigOption("GDAL_CLOSE_JP2ECW_RESOURCE", "YES"))) )
831 : {
832 68 : VSIIOStream *poUnderlyingIOStream = (VSIIOStream *)NULL;
833 :
834 68 : poUnderlyingIOStream = ((VSIIOStream *)(poFileView->GetStream()));
835 68 : delete poFileView;
836 :
837 68 : if( bUsingCustomStream )
838 : {
839 15 : if( --poUnderlyingIOStream->nFileViewCount == 0 )
840 15 : delete poUnderlyingIOStream;
841 : }
842 : }
843 :
844 : /* WriteHeader() must be called after closing the file handle to work */
845 : /* on Windows */
846 68 : if( bHdrDirty )
847 3 : WriteHeader();
848 : #if ECWSDK_VERSION>=50
849 :
850 : if (bStatisticsDirty){
851 : StatisticsWrite();
852 : }
853 : CleanupStatistics();
854 :
855 : #endif
856 :
857 68 : CPLFree( pszProjection );
858 68 : CSLDestroy( papszGMLMetadata );
859 :
860 68 : if( nGCPCount > 0 )
861 : {
862 4 : GDALDeinitGCPs( nGCPCount, pasGCPList );
863 4 : CPLFree( pasGCPList );
864 : }
865 :
866 68 : CPLFree(sCachedMultiBandIO.pabyData);
867 68 : }
868 :
869 : #if ECWSDK_VERSION>=50
870 :
871 : /************************************************************************/
872 : /* StatisticsEnsureInitialized() */
873 : /************************************************************************/
874 :
875 : NCS::CError ECWDataset::StatisticsEnsureInitialized(){
876 : if (bStatisticsInitialized == TRUE){
877 : return NCS_SUCCESS;
878 : }
879 :
880 : NCS::CError error = poFileView->GetClientStatistics(&pStatistics);
881 : if (error.Success()){
882 : bStatisticsInitialized = TRUE;
883 : }
884 : return error;
885 : }
886 :
887 : /************************************************************************/
888 : /* StatisticsWrite() */
889 : /************************************************************************/
890 :
891 : NCS::CError ECWDataset::StatisticsWrite(){
892 :
893 : NCSFileView* view = NCSEcwEditOpen( GetDescription() );
894 : NCS::CError error;
895 : if ( view != NULL ){
896 : error = NCSEcwEditSetStatistics(view, pStatistics);
897 : if (error.Success()){
898 : error = NCSEcwEditFlushAll(view);
899 : if (error.Success()){
900 : error = NCSEcwEditClose(view);
901 : }
902 : }
903 : }
904 :
905 : bStatisticsDirty = FALSE;
906 :
907 : return error;
908 :
909 : }
910 :
911 : /************************************************************************/
912 : /* CleanupStatistics() */
913 : /************************************************************************/
914 :
915 : void ECWDataset::CleanupStatistics(){
916 : if (bStatisticsInitialized == TRUE && pStatistics !=NULL){
917 : NCSEcwFreeStatistics(pStatistics);
918 : }
919 : }
920 :
921 : #endif // #if ECWSDK_VERSION>=50
922 :
923 : /************************************************************************/
924 : /* SetGeoTransform() */
925 : /************************************************************************/
926 :
927 6 : CPLErr ECWDataset::SetGeoTransform( double * padfGeoTransform )
928 : {
929 6 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
930 5 : return GDALPamDataset::SetGeoTransform(padfGeoTransform);
931 :
932 2 : if ( !bGeoTransformValid ||
933 1 : adfGeoTransform[0] != padfGeoTransform[0] ||
934 0 : adfGeoTransform[1] != padfGeoTransform[1] ||
935 0 : adfGeoTransform[2] != padfGeoTransform[2] ||
936 0 : adfGeoTransform[3] != padfGeoTransform[3] ||
937 0 : adfGeoTransform[4] != padfGeoTransform[4] ||
938 0 : adfGeoTransform[5] != padfGeoTransform[5] )
939 : {
940 1 : memcpy(adfGeoTransform, padfGeoTransform, 6 * sizeof(double));
941 1 : bGeoTransformValid = TRUE;
942 1 : bHdrDirty = TRUE;
943 1 : bGeoTransformChanged = TRUE;
944 : }
945 :
946 1 : return CE_None;
947 : }
948 :
949 : /************************************************************************/
950 : /* SetProjection() */
951 : /************************************************************************/
952 :
953 6 : CPLErr ECWDataset::SetProjection( const char* pszProjectionIn )
954 : {
955 6 : if ( bIsJPEG2000 || eAccess == GA_ReadOnly )
956 5 : return GDALPamDataset::SetProjection(pszProjectionIn);
957 :
958 1 : if ( !( (pszProjection == NULL && pszProjectionIn == NULL) ||
959 : (pszProjection != NULL && pszProjectionIn != NULL &&
960 : strcmp(pszProjection, pszProjectionIn) == 0) ) )
961 : {
962 1 : CPLFree(pszProjection);
963 1 : pszProjection = pszProjectionIn ? CPLStrdup(pszProjectionIn) : NULL;
964 1 : bHdrDirty = TRUE;
965 1 : bProjectionChanged = TRUE;
966 : }
967 :
968 1 : return CE_None;
969 : }
970 :
971 : /************************************************************************/
972 : /* SetMetadataItem() */
973 : /************************************************************************/
974 :
975 3 : CPLErr ECWDataset::SetMetadataItem( const char * pszName,
976 : const char * pszValue,
977 : const char * pszDomain )
978 : {
979 3 : if ( !bIsJPEG2000 && eAccess == GA_Update &&
980 : (pszDomain == NULL || EQUAL(pszDomain, "") ||
981 : (pszDomain != NULL && EQUAL(pszDomain, "ECW"))) &&
982 : pszName != NULL &&
983 : (strcmp(pszName, "PROJ") == 0 || strcmp( pszName, "DATUM") == 0 ||
984 : strcmp( pszName, "UNITS") == 0 ) )
985 : {
986 3 : CPLString osNewVal = pszValue ? pszValue : "";
987 3 : if (osNewVal.size() > 31)
988 0 : osNewVal.resize(31);
989 3 : if (strcmp(pszName, "PROJ") == 0)
990 : {
991 1 : bProjCodeChanged = (osNewVal != m_osProjCode);
992 1 : m_osProjCode = osNewVal;
993 1 : bHdrDirty |= bProjCodeChanged;
994 : }
995 2 : else if (strcmp( pszName, "DATUM") == 0)
996 : {
997 1 : bDatumCodeChanged |= (osNewVal != m_osDatumCode)? TRUE:FALSE ;
998 1 : m_osDatumCode = osNewVal;
999 1 : bHdrDirty |= bDatumCodeChanged;
1000 : }
1001 : else
1002 : {
1003 1 : bUnitsCodeChanged |= (osNewVal != m_osUnitsCode)?TRUE:FALSE;
1004 1 : m_osUnitsCode = osNewVal;
1005 1 : bHdrDirty |= bUnitsCodeChanged;
1006 : }
1007 3 : return CE_None;
1008 : }
1009 : else
1010 0 : return GDALPamDataset::SetMetadataItem(pszName, pszValue, pszDomain);
1011 : }
1012 :
1013 : /************************************************************************/
1014 : /* SetMetadata() */
1015 : /************************************************************************/
1016 :
1017 15 : CPLErr ECWDataset::SetMetadata( char ** papszMetadata,
1018 : const char * pszDomain )
1019 : {
1020 15 : if ( (pszDomain == NULL || EQUAL(pszDomain, "") || EQUAL(pszDomain, "ECW")) &&
1021 : (CSLFetchNameValue(papszMetadata, "PROJ") != NULL ||
1022 : CSLFetchNameValue(papszMetadata, "DATUM") != NULL ||
1023 : CSLFetchNameValue(papszMetadata, "UNITS") != NULL) )
1024 : {
1025 0 : CPLStringList osNewMetadata;
1026 0 : char** papszIter = papszMetadata;
1027 0 : while(*papszIter)
1028 : {
1029 0 : if (strncmp(*papszIter, "PROJ=", 5) == 0 ||
1030 : strncmp(*papszIter, "DATUM=", 6) == 0 ||
1031 : strncmp(*papszIter, "UNITS=", 6) == 0)
1032 : {
1033 0 : char* pszKey = NULL;
1034 0 : const char* pszValue = CPLParseNameValue(*papszIter, &pszKey );
1035 0 : SetMetadataItem(pszKey, pszValue, pszDomain);
1036 0 : CPLFree(pszKey);
1037 : }
1038 : else
1039 0 : osNewMetadata.AddString(*papszIter);
1040 0 : papszIter ++;
1041 : }
1042 0 : if (osNewMetadata.size() != 0)
1043 0 : return GDALPamDataset::SetMetadata(osNewMetadata.List(), pszDomain);
1044 : else
1045 0 : return CE_None;
1046 : }
1047 : else
1048 15 : return GDALPamDataset::SetMetadata(papszMetadata, pszDomain);
1049 : }
1050 :
1051 : /************************************************************************/
1052 : /* WriteHeader() */
1053 : /************************************************************************/
1054 :
1055 3 : void ECWDataset::WriteHeader()
1056 : {
1057 3 : if (!bHdrDirty)
1058 0 : return;
1059 :
1060 3 : CPLAssert(eAccess == GA_Update);
1061 3 : CPLAssert(!bIsJPEG2000);
1062 :
1063 3 : bHdrDirty = FALSE;
1064 :
1065 3 : NCSEcwEditInfo *psEditInfo = NULL;
1066 : NCSError eErr;
1067 :
1068 : /* Load original header info */
1069 : #if ECWSDK_VERSION<50
1070 3 : eErr = NCSEcwEditReadInfo((char*) GetDescription(), &psEditInfo);
1071 : #else
1072 : eErr = NCSEcwEditReadInfo( NCS::CString::Utf8Decode(GetDescription()).c_str(), &psEditInfo);
1073 : #endif
1074 3 : if (eErr != NCS_SUCCESS)
1075 : {
1076 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditReadInfo() failed");
1077 0 : return;
1078 : }
1079 :
1080 : /* To avoid potential cross-heap issues, we keep the original */
1081 : /* strings, and restore them before freeing the structure */
1082 3 : char* pszOriginalCode = psEditInfo->szDatum;
1083 3 : char* pszOriginalProj = psEditInfo->szProjection;
1084 :
1085 : /* Alter the structure with user modified information */
1086 : char szProjCode[32], szDatumCode[32], szUnits[32];
1087 3 : if (bProjectionChanged)
1088 : {
1089 1 : if (ECWTranslateFromWKT( pszProjection, szProjCode, sizeof(szProjCode),
1090 : szDatumCode, sizeof(szDatumCode), szUnits ) )
1091 : {
1092 1 : psEditInfo->szDatum = szDatumCode;
1093 1 : psEditInfo->szProjection = szProjCode;
1094 1 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
1095 1 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
1096 1 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
1097 : CPLDebug("ECW", "Rewrite UNITS : %s",
1098 1 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
1099 : }
1100 : }
1101 :
1102 3 : if (bDatumCodeChanged)
1103 : {
1104 1 : psEditInfo->szDatum = (char*) ((m_osDatumCode.size()) ? m_osDatumCode.c_str() : "RAW");
1105 1 : CPLDebug("ECW", "Rewrite DATUM : %s", psEditInfo->szDatum);
1106 : }
1107 3 : if (bProjCodeChanged)
1108 : {
1109 1 : psEditInfo->szProjection = (char*) ((m_osProjCode.size()) ? m_osProjCode.c_str() : "RAW");
1110 1 : CPLDebug("ECW", "Rewrite PROJ : %s", psEditInfo->szProjection);
1111 : }
1112 3 : if (bUnitsCodeChanged)
1113 : {
1114 1 : psEditInfo->eCellSizeUnits = ECWTranslateToCellSizeUnits(m_osUnitsCode.c_str());
1115 : CPLDebug("ECW", "Rewrite UNITS : %s",
1116 1 : ECWTranslateFromCellSizeUnits(psEditInfo->eCellSizeUnits));
1117 : }
1118 :
1119 3 : if (bGeoTransformChanged)
1120 : {
1121 1 : psEditInfo->fOriginX = adfGeoTransform[0];
1122 1 : psEditInfo->fCellIncrementX = adfGeoTransform[1];
1123 1 : psEditInfo->fOriginY = adfGeoTransform[3];
1124 1 : psEditInfo->fCellIncrementY = adfGeoTransform[5];
1125 1 : CPLDebug("ECW", "Rewrite Geotransform");
1126 : }
1127 :
1128 : /* Write modified header info */
1129 : #if ECWSDK_VERSION<50
1130 3 : eErr = NCSEcwEditWriteInfo((char*) GetDescription(), psEditInfo, NULL, NULL, NULL);
1131 : #else
1132 : eErr = NCSEcwEditWriteInfo( NCS::CString::Utf8Decode(GetDescription()).c_str(), psEditInfo, NULL, NULL, NULL);
1133 : #endif
1134 3 : if (eErr != NCS_SUCCESS)
1135 : {
1136 0 : CPLError(CE_Failure, CPLE_AppDefined, "NCSEcwEditWriteInfo() failed");
1137 : }
1138 :
1139 : /* Restore original pointers before free'ing */
1140 3 : psEditInfo->szDatum = pszOriginalCode;
1141 3 : psEditInfo->szProjection = pszOriginalProj;
1142 :
1143 3 : NCSEcwEditFreeInfo(psEditInfo);
1144 : }
1145 :
1146 : /************************************************************************/
1147 : /* AdviseRead() */
1148 : /************************************************************************/
1149 :
1150 29 : CPLErr ECWDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
1151 : int nBufXSize, int nBufYSize,
1152 : GDALDataType eDT,
1153 : int nBandCount, int *panBandList,
1154 : char **papszOptions )
1155 :
1156 : {
1157 29 : int *panAdjustedBandList = NULL;
1158 :
1159 : CPLDebug( "ECW",
1160 : "ECWDataset::AdviseRead(%d,%d,%d,%d->%d,%d)",
1161 29 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1162 :
1163 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
1164 29 : if( nBufXSize > nXSize || nBufYSize > nYSize )
1165 : {
1166 : CPLError( CE_Warning, CPLE_AppDefined,
1167 : "Supersampling not directly supported by ECW toolkit,\n"
1168 0 : "ignoring AdviseRead() request." );
1169 0 : return CE_Warning;
1170 : }
1171 : #endif
1172 :
1173 : /* -------------------------------------------------------------------- */
1174 : /* Adjust band numbers to be zero based. */
1175 : /* -------------------------------------------------------------------- */
1176 : panAdjustedBandList = (int *)
1177 29 : CPLMalloc(sizeof(int) * nBandCount );
1178 60 : for( int ii= 0; ii < nBandCount; ii++ )
1179 31 : panAdjustedBandList[ii] = panBandList[ii] - 1;
1180 :
1181 : /* -------------------------------------------------------------------- */
1182 : /* Cleanup old window cache information. */
1183 : /* -------------------------------------------------------------------- */
1184 29 : CleanupWindow();
1185 :
1186 : /* -------------------------------------------------------------------- */
1187 : /* Set the new requested window. */
1188 : /* -------------------------------------------------------------------- */
1189 29 : CNCSError oErr;
1190 :
1191 : oErr = poFileView->SetView( nBandCount, (UINT32 *) panAdjustedBandList,
1192 : nXOff, nYOff,
1193 : nXOff + nXSize-1, nYOff + nYSize-1,
1194 29 : nBufXSize, nBufYSize );
1195 :
1196 29 : CPLFree( panAdjustedBandList );
1197 29 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
1198 : {
1199 0 : ECWReportError(oErr);
1200 :
1201 0 : bWinActive = FALSE;
1202 0 : return CE_Failure;
1203 : }
1204 :
1205 29 : bWinActive = TRUE;
1206 :
1207 : /* -------------------------------------------------------------------- */
1208 : /* Record selected window. */
1209 : /* -------------------------------------------------------------------- */
1210 29 : nWinXOff = nXOff;
1211 29 : nWinYOff = nYOff;
1212 29 : nWinXSize = nXSize;
1213 29 : nWinYSize = nYSize;
1214 29 : nWinBufXSize = nBufXSize;
1215 29 : nWinBufYSize = nBufYSize;
1216 :
1217 29 : panWinBandList = (int *) CPLMalloc(sizeof(int)*nBandCount);
1218 29 : memcpy( panWinBandList, panBandList, sizeof(int)* nBandCount);
1219 29 : nWinBandCount = nBandCount;
1220 :
1221 29 : nWinBufLoaded = -1;
1222 :
1223 : /* -------------------------------------------------------------------- */
1224 : /* Allocate current scanline buffer. */
1225 : /* -------------------------------------------------------------------- */
1226 29 : papCurLineBuf = (void **) CPLMalloc(sizeof(void*) * nWinBandCount );
1227 60 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
1228 31 : papCurLineBuf[iBand] =
1229 31 : CPLMalloc(nBufXSize * (GDALGetDataTypeSize(eRasterDataType)/8) );
1230 :
1231 29 : return CE_None;
1232 : }
1233 :
1234 : /************************************************************************/
1235 : /* TryWinRasterIO() */
1236 : /* */
1237 : /* Try to satisfy the given request based on the currently */
1238 : /* defined window. Return TRUE on success or FALSE on */
1239 : /* failure. On failure, the caller should satisfy the request */
1240 : /* another way (not report an error). */
1241 : /************************************************************************/
1242 :
1243 12204 : int ECWDataset::TryWinRasterIO( GDALRWFlag eFlag,
1244 : int nXOff, int nYOff, int nXSize, int nYSize,
1245 : GByte *pabyData, int nBufXSize, int nBufYSize,
1246 : GDALDataType eDT,
1247 : int nBandCount, int *panBandList,
1248 : int nPixelSpace, int nLineSpace,
1249 : int nBandSpace )
1250 :
1251 : {
1252 : int iBand, i;
1253 :
1254 : /* -------------------------------------------------------------------- */
1255 : /* Provide default buffer organization. */
1256 : /* -------------------------------------------------------------------- */
1257 12204 : if( nPixelSpace == 0 )
1258 0 : nPixelSpace = GDALGetDataTypeSize( eDT ) / 8;
1259 12204 : if( nLineSpace == 0 )
1260 0 : nLineSpace = nPixelSpace * nBufXSize;
1261 12204 : if( nBandSpace == 0 )
1262 1 : nBandSpace = nLineSpace * nBufYSize;
1263 :
1264 : /* -------------------------------------------------------------------- */
1265 : /* Do some simple tests to see if the current window can */
1266 : /* satisfy our requirement. */
1267 : /* -------------------------------------------------------------------- */
1268 : #ifdef NOISY_DEBUG
1269 : CPLDebug( "ECW", "TryWinRasterIO(%d,%d,%d,%d,%d,%d)",
1270 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1271 : #endif
1272 :
1273 12204 : if( !bWinActive )
1274 54 : return FALSE;
1275 :
1276 12150 : if( nXOff != nWinXOff || nXSize != nWinXSize )
1277 0 : return FALSE;
1278 :
1279 12150 : if( nBufXSize != nWinBufXSize )
1280 0 : return FALSE;
1281 :
1282 25092 : for( iBand = 0; iBand < nBandCount; iBand++ )
1283 : {
1284 14158 : for( i = 0; i < nWinBandCount; i++ )
1285 : {
1286 14150 : if( panWinBandList[i] == panBandList[iBand] )
1287 12942 : break;
1288 : }
1289 :
1290 12950 : if( i == nWinBandCount )
1291 8 : return FALSE;
1292 : }
1293 :
1294 12142 : if( nYOff < nWinYOff || nYOff + nYSize > nWinYOff + nWinYSize )
1295 0 : return FALSE;
1296 :
1297 : /* -------------------------------------------------------------------- */
1298 : /* Now we try more subtle tests. */
1299 : /* -------------------------------------------------------------------- */
1300 : {
1301 : static int nDebugCount = 0;
1302 :
1303 12142 : if( nDebugCount < 30 )
1304 : CPLDebug( "ECW",
1305 : "TryWinRasterIO(%d,%d,%d,%d -> %dx%d) - doing advised read.",
1306 30 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1307 :
1308 12142 : if( nDebugCount == 29 )
1309 1 : CPLDebug( "ECW", "No more TryWinRasterIO messages will be reported" );
1310 :
1311 12142 : nDebugCount++;
1312 : }
1313 :
1314 : /* -------------------------------------------------------------------- */
1315 : /* Actually load data one buffer line at a time. */
1316 : /* -------------------------------------------------------------------- */
1317 : int iBufLine;
1318 :
1319 24284 : for( iBufLine = 0; iBufLine < nBufYSize; iBufLine++ )
1320 : {
1321 12142 : double fFileLine = ((iBufLine+0.5) / nBufYSize) * nYSize + nYOff;
1322 : int iWinLine =
1323 12142 : (int) (((fFileLine - nWinYOff) / nWinYSize) * nWinBufYSize);
1324 :
1325 12142 : if( iWinLine == nWinBufLoaded + 1 )
1326 12142 : LoadNextLine();
1327 :
1328 12142 : if( iWinLine != nWinBufLoaded )
1329 0 : return FALSE;
1330 :
1331 : /* -------------------------------------------------------------------- */
1332 : /* Copy out all our target bands. */
1333 : /* -------------------------------------------------------------------- */
1334 : int iWinBand;
1335 25084 : for( iBand = 0; iBand < nBandCount; iBand++ )
1336 : {
1337 14142 : for( iWinBand = 0; iWinBand < nWinBandCount; iWinBand++ )
1338 : {
1339 14142 : if( panWinBandList[iWinBand] == panBandList[iBand] )
1340 12942 : break;
1341 : }
1342 :
1343 : GDALCopyWords( papCurLineBuf[iWinBand], eRasterDataType,
1344 : GDALGetDataTypeSize( eRasterDataType ) / 8,
1345 : pabyData + nBandSpace * iBand
1346 : + iBufLine * nLineSpace, eDT, nPixelSpace,
1347 12942 : nBufXSize );
1348 : }
1349 : }
1350 :
1351 12142 : return TRUE;
1352 : }
1353 :
1354 : /************************************************************************/
1355 : /* LoadNextLine() */
1356 : /************************************************************************/
1357 :
1358 12142 : CPLErr ECWDataset::LoadNextLine()
1359 :
1360 : {
1361 12142 : if( !bWinActive )
1362 0 : return CE_Failure;
1363 :
1364 12142 : if( nWinBufLoaded == nWinBufYSize-1 )
1365 : {
1366 0 : CleanupWindow();
1367 0 : return CE_Failure;
1368 : }
1369 :
1370 : NCSEcwReadStatus eRStatus;
1371 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
1372 : (UINT16) nWinBandCount,
1373 12142 : papCurLineBuf );
1374 12142 : if( eRStatus != NCSECW_READ_OK )
1375 0 : return CE_Failure;
1376 :
1377 12142 : nWinBufLoaded++;
1378 :
1379 12142 : return CE_None;
1380 : }
1381 :
1382 : /************************************************************************/
1383 : /* CleanupWindow() */
1384 : /************************************************************************/
1385 :
1386 129 : void ECWDataset::CleanupWindow()
1387 :
1388 : {
1389 129 : if( !bWinActive )
1390 100 : return;
1391 :
1392 29 : bWinActive = FALSE;
1393 29 : CPLFree( panWinBandList );
1394 29 : panWinBandList = NULL;
1395 :
1396 60 : for( int iBand = 0; iBand < nWinBandCount; iBand++ )
1397 31 : CPLFree( papCurLineBuf[iBand] );
1398 29 : CPLFree( papCurLineBuf );
1399 29 : papCurLineBuf = NULL;
1400 : }
1401 :
1402 : /************************************************************************/
1403 : /* IRasterIO() */
1404 : /************************************************************************/
1405 :
1406 12180 : CPLErr ECWDataset::IRasterIO( GDALRWFlag eRWFlag,
1407 : int nXOff, int nYOff, int nXSize, int nYSize,
1408 : void * pData, int nBufXSize, int nBufYSize,
1409 : GDALDataType eBufType,
1410 : int nBandCount, int *panBandMap,
1411 : int nPixelSpace, int nLineSpace, int nBandSpace)
1412 :
1413 : {
1414 12180 : if( eRWFlag == GF_Write )
1415 0 : return CE_Failure;
1416 :
1417 12180 : if( nBandCount > 100 )
1418 0 : return CE_Failure;
1419 :
1420 12180 : if( bUseOldBandRasterIOImplementation )
1421 : /* Sanity check. Shouldn't happen */
1422 0 : return CE_Failure;
1423 12180 : int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
1424 :
1425 12180 : if ( nPixelSpace == 0 ){
1426 0 : nPixelSpace = nDataTypeSize;
1427 : }
1428 :
1429 12180 : if (nLineSpace == 0 ) {
1430 0 : nLineSpace = nPixelSpace*nBufXSize;
1431 : }
1432 12180 : if ( nBandSpace == 0 ){
1433 0 : nBandSpace = nDataTypeSize*nBufXSize*nBufYSize;
1434 : }
1435 : /* -------------------------------------------------------------------- */
1436 : /* ECW SDK 3.3 has a bug with the ECW format when we query the */
1437 : /* number of bands of the dataset, but not in the "natural order". */
1438 : /* It ignores the content of panBandMap. (#4234) */
1439 : /* -------------------------------------------------------------------- */
1440 : #if ECWSDK_VERSION < 40
1441 12180 : if( !bIsJPEG2000 && nBandCount == nBands )
1442 : {
1443 : int i;
1444 406 : int bDoBandIRasterIO = FALSE;
1445 1624 : for( i = 0; i < nBandCount; i++ )
1446 : {
1447 1218 : if( panBandMap[i] != i + 1 )
1448 : {
1449 2 : bDoBandIRasterIO = TRUE;
1450 : }
1451 : }
1452 406 : if( bDoBandIRasterIO )
1453 : {
1454 : return GDALDataset::IRasterIO(
1455 : eRWFlag, nXOff, nYOff, nXSize, nYSize,
1456 : pData, nBufXSize, nBufYSize,
1457 : eBufType,
1458 : nBandCount, panBandMap,
1459 1 : nPixelSpace, nLineSpace, nBandSpace);
1460 : }
1461 : }
1462 : #endif
1463 :
1464 : /* -------------------------------------------------------------------- */
1465 : /* Check if we can directly return the data in case we have cached */
1466 : /* it from a previous call in a multi-band reading pattern. */
1467 : /* -------------------------------------------------------------------- */
1468 12179 : if( nBandCount == 1 && *panBandMap > 1 && *panBandMap <= nBands &&
1469 : sCachedMultiBandIO.nXOff == nXOff &&
1470 : sCachedMultiBandIO.nYOff == nYOff &&
1471 : sCachedMultiBandIO.nXSize == nXSize &&
1472 : sCachedMultiBandIO.nYSize == nYSize &&
1473 : sCachedMultiBandIO.nBufXSize == nBufXSize &&
1474 : sCachedMultiBandIO.nBufYSize == nBufYSize &&
1475 : sCachedMultiBandIO.eBufType == eBufType )
1476 : {
1477 11 : sCachedMultiBandIO.nBandsTried ++;
1478 :
1479 11 : if( sCachedMultiBandIO.bEnabled &&
1480 : sCachedMultiBandIO.pabyData != NULL )
1481 : {
1482 : int j;
1483 5 : int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
1484 255 : for(j = 0; j < nBufYSize; j++)
1485 : {
1486 : GDALCopyWords(sCachedMultiBandIO.pabyData +
1487 : (*panBandMap - 1) * nBufXSize * nBufYSize * nDataTypeSize +
1488 : j * nBufXSize * nDataTypeSize,
1489 : eBufType, nDataTypeSize,
1490 : ((GByte*)pData) + j * nLineSpace, eBufType, nDataTypeSize,
1491 250 : nBufXSize);
1492 : }
1493 5 : return CE_None;
1494 : }
1495 :
1496 6 : if( !(sCachedMultiBandIO.bEnabled) &&
1497 : sCachedMultiBandIO.nBandsTried == nBands &&
1498 : CSLTestBoolean(CPLGetConfigOption("ECW_CLEVER", "YES")) )
1499 : {
1500 3 : sCachedMultiBandIO.bEnabled = TRUE;
1501 3 : CPLDebug("ECW", "Detecting successive band reading pattern (for next time)");
1502 : }
1503 : }
1504 :
1505 : /* -------------------------------------------------------------------- */
1506 : /* Try to do it based on existing "advised" access. */
1507 : /* -------------------------------------------------------------------- */
1508 12174 : if( TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1509 : (GByte *) pData, nBufXSize, nBufYSize,
1510 : eBufType, nBandCount, panBandMap,
1511 : nPixelSpace, nLineSpace, nBandSpace ) )
1512 12113 : return CE_None;
1513 :
1514 : /* -------------------------------------------------------------------- */
1515 : /* If we are requesting a single line at 1:1, we do a multi-band */
1516 : /* AdviseRead() and then TryWinRasterIO() again. */
1517 : /* */
1518 : /* Except for reading a 1x1 window when reading a scanline might */
1519 : /* be longer. */
1520 : /* -------------------------------------------------------------------- */
1521 61 : if( nXSize == 1 && nYSize == 1 && nBufXSize == 1 && nBufYSize == 1 )
1522 : {
1523 : /* do nothing */
1524 : }
1525 :
1526 : #if !defined(SDK_CAN_DO_SUPERSAMPLING)
1527 : /* -------------------------------------------------------------------- */
1528 : /* If we are supersampling we need to fall into the general */
1529 : /* purpose logic. */
1530 : /* -------------------------------------------------------------------- */
1531 57 : else if( nXSize < nBufXSize || nYSize < nBufYSize )
1532 : {
1533 1 : bUseOldBandRasterIOImplementation = TRUE;
1534 : CPLErr eErr =
1535 : GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1536 : pData, nBufXSize, nBufYSize,
1537 : eBufType,
1538 : nBandCount, panBandMap,
1539 1 : nPixelSpace, nLineSpace, nBandSpace);
1540 1 : bUseOldBandRasterIOImplementation = FALSE;
1541 1 : return eErr;
1542 : }
1543 : #endif
1544 :
1545 56 : else if( nBufYSize == 1 )
1546 : {
1547 : //JTO: this is tricky, because it expects the rest of the image with this bufer width to be
1548 : //read. The prefered way to achieve this behaviour would be to call AdviseRead before call IRasterIO.
1549 : //ERO; indeed, the logic could be improved to detect successive pattern of single line reading
1550 : //before doing an AdviseRead.
1551 : CPLErr eErr;
1552 :
1553 : eErr = AdviseRead( nXOff, nYOff, nXSize, GetRasterYSize() - nYOff,
1554 : nBufXSize, (nRasterYSize - nYOff) / nYSize, eBufType,
1555 29 : nBandCount, panBandMap, NULL );
1556 29 : if( eErr == CE_None
1557 : && TryWinRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1558 : (GByte *) pData, nBufXSize, nBufYSize,
1559 : eBufType, nBandCount, panBandMap,
1560 : nPixelSpace, nLineSpace, nBandSpace ) )
1561 29 : return CE_None;
1562 : }
1563 :
1564 : CPLDebug( "ECW",
1565 : "RasterIO(%d,%d,%d,%d -> %dx%d) - doing interleaved read.",
1566 31 : nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize );
1567 :
1568 : /* -------------------------------------------------------------------- */
1569 : /* Setup view. */
1570 : /* -------------------------------------------------------------------- */
1571 : UINT32 anBandIndices[100];
1572 : int i;
1573 : NCSError eNCSErr;
1574 31 : CNCSError oErr;
1575 :
1576 74 : for( i = 0; i < nBandCount; i++ )
1577 43 : anBandIndices[i] = panBandMap[i] - 1;
1578 :
1579 31 : CleanupWindow();
1580 :
1581 : /* -------------------------------------------------------------------- */
1582 : /* Cache data in the context of a multi-band reading pattern. */
1583 : /* -------------------------------------------------------------------- */
1584 31 : if( nBandCount == 1 && *panBandMap == 1 && (nBands == 3 || nBands == 4) )
1585 : {
1586 14 : if( sCachedMultiBandIO.bEnabled && sCachedMultiBandIO.nBandsTried != nBands )
1587 : {
1588 1 : sCachedMultiBandIO.bEnabled = FALSE;
1589 1 : CPLDebug("ECW", "Disabling successive band reading pattern");
1590 : }
1591 :
1592 14 : sCachedMultiBandIO.nXOff = nXOff;
1593 14 : sCachedMultiBandIO.nYOff = nYOff;
1594 14 : sCachedMultiBandIO.nXSize = nXSize;
1595 14 : sCachedMultiBandIO.nYSize = nYSize;
1596 14 : sCachedMultiBandIO.nBufXSize = nBufXSize;
1597 14 : sCachedMultiBandIO.nBufYSize = nBufYSize;
1598 14 : sCachedMultiBandIO.eBufType = eBufType;
1599 14 : sCachedMultiBandIO.nBandsTried = 1;
1600 :
1601 14 : int nDataTypeSize = GDALGetDataTypeSize(eBufType) / 8;
1602 :
1603 14 : if( sCachedMultiBandIO.bEnabled )
1604 : {
1605 : GByte* pNew = (GByte*)VSIRealloc(
1606 : sCachedMultiBandIO.pabyData,
1607 2 : nBufXSize * nBufYSize * nBands * nDataTypeSize);
1608 2 : if( pNew == NULL )
1609 0 : CPLFree(sCachedMultiBandIO.pabyData);
1610 2 : sCachedMultiBandIO.pabyData = pNew;
1611 : }
1612 :
1613 14 : if( sCachedMultiBandIO.bEnabled &&
1614 : sCachedMultiBandIO.pabyData != NULL )
1615 : {
1616 8 : for( i = 0; i < nBands; i++ )
1617 6 : anBandIndices[i] = i;
1618 :
1619 : oErr = poFileView->SetView( nBands, anBandIndices,
1620 : nXOff, nYOff,
1621 : nXOff + nXSize - 1,
1622 : nYOff + nYSize - 1,
1623 2 : nBufXSize, nBufYSize );
1624 2 : eNCSErr = oErr.GetErrorNumber();
1625 :
1626 2 : if( eNCSErr != NCS_SUCCESS )
1627 : {
1628 : CPLError( CE_Failure, CPLE_AppDefined,
1629 0 : "%s", NCSGetErrorText(eNCSErr) );
1630 :
1631 0 : return CE_Failure;
1632 : }
1633 :
1634 : CPLErr eErr = ReadBands(sCachedMultiBandIO.pabyData,
1635 : nBufXSize, nBufYSize, eBufType,
1636 : nBands,
1637 : nDataTypeSize,
1638 : nBufXSize * nDataTypeSize,
1639 2 : nBufXSize * nBufYSize * nDataTypeSize);
1640 2 : if( eErr != CE_None )
1641 0 : return eErr;
1642 :
1643 : int j;
1644 102 : for(j = 0; j < nBufYSize; j++)
1645 : {
1646 : GDALCopyWords(sCachedMultiBandIO.pabyData +
1647 : j * nBufXSize * nDataTypeSize,
1648 : eBufType, nDataTypeSize,
1649 : ((GByte*)pData) + j * nLineSpace, eBufType, nDataTypeSize,
1650 100 : nBufXSize);
1651 : }
1652 2 : return CE_None;
1653 : }
1654 : }
1655 :
1656 : oErr = poFileView->SetView( nBandCount, anBandIndices,
1657 : nXOff, nYOff,
1658 : nXOff + nXSize - 1,
1659 : nYOff + nYSize - 1,
1660 29 : nBufXSize, nBufYSize );
1661 29 : eNCSErr = oErr.GetErrorNumber();
1662 :
1663 29 : if( eNCSErr != NCS_SUCCESS )
1664 : {
1665 : CPLError( CE_Failure, CPLE_AppDefined,
1666 0 : "%s", NCSGetErrorText(eNCSErr) );
1667 :
1668 0 : return CE_Failure;
1669 : }
1670 :
1671 : return ReadBands(pData, nBufXSize, nBufYSize, eBufType,
1672 29 : nBandCount, nPixelSpace, nLineSpace, nBandSpace);
1673 : }
1674 :
1675 : /************************************************************************/
1676 : /* ReadBandsDirectly() */
1677 : /************************************************************************/
1678 :
1679 30 : CPLErr ECWDataset::ReadBandsDirectly(void * pData, int nBufXSize, int nBufYSize,
1680 : GDALDataType eBufType,
1681 : int nBandCount,
1682 : int nPixelSpace, int nLineSpace, int nBandSpace)
1683 : {
1684 : CPLDebug( "ECW",
1685 : "ReadBandsDirectly(-> %dx%d) - reading lines directly.",
1686 30 : nBufXSize, nBufYSize);
1687 :
1688 30 : UINT8 **pBIL = (UINT8**)NCSMalloc(nBandCount * sizeof(UINT8*), FALSE);
1689 :
1690 74 : for(int nB = 0; nB < nBandCount; nB++)
1691 : {
1692 44 : pBIL[nB] = ((UINT8*)pData) + (nBandSpace*nB);//for any bit depth
1693 : }
1694 :
1695 5322 : for(int nR = 0; nR < nBufYSize; nR++)
1696 : {
1697 5292 : if (poFileView->ReadLineBIL(eNCSRequestDataType,(UINT16) nBandCount, (void**)pBIL) != NCSECW_READ_OK)
1698 : {
1699 0 : if(pBIL) {
1700 0 : NCSFree(pBIL);
1701 : }
1702 :
1703 0 : return CE_Failure;
1704 : }
1705 12486 : for(int nB = 0; nB < nBandCount; nB++)
1706 : {
1707 7194 : pBIL[nB] += nLineSpace;
1708 : }
1709 : }
1710 30 : if(pBIL)
1711 : {
1712 30 : NCSFree(pBIL);
1713 : }
1714 30 : return CE_None;
1715 : }
1716 :
1717 : /************************************************************************/
1718 : /* ReadBands() */
1719 : /************************************************************************/
1720 :
1721 31 : CPLErr ECWDataset::ReadBands(void * pData, int nBufXSize, int nBufYSize,
1722 : GDALDataType eBufType,
1723 : int nBandCount,
1724 : int nPixelSpace, int nLineSpace, int nBandSpace)
1725 : {
1726 : int i;
1727 : /* -------------------------------------------------------------------- */
1728 : /* Setup working scanline, and the pointers into it. */
1729 : /* -------------------------------------------------------------------- */
1730 31 : int nDataTypeSize = (GDALGetDataTypeSize(eRasterDataType) / 8);
1731 : bool bDirect = (eBufType == eRasterDataType) && nDataTypeSize == nPixelSpace &&
1732 31 : nLineSpace == (nPixelSpace*nBufXSize) && nBandSpace == (nDataTypeSize*nBufXSize*nBufYSize) ;
1733 31 : if (bDirect)
1734 : {
1735 : return ReadBandsDirectly(pData, nBufXSize, nBufYSize,eBufType,
1736 30 : nBandCount, nPixelSpace, nLineSpace, nBandSpace);
1737 : }
1738 : CPLDebug( "ECW",
1739 : "ReadBands(-> %dx%d) - reading lines using GDALCopyWords.",
1740 1 : nBufXSize, nBufYSize);
1741 1 : CPLErr eErr = CE_None;
1742 : GByte *pabyBILScanline = (GByte *) CPLMalloc(nBufXSize * nDataTypeSize *
1743 1 : nBandCount);
1744 1 : GByte **papabyBIL = (GByte **) CPLMalloc(nBandCount * sizeof(void*));
1745 :
1746 4 : for( i = 0; i < nBandCount; i++ )
1747 3 : papabyBIL[i] = pabyBILScanline + i * nBufXSize * nDataTypeSize;
1748 :
1749 : /* -------------------------------------------------------------------- */
1750 : /* Read back all the data for the requested view. */
1751 : /* -------------------------------------------------------------------- */
1752 41 : for( int iScanline = 0; iScanline < nBufYSize; iScanline++ )
1753 : {
1754 : NCSEcwReadStatus eRStatus;
1755 :
1756 : eRStatus = poFileView->ReadLineBIL( eNCSRequestDataType,
1757 : (UINT16) nBandCount,
1758 40 : (void **) papabyBIL );
1759 40 : if( eRStatus != NCSECW_READ_OK )
1760 : {
1761 0 : eErr = CE_Failure;
1762 : CPLError( CE_Failure, CPLE_AppDefined,
1763 0 : "NCScbmReadViewLineBIL failed." );
1764 0 : break;
1765 : }
1766 :
1767 160 : for( i = 0; i < nBandCount; i++ )
1768 : {
1769 : GDALCopyWords(
1770 : pabyBILScanline + i * nDataTypeSize * nBufXSize,
1771 : eRasterDataType, nDataTypeSize,
1772 : ((GByte *) pData) + nLineSpace * iScanline + nBandSpace * i,
1773 : eBufType, nPixelSpace,
1774 120 : nBufXSize );
1775 : }
1776 : }
1777 :
1778 1 : CPLFree( pabyBILScanline );
1779 1 : CPLFree( papabyBIL );
1780 :
1781 1 : return eErr;
1782 : }
1783 :
1784 : /************************************************************************/
1785 : /* IdentifyJPEG2000() */
1786 : /* */
1787 : /* Open method that only supports JPEG2000 files. */
1788 : /************************************************************************/
1789 :
1790 12075 : int ECWDataset::IdentifyJPEG2000( GDALOpenInfo * poOpenInfo )
1791 :
1792 : {
1793 12075 : if( EQUALN(poOpenInfo->pszFilename,"J2K_SUBFILE:",12) )
1794 0 : return TRUE;
1795 :
1796 12075 : else if( poOpenInfo->nHeaderBytes >= 16
1797 : && (memcmp( poOpenInfo->pabyHeader, jpc_header,
1798 : sizeof(jpc_header) ) == 0
1799 : || memcmp( poOpenInfo->pabyHeader, jp2_header,
1800 : sizeof(jp2_header) ) == 0) )
1801 43 : return TRUE;
1802 :
1803 : else
1804 12032 : return FALSE;
1805 : }
1806 :
1807 : /************************************************************************/
1808 : /* OpenJPEG2000() */
1809 : /* */
1810 : /* Open method that only supports JPEG2000 files. */
1811 : /************************************************************************/
1812 :
1813 1965 : GDALDataset *ECWDataset::OpenJPEG2000( GDALOpenInfo * poOpenInfo )
1814 :
1815 : {
1816 1965 : if (!IdentifyJPEG2000(poOpenInfo))
1817 1922 : return NULL;
1818 :
1819 43 : return Open( poOpenInfo, TRUE );
1820 : }
1821 :
1822 : /************************************************************************/
1823 : /* IdentifyECW() */
1824 : /* */
1825 : /* Identify method that only supports ECW files. */
1826 : /************************************************************************/
1827 :
1828 12754 : int ECWDataset::IdentifyECW( GDALOpenInfo * poOpenInfo )
1829 :
1830 : {
1831 : /* -------------------------------------------------------------------- */
1832 : /* This has to either be a file on disk ending in .ecw or a */
1833 : /* ecwp: protocol url. */
1834 : /* -------------------------------------------------------------------- */
1835 12754 : if( (!EQUAL(CPLGetExtension(poOpenInfo->pszFilename),"ecw")
1836 : || poOpenInfo->nHeaderBytes == 0)
1837 : && !EQUALN(poOpenInfo->pszFilename,"ecwp:",5)
1838 : && !EQUALN(poOpenInfo->pszFilename,"ecwps:",5) )
1839 12728 : return FALSE;
1840 :
1841 26 : return TRUE;
1842 : }
1843 :
1844 : /************************************************************************/
1845 : /* OpenECW() */
1846 : /* */
1847 : /* Open method that only supports ECW files. */
1848 : /************************************************************************/
1849 :
1850 2623 : GDALDataset *ECWDataset::OpenECW( GDALOpenInfo * poOpenInfo )
1851 :
1852 : {
1853 2623 : if (!IdentifyECW(poOpenInfo))
1854 2597 : return NULL;
1855 :
1856 26 : return Open( poOpenInfo, FALSE );
1857 : }
1858 :
1859 : /************************************************************************/
1860 : /* OpenFileView() */
1861 : /************************************************************************/
1862 :
1863 69 : CNCSJP2FileView *ECWDataset::OpenFileView( const char *pszDatasetName,
1864 : bool bProgressive,
1865 : int &bUsingCustomStream, bool bWrite )
1866 :
1867 : {
1868 : /* -------------------------------------------------------------------- */
1869 : /* First we try to open it as a normal CNCSFile, letting the */
1870 : /* ECW SDK manage the IO itself. This will only work for real */
1871 : /* files, and ecwp: or ecwps: sources. */
1872 : /* -------------------------------------------------------------------- */
1873 69 : CNCSJP2FileView *poFileView = NULL;
1874 : NCSError eErr;
1875 69 : CNCSError oErr;
1876 :
1877 69 : bUsingCustomStream = FALSE;
1878 69 : poFileView = new CNCSFile();
1879 : //we always open in read only mode. This should be improved in the future.
1880 138 : oErr = poFileView->Open( (char *) pszDatasetName, bProgressive, false );
1881 69 : eErr = oErr.GetErrorNumber();
1882 :
1883 : /* -------------------------------------------------------------------- */
1884 : /* If that did not work, trying opening as a virtual file. */
1885 : /* -------------------------------------------------------------------- */
1886 69 : if( eErr != NCS_SUCCESS )
1887 : {
1888 : CPLDebug( "ECW",
1889 : "NCScbmOpenFileView(%s): eErr=%d, will try VSIL stream.",
1890 16 : pszDatasetName, (int) eErr );
1891 :
1892 16 : delete poFileView;
1893 :
1894 16 : VSILFILE *fpVSIL = VSIFOpenL( pszDatasetName, "rb" );
1895 16 : if( fpVSIL == NULL )
1896 : {
1897 : CPLError( CE_Failure, CPLE_OpenFailed,
1898 0 : "Failed to open %s.", pszDatasetName );
1899 0 : return NULL;
1900 : }
1901 :
1902 16 : if( hECWDatasetMutex == NULL )
1903 : {
1904 0 : hECWDatasetMutex = CPLCreateMutex();
1905 : }
1906 16 : else if( !CPLAcquireMutex( hECWDatasetMutex, 60.0 ) )
1907 : {
1908 0 : CPLDebug( "ECW", "Failed to acquire mutex in 60s." );
1909 : }
1910 : else
1911 : {
1912 16 : CPLDebug( "ECW", "Got mutex." );
1913 : }
1914 16 : VSIIOStream *poIOStream = new VSIIOStream();
1915 32 : poIOStream->Access( fpVSIL, FALSE, pszDatasetName, 0, -1 );
1916 :
1917 16 : poFileView = new CNCSJP2FileView();
1918 32 : oErr = poFileView->Open( poIOStream, bProgressive );
1919 :
1920 : // The CNCSJP2FileView (poFileView) object may not use the iostream
1921 : // (poIOStream) passed to the CNCSJP2FileView::Open() method if an
1922 : // iostream is already available to the ECW JPEG 2000 SDK for a given
1923 : // file. Consequently, if the iostream passed to
1924 : // CNCSJP2FileView::Open() does not become the underlying iostream
1925 : // of the CNCSJP2FileView object, then it should be deleted.
1926 : //
1927 : // In addition, the underlying iostream of the CNCSJP2FileView object
1928 : // should not be deleted until all CNCSJP2FileView objects using the
1929 : // underlying iostream are deleted. Consequently, each time a
1930 : // CNCSJP2FileView object is created, the nFileViewCount attribute
1931 : // of the underlying VSIIOStream object must be incremented for use
1932 : // in the ECWDataset destructor.
1933 :
1934 : VSIIOStream * poUnderlyingIOStream =
1935 16 : ((VSIIOStream *)(poFileView->GetStream()));
1936 :
1937 16 : if ( poUnderlyingIOStream )
1938 15 : poUnderlyingIOStream->nFileViewCount++;
1939 :
1940 16 : if ( poIOStream != poUnderlyingIOStream )
1941 : {
1942 1 : delete poIOStream;
1943 : }
1944 : else
1945 : {
1946 15 : bUsingCustomStream = TRUE;
1947 : }
1948 :
1949 16 : CPLReleaseMutex( hECWDatasetMutex );
1950 :
1951 16 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
1952 : {
1953 1 : if (poFileView)
1954 1 : delete poFileView;
1955 1 : ECWReportError(oErr);
1956 :
1957 1 : return NULL;
1958 : }
1959 : }
1960 :
1961 68 : return poFileView;
1962 : }
1963 :
1964 : /************************************************************************/
1965 : /* Open() */
1966 : /************************************************************************/
1967 :
1968 69 : GDALDataset *ECWDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJPEG2000 )
1969 :
1970 : {
1971 69 : CNCSJP2FileView *poFileView = NULL;
1972 : int i;
1973 69 : int bUsingCustomStream = FALSE;
1974 69 : CPLString osFilename = poOpenInfo->pszFilename;
1975 :
1976 69 : ECWInitialize();
1977 :
1978 : /* -------------------------------------------------------------------- */
1979 : /* If we get a J2K_SUBFILE style name, convert it into the */
1980 : /* corresponding /vsisubfile/ path. */
1981 : /* */
1982 : /* From: J2K_SUBFILE:offset,size,filename */
1983 : /* To: /vsisubfile/offset_size,filename */
1984 : /* -------------------------------------------------------------------- */
1985 69 : if (EQUALN(osFilename,"J2K_SUBFILE:",12))
1986 : {
1987 0 : char** papszTokens = CSLTokenizeString2(osFilename.c_str()+12, ",", 0);
1988 0 : if (CSLCount(papszTokens) >= 2)
1989 : {
1990 : osFilename.Printf( "/vsisubfile/%s_%s,%s",
1991 0 : papszTokens[0], papszTokens[1], papszTokens[2]);
1992 : }
1993 : else
1994 : {
1995 : CPLError( CE_Failure, CPLE_OpenFailed,
1996 0 : "Failed to parse J2K_SUBFILE specification." );
1997 0 : CSLDestroy(papszTokens);
1998 0 : return NULL;
1999 : }
2000 0 : CSLDestroy(papszTokens);
2001 : }
2002 :
2003 : /* -------------------------------------------------------------------- */
2004 : /* Open the client interface. */
2005 : /* -------------------------------------------------------------------- */
2006 69 : poFileView = OpenFileView( osFilename.c_str(), false, bUsingCustomStream, poOpenInfo->eAccess == GA_Update );
2007 69 : if( poFileView == NULL )
2008 1 : return NULL;
2009 :
2010 : /* -------------------------------------------------------------------- */
2011 : /* Create a corresponding GDALDataset. */
2012 : /* -------------------------------------------------------------------- */
2013 : ECWDataset *poDS;
2014 :
2015 68 : poDS = new ECWDataset(bIsJPEG2000);
2016 68 : poDS->poFileView = poFileView;
2017 68 : poDS->eAccess = poOpenInfo->eAccess;
2018 :
2019 : // Disable .aux.xml writing for subfiles and such. Unfortunately
2020 : // this will also disable it in some cases where it might be
2021 : // applicable.
2022 68 : if( bUsingCustomStream )
2023 15 : poDS->nPamFlags |= GPF_DISABLED;
2024 :
2025 68 : poDS->bUsingCustomStream = bUsingCustomStream;
2026 :
2027 : /* -------------------------------------------------------------------- */
2028 : /* Fetch general file information. */
2029 : /* -------------------------------------------------------------------- */
2030 68 : poDS->psFileInfo = poFileView->GetFileInfo();
2031 :
2032 : CPLDebug( "ECW", "FileInfo: SizeXY=%d,%d Bands=%d\n"
2033 : " OriginXY=%g,%g CellIncrementXY=%g,%g\n"
2034 : " ColorSpace=%d, eCellType=%d\n",
2035 : poDS->psFileInfo->nSizeX,
2036 : poDS->psFileInfo->nSizeY,
2037 : poDS->psFileInfo->nBands,
2038 : poDS->psFileInfo->fOriginX,
2039 : poDS->psFileInfo->fOriginY,
2040 : poDS->psFileInfo->fCellIncrementX,
2041 : poDS->psFileInfo->fCellIncrementY,
2042 : (int) poDS->psFileInfo->eColorSpace,
2043 68 : (int) poDS->psFileInfo->eCellType );
2044 :
2045 : /* -------------------------------------------------------------------- */
2046 : /* Establish raster info. */
2047 : /* -------------------------------------------------------------------- */
2048 68 : poDS->nRasterXSize = poDS->psFileInfo->nSizeX;
2049 68 : poDS->nRasterYSize = poDS->psFileInfo->nSizeY;
2050 :
2051 : /* -------------------------------------------------------------------- */
2052 : /* Establish the GDAL data type that corresponds. A few NCS */
2053 : /* data types have no direct corresponding value in GDAL so we */
2054 : /* will coerce to something sufficiently similar. */
2055 : /* -------------------------------------------------------------------- */
2056 68 : poDS->eNCSRequestDataType = poDS->psFileInfo->eCellType;
2057 68 : switch( poDS->psFileInfo->eCellType )
2058 : {
2059 : case NCSCT_UINT8:
2060 57 : poDS->eRasterDataType = GDT_Byte;
2061 57 : break;
2062 :
2063 : case NCSCT_UINT16:
2064 5 : poDS->eRasterDataType = GDT_UInt16;
2065 5 : break;
2066 :
2067 : case NCSCT_UINT32:
2068 : case NCSCT_UINT64:
2069 1 : poDS->eRasterDataType = GDT_UInt32;
2070 1 : poDS->eNCSRequestDataType = NCSCT_UINT32;
2071 1 : break;
2072 :
2073 : case NCSCT_INT8:
2074 : case NCSCT_INT16:
2075 3 : poDS->eRasterDataType = GDT_Int16;
2076 3 : poDS->eNCSRequestDataType = NCSCT_INT16;
2077 3 : break;
2078 :
2079 : case NCSCT_INT32:
2080 : case NCSCT_INT64:
2081 2 : poDS->eRasterDataType = GDT_Int32;
2082 2 : poDS->eNCSRequestDataType = NCSCT_INT32;
2083 2 : break;
2084 :
2085 : case NCSCT_IEEE4:
2086 0 : poDS->eRasterDataType = GDT_Float32;
2087 0 : break;
2088 :
2089 : case NCSCT_IEEE8:
2090 0 : poDS->eRasterDataType = GDT_Float64;
2091 : break;
2092 : }
2093 :
2094 : /* -------------------------------------------------------------------- */
2095 : /* Create band information objects. */
2096 : /* -------------------------------------------------------------------- */
2097 206 : for( i=0; i < poDS->psFileInfo->nBands; i++ )
2098 138 : poDS->SetBand( i+1, new ECWRasterBand( poDS, i+1 ) );
2099 :
2100 : /* -------------------------------------------------------------------- */
2101 : /* Look for supporting coordinate system information. */
2102 : /* -------------------------------------------------------------------- */
2103 68 : if( bIsJPEG2000 )
2104 : {
2105 43 : GDALJP2Metadata oJP2Geo;
2106 43 : if ( oJP2Geo.ReadAndParse( osFilename ) )
2107 : {
2108 25 : poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
2109 25 : poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
2110 : memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
2111 25 : sizeof(double) * 6 );
2112 25 : poDS->nGCPCount = oJP2Geo.nGCPCount;
2113 25 : poDS->pasGCPList = oJP2Geo.pasGCPList;
2114 25 : oJP2Geo.pasGCPList = NULL;
2115 25 : oJP2Geo.nGCPCount = 0;
2116 : }
2117 :
2118 43 : if (oJP2Geo.pszXMPMetadata)
2119 : {
2120 : char *apszMDList[2];
2121 1 : apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
2122 1 : apszMDList[1] = NULL;
2123 1 : poDS->SetMetadata(apszMDList, "xml:XMP");
2124 43 : }
2125 : }
2126 : else
2127 : {
2128 25 : poDS->ECW2WKTProjection();
2129 : }
2130 :
2131 : /* -------------------------------------------------------------------- */
2132 : /* Check for world file. */
2133 : /* -------------------------------------------------------------------- */
2134 68 : if( !poDS->bGeoTransformValid )
2135 : {
2136 : poDS->bGeoTransformValid |=
2137 : GDALReadWorldFile2( osFilename, NULL,
2138 : poDS->adfGeoTransform,
2139 : poOpenInfo->papszSiblingFiles, NULL )
2140 : || GDALReadWorldFile2( osFilename, ".wld",
2141 : poDS->adfGeoTransform,
2142 22 : poOpenInfo->papszSiblingFiles, NULL );
2143 : }
2144 :
2145 : /* -------------------------------------------------------------------- */
2146 : /* Initialize any PAM information. */
2147 : /* -------------------------------------------------------------------- */
2148 68 : poDS->SetDescription( osFilename );
2149 68 : poDS->TryLoadXML();
2150 :
2151 68 : return( poDS );
2152 : }
2153 :
2154 : /************************************************************************/
2155 : /* GetGCPCount() */
2156 : /************************************************************************/
2157 :
2158 7 : int ECWDataset::GetGCPCount()
2159 :
2160 : {
2161 7 : if( nGCPCount != 0 )
2162 3 : return nGCPCount;
2163 : else
2164 4 : return GDALPamDataset::GetGCPCount();
2165 : }
2166 :
2167 : /************************************************************************/
2168 : /* GetGCPProjection() */
2169 : /************************************************************************/
2170 :
2171 2 : const char *ECWDataset::GetGCPProjection()
2172 :
2173 : {
2174 2 : if( nGCPCount > 0 )
2175 2 : return pszProjection;
2176 : else
2177 0 : return GDALPamDataset::GetGCPProjection();
2178 : }
2179 :
2180 : /************************************************************************/
2181 : /* GetGCP() */
2182 : /************************************************************************/
2183 :
2184 3 : const GDAL_GCP *ECWDataset::GetGCPs()
2185 :
2186 : {
2187 3 : if( nGCPCount != 0 )
2188 2 : return pasGCPList;
2189 : else
2190 1 : return GDALPamDataset::GetGCPs();
2191 : }
2192 :
2193 : /************************************************************************/
2194 : /* GetProjectionRef() */
2195 : /* */
2196 : /* We let PAM coordinate system override the one stored inside */
2197 : /* our file. */
2198 : /************************************************************************/
2199 :
2200 43 : const char *ECWDataset::GetProjectionRef()
2201 :
2202 : {
2203 43 : const char* pszPamPrj = GDALPamDataset::GetProjectionRef();
2204 :
2205 43 : if( pszProjection != NULL && strlen(pszPamPrj) == 0 )
2206 28 : return pszProjection;
2207 : else
2208 15 : return pszPamPrj;
2209 : }
2210 :
2211 : /************************************************************************/
2212 : /* GetGeoTransform() */
2213 : /* */
2214 : /* Let the PAM geotransform override the native one if it is */
2215 : /* available. */
2216 : /************************************************************************/
2217 :
2218 29 : CPLErr ECWDataset::GetGeoTransform( double * padfTransform )
2219 :
2220 : {
2221 29 : CPLErr eErr = GDALPamDataset::GetGeoTransform( padfTransform );
2222 :
2223 29 : if( eErr != CE_None && bGeoTransformValid )
2224 : {
2225 24 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
2226 24 : return( CE_None );
2227 : }
2228 : else
2229 5 : return eErr;
2230 : }
2231 :
2232 : /************************************************************************/
2233 : /* GetMetadataItem() */
2234 : /************************************************************************/
2235 :
2236 14 : const char *ECWDataset::GetMetadataItem( const char * pszName,
2237 : const char * pszDomain )
2238 : {
2239 14 : if (!bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") && pszName != NULL)
2240 : {
2241 6 : if (EQUAL(pszName, "PROJ"))
2242 2 : return m_osProjCode.size() ? m_osProjCode.c_str() : "RAW";
2243 4 : if (EQUAL(pszName, "DATUM"))
2244 2 : return m_osDatumCode.size() ? m_osDatumCode.c_str() : "RAW";
2245 2 : if (EQUAL(pszName, "UNITS"))
2246 2 : return m_osUnitsCode.size() ? m_osUnitsCode.c_str() : "METERS";
2247 : }
2248 8 : return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
2249 : }
2250 :
2251 : /************************************************************************/
2252 : /* GetMetadata() */
2253 : /************************************************************************/
2254 :
2255 20 : char **ECWDataset::GetMetadata( const char *pszDomain )
2256 :
2257 : {
2258 20 : if( !bIsJPEG2000 && pszDomain != NULL && EQUAL(pszDomain, "ECW") )
2259 : {
2260 0 : oECWMetadataList.Clear();
2261 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "PROJ", GetMetadataItem("PROJ", "ECW")));
2262 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "DATUM", GetMetadataItem("DATUM", "ECW")));
2263 0 : oECWMetadataList.AddString(CPLSPrintf("%s=%s", "UNITS", GetMetadataItem("UNITS", "ECW")));
2264 0 : return oECWMetadataList.List();
2265 : }
2266 20 : else if( pszDomain == NULL || !EQUAL(pszDomain,"GML") )
2267 20 : return GDALPamDataset::GetMetadata( pszDomain );
2268 : else
2269 0 : return papszGMLMetadata;
2270 : }
2271 :
2272 : /************************************************************************/
2273 : /* ECW2WKTProjection() */
2274 : /* */
2275 : /* Set the dataset pszProjection string in OGC WKT format by */
2276 : /* looking up the ECW (GDT) coordinate system info in */
2277 : /* ecw_cs.dat support data file. */
2278 : /* */
2279 : /* This code is likely still broken in some circumstances. For */
2280 : /* instance, I haven't been careful about changing the linear */
2281 : /* projection parameters (false easting/northing) if the units */
2282 : /* is feet. Lots of cases missing here, and in ecw_cs.dat. */
2283 : /************************************************************************/
2284 :
2285 25 : void ECWDataset::ECW2WKTProjection()
2286 :
2287 : {
2288 25 : if( psFileInfo == NULL )
2289 0 : return;
2290 :
2291 : /* -------------------------------------------------------------------- */
2292 : /* Capture Geotransform. */
2293 : /* */
2294 : /* We will try to ignore the provided file information if it is */
2295 : /* origin (0,0) and pixel size (1,1). I think sometimes I have */
2296 : /* also seen pixel increments of 0 on invalid datasets. */
2297 : /* -------------------------------------------------------------------- */
2298 25 : if( psFileInfo->fOriginX != 0.0
2299 : || psFileInfo->fOriginY != 0.0
2300 : || (psFileInfo->fCellIncrementX != 0.0
2301 : && psFileInfo->fCellIncrementX != 1.0)
2302 : || (psFileInfo->fCellIncrementY != 0.0
2303 : && psFileInfo->fCellIncrementY != 1.0) )
2304 : {
2305 25 : bGeoTransformValid = TRUE;
2306 :
2307 25 : adfGeoTransform[0] = psFileInfo->fOriginX;
2308 25 : adfGeoTransform[1] = psFileInfo->fCellIncrementX;
2309 25 : adfGeoTransform[2] = 0.0;
2310 :
2311 25 : adfGeoTransform[3] = psFileInfo->fOriginY;
2312 25 : adfGeoTransform[4] = 0.0;
2313 25 : adfGeoTransform[5] = -fabs(psFileInfo->fCellIncrementY);
2314 : }
2315 :
2316 : /* -------------------------------------------------------------------- */
2317 : /* do we have projection and datum? */
2318 : /* -------------------------------------------------------------------- */
2319 25 : CPLString osUnits = ECWTranslateFromCellSizeUnits(psFileInfo->eCellSizeUnits);
2320 :
2321 : CPLDebug( "ECW", "projection=%s, datum=%s, units=%s",
2322 : psFileInfo->szProjection, psFileInfo->szDatum,
2323 25 : osUnits.c_str());
2324 :
2325 25 : if( EQUAL(psFileInfo->szProjection,"RAW") )
2326 : return;
2327 :
2328 : /* -------------------------------------------------------------------- */
2329 : /* Set projection if we have it. */
2330 : /* -------------------------------------------------------------------- */
2331 9 : OGRSpatialReference oSRS;
2332 :
2333 : /* For backward-compatible with previous behaviour. Should we only */
2334 : /* restrict to those 2 values ? */
2335 9 : if (psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_METERS &&
2336 : psFileInfo->eCellSizeUnits != ECW_CELL_UNITS_FEET)
2337 0 : osUnits = ECWTranslateFromCellSizeUnits(ECW_CELL_UNITS_METERS);
2338 :
2339 9 : m_osDatumCode = psFileInfo->szDatum;
2340 9 : m_osProjCode = psFileInfo->szProjection;
2341 9 : m_osUnitsCode = osUnits;
2342 9 : if( oSRS.importFromERM( psFileInfo->szProjection,
2343 : psFileInfo->szDatum,
2344 : osUnits ) == OGRERR_NONE )
2345 : {
2346 9 : oSRS.exportToWkt( &pszProjection );
2347 : }
2348 :
2349 9 : CPLErrorReset(); /* see #4187 */
2350 : }
2351 :
2352 : /************************************************************************/
2353 : /* ECWTranslateFromWKT() */
2354 : /************************************************************************/
2355 :
2356 24 : int ECWTranslateFromWKT( const char *pszWKT,
2357 : char *pszProjection,
2358 : int nProjectionLen,
2359 : char *pszDatum,
2360 : int nDatumLen,
2361 : char *pszUnits)
2362 :
2363 : {
2364 24 : OGRSpatialReference oSRS;
2365 24 : char *pszWKTIn = (char *) pszWKT;
2366 :
2367 24 : strcpy( pszProjection, "RAW" );
2368 24 : strcpy( pszDatum, "RAW" );
2369 24 : strcpy( pszUnits, "METERS" );
2370 :
2371 24 : if( pszWKT == NULL || strlen(pszWKT) == 0 )
2372 1 : return FALSE;
2373 :
2374 23 : oSRS.importFromWkt( &pszWKTIn );
2375 :
2376 23 : if( oSRS.IsLocal() )
2377 0 : return TRUE;
2378 :
2379 : /* -------------------------------------------------------------------- */
2380 : /* Do we have an overall EPSG number for this coordinate system? */
2381 : /* -------------------------------------------------------------------- */
2382 23 : const char *pszAuthorityCode = NULL;
2383 23 : const char *pszAuthorityName = NULL;
2384 23 : UINT32 nEPSGCode = 0;
2385 :
2386 23 : if( oSRS.IsProjected() )
2387 : {
2388 6 : pszAuthorityCode = oSRS.GetAuthorityCode( "PROJCS" );
2389 6 : pszAuthorityName = oSRS.GetAuthorityName( "PROJCS" );
2390 : }
2391 17 : else if( oSRS.IsGeographic() )
2392 : {
2393 17 : pszAuthorityCode = oSRS.GetAuthorityCode( "GEOGCS" );
2394 17 : pszAuthorityName = oSRS.GetAuthorityName( "GEOGCS" );
2395 : }
2396 :
2397 23 : if( pszAuthorityName != NULL && EQUAL(pszAuthorityName,"EPSG")
2398 : && pszAuthorityCode != NULL && atoi(pszAuthorityCode) > 0 )
2399 18 : nEPSGCode = (UINT32) atoi(pszAuthorityCode);
2400 :
2401 23 : if( nEPSGCode != 0 )
2402 : {
2403 18 : char *pszEPSGProj = NULL, *pszEPSGDatum = NULL;
2404 18 : CNCSError oErr;
2405 :
2406 : oErr =
2407 : CNCSJP2FileView::GetProjectionAndDatum( atoi(pszAuthorityCode),
2408 18 : &pszEPSGProj, &pszEPSGDatum );
2409 :
2410 : CPLDebug( "ECW", "GetGDTProjDat(%d) = %s/%s",
2411 18 : atoi(pszAuthorityCode), pszEPSGProj, pszEPSGDatum );
2412 :
2413 18 : if( oErr.GetErrorNumber() == NCS_SUCCESS
2414 : && pszEPSGProj != NULL && pszEPSGDatum != NULL )
2415 : {
2416 18 : strncpy( pszProjection, pszEPSGProj, nProjectionLen );
2417 18 : strncpy( pszDatum, pszEPSGDatum, nDatumLen );
2418 18 : pszProjection[nProjectionLen - 1] = 0;
2419 18 : pszDatum[nDatumLen - 1] = 0;
2420 18 : NCSFree( pszEPSGProj );
2421 18 : NCSFree( pszEPSGDatum );
2422 18 : return TRUE;
2423 : }
2424 :
2425 0 : NCSFree( pszEPSGProj );
2426 0 : NCSFree( pszEPSGDatum );
2427 :
2428 : }
2429 :
2430 : /* -------------------------------------------------------------------- */
2431 : /* Fallback to translating based on the ecw_cs.wkt file, and */
2432 : /* various jiffy rules. */
2433 : /* -------------------------------------------------------------------- */
2434 :
2435 5 : return oSRS.exportToERM( pszProjection, pszDatum, pszUnits ) == OGRERR_NONE;
2436 : }
2437 :
2438 : /************************************************************************/
2439 : /* ECWTranslateToCellSizeUnits() */
2440 : /************************************************************************/
2441 :
2442 25 : CellSizeUnits ECWTranslateToCellSizeUnits(const char* pszUnits)
2443 : {
2444 25 : if (EQUAL(pszUnits, "METERS"))
2445 23 : return ECW_CELL_UNITS_METERS;
2446 2 : else if (EQUAL(pszUnits, "DEGREES"))
2447 0 : return ECW_CELL_UNITS_DEGREES;
2448 2 : else if (EQUAL(pszUnits, "FEET"))
2449 2 : return ECW_CELL_UNITS_FEET;
2450 0 : else if (EQUAL(pszUnits, "UNKNOWN"))
2451 0 : return ECW_CELL_UNITS_UNKNOWN;
2452 0 : else if (EQUAL(pszUnits, "INVALID"))
2453 0 : return ECW_CELL_UNITS_INVALID;
2454 : else
2455 : {
2456 0 : CPLError(CE_Warning, CPLE_AppDefined, "Unrecognized value for UNITS : %s", pszUnits);
2457 0 : return ECW_CELL_UNITS_INVALID;
2458 : }
2459 : }
2460 :
2461 : /************************************************************************/
2462 : /* ECWGetColorInterpretationByName() */
2463 : /************************************************************************/
2464 :
2465 28 : GDALColorInterp ECWGetColorInterpretationByName(const char *pszName)
2466 : {
2467 28 : if (EQUAL(pszName, NCS_BANDDESC_AllOpacity))
2468 1 : return GCI_AlphaBand;
2469 27 : else if (EQUAL(pszName, NCS_BANDDESC_Blue))
2470 0 : return GCI_BlueBand;
2471 27 : else if (EQUAL(pszName, NCS_BANDDESC_Green))
2472 0 : return GCI_GreenBand;
2473 27 : else if (EQUAL(pszName, NCS_BANDDESC_Red))
2474 0 : return GCI_RedBand;
2475 27 : else if (EQUAL(pszName, NCS_BANDDESC_Greyscale))
2476 0 : return GCI_GrayIndex;
2477 27 : else if (EQUAL(pszName, NCS_BANDDESC_GreyscaleOpacity))
2478 0 : return GCI_AlphaBand;
2479 27 : return GCI_Undefined;
2480 : }
2481 :
2482 : /************************************************************************/
2483 : /* ECWGetColorInterpretationName() */
2484 : /************************************************************************/
2485 :
2486 40 : const char* ECWGetColorInterpretationName(GDALColorInterp eColorInterpretation, int nBandNumber)
2487 : {
2488 : const char *result;
2489 40 : switch (eColorInterpretation){
2490 : case GCI_AlphaBand:
2491 1 : result = NCS_BANDDESC_AllOpacity;
2492 1 : break;
2493 : case GCI_GrayIndex:
2494 19 : result = NCS_BANDDESC_Greyscale;
2495 19 : break;
2496 : case GCI_RedBand:
2497 : case GCI_GreenBand:
2498 : case GCI_BlueBand:
2499 15 : result = GDALGetColorInterpretationName(eColorInterpretation);
2500 15 : break;
2501 : case GCI_Undefined:
2502 5 : if (nBandNumber <=3){
2503 4 : if (nBandNumber == 0 ) {
2504 0 : result = "Red";
2505 4 : }else if (nBandNumber == 1) {
2506 2 : result = "Green";
2507 2 : }else if (nBandNumber == 2) {
2508 1 : result = "Blue";
2509 : }
2510 : }
2511 5 : result = CPLSPrintf(NCS_BANDDESC_Band,nBandNumber + 1);
2512 5 : break;
2513 : default:
2514 0 : result = CPLSPrintf(NCS_BANDDESC_Band,nBandNumber + 1);
2515 : }
2516 40 : return result;
2517 : }
2518 :
2519 : /************************************************************************/
2520 : /* ECWTranslateFromCellSizeUnits() */
2521 : /************************************************************************/
2522 :
2523 51 : const char* ECWTranslateFromCellSizeUnits(CellSizeUnits eUnits)
2524 : {
2525 51 : if (eUnits == ECW_CELL_UNITS_METERS)
2526 47 : return "METERS";
2527 4 : else if (eUnits == ECW_CELL_UNITS_DEGREES)
2528 0 : return "DEGREES";
2529 4 : else if (eUnits == ECW_CELL_UNITS_FEET)
2530 4 : return "FEET";
2531 0 : else if (eUnits == ECW_CELL_UNITS_UNKNOWN)
2532 0 : return "UNKNOWN";
2533 : else
2534 0 : return "INVALID";
2535 : }
2536 :
2537 : #endif /* def FRMT_ecw */
2538 :
2539 : /************************************************************************/
2540 : /* ECWInitialize() */
2541 : /* */
2542 : /* Initialize NCS library. We try to defer this as late as */
2543 : /* possible since de-initializing it seems to be expensive/slow */
2544 : /* on some system. */
2545 : /************************************************************************/
2546 :
2547 119 : void ECWInitialize()
2548 :
2549 : {
2550 119 : CPLMutexHolder oHolder( &hECWDatasetMutex );
2551 :
2552 119 : if( bNCSInitialized )
2553 : return;
2554 :
2555 : #ifndef WIN32
2556 3 : NCSecwInit();
2557 : #endif
2558 3 : bNCSInitialized = TRUE;
2559 :
2560 : /* -------------------------------------------------------------------- */
2561 : /* This will disable automatic conversion of YCbCr to RGB by */
2562 : /* the toolkit. */
2563 : /* -------------------------------------------------------------------- */
2564 3 : if( !CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB","YES") ) )
2565 0 : NCSecwSetConfig(NCSCFG_JP2_MANAGE_ICC, FALSE);
2566 : #if ECWSDK_VERSION>= 50
2567 : NCSecwSetConfig(NCSCFG_ECWP_CLIENT_HTTP_USER_AGENT, "ECW GDAL Driver/" NCS_ECWJP2_FULL_VERSION_STRING_DOT_DEL);
2568 : #endif
2569 : /* -------------------------------------------------------------------- */
2570 : /* Initialize cache memory limit. Default is apparently 1/4 RAM. */
2571 : /* -------------------------------------------------------------------- */
2572 : const char *pszEcwCacheSize =
2573 3 : CPLGetConfigOption("GDAL_ECW_CACHE_MAXMEM",NULL);
2574 3 : if( pszEcwCacheSize == NULL )
2575 3 : pszEcwCacheSize = CPLGetConfigOption("ECW_CACHE_MAXMEM",NULL);
2576 :
2577 3 : if( pszEcwCacheSize != NULL )
2578 0 : NCSecwSetConfig(NCSCFG_CACHE_MAXMEM, (UINT32) atoi(pszEcwCacheSize) );
2579 :
2580 : /* -------------------------------------------------------------------- */
2581 : /* Version 3.x and 4.x of the ECWJP2 SDK did not resolve datum and */
2582 : /* projection to EPSG code using internal mapping. */
2583 : /* Version 5.x do so we provide means to achieve old */
2584 : /* behaviour. */
2585 : /* -------------------------------------------------------------------- */
2586 : #if ECWSDK_VERSION >= 50
2587 : if( CSLTestBoolean( CPLGetConfigOption("ECW_DO_NOT_RESOLVE_DATUM_PROJECTION","NO") ) == TRUE)
2588 : NCSecwSetConfig(NCSCFG_PROJECTION_FORMAT, NCS_PROJECTION_ERMAPPER_FORMAT);
2589 : #endif
2590 : /* -------------------------------------------------------------------- */
2591 : /* Allow configuration of a local cache based on configuration */
2592 : /* options. Setting the location turns things on. */
2593 : /* -------------------------------------------------------------------- */
2594 : const char *pszOpt;
2595 :
2596 : #if ECWSDK_VERSION >= 40
2597 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_SIZE_MB", NULL );
2598 : if( pszOpt )
2599 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_SIZE_MB, (INT32) atoi( pszOpt ) );
2600 :
2601 : pszOpt = CPLGetConfigOption( "ECWP_CACHE_LOCATION", NULL );
2602 : if( pszOpt )
2603 : {
2604 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_LOCATION, pszOpt );
2605 : NCSecwSetConfig( NCSCFG_ECWP_CACHE_ENABLED, (BOOLEAN) TRUE );
2606 : }
2607 : #endif
2608 :
2609 : /* -------------------------------------------------------------------- */
2610 : /* Various other configuration items. */
2611 : /* -------------------------------------------------------------------- */
2612 3 : pszOpt = CPLGetConfigOption( "ECWP_BLOCKING_TIME_MS", NULL );
2613 3 : if( pszOpt )
2614 : NCSecwSetConfig( NCSCFG_BLOCKING_TIME_MS,
2615 0 : (NCSTimeStampMs) atoi(pszOpt) );
2616 :
2617 : // I believe 10s means we wait for complete data back from
2618 : // ECWP almost all the time which is good for our blocking model.
2619 3 : pszOpt = CPLGetConfigOption( "ECWP_REFRESH_TIME_MS", "10000" );
2620 3 : if( pszOpt )
2621 : NCSecwSetConfig( NCSCFG_REFRESH_TIME_MS,
2622 3 : (NCSTimeStampMs) atoi(pszOpt) );
2623 :
2624 3 : pszOpt = CPLGetConfigOption( "ECW_TEXTURE_DITHER", NULL );
2625 3 : if( pszOpt )
2626 : NCSecwSetConfig( NCSCFG_TEXTURE_DITHER,
2627 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2628 :
2629 :
2630 3 : pszOpt = CPLGetConfigOption( "ECW_FORCE_FILE_REOPEN", NULL );
2631 3 : if( pszOpt )
2632 : NCSecwSetConfig( NCSCFG_FORCE_FILE_REOPEN,
2633 0 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2634 :
2635 3 : pszOpt = CPLGetConfigOption( "ECW_CACHE_MAXOPEN", NULL );
2636 3 : if( pszOpt )
2637 0 : NCSecwSetConfig( NCSCFG_CACHE_MAXOPEN, (UINT32) atoi(pszOpt) );
2638 :
2639 : #if ECWSDK_VERSION >= 40
2640 : pszOpt = CPLGetConfigOption( "ECW_AUTOGEN_J2I", NULL );
2641 : if( pszOpt )
2642 : NCSecwSetConfig( NCSCFG_JP2_AUTOGEN_J2I,
2643 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2644 :
2645 : pszOpt = CPLGetConfigOption( "ECW_OPTIMIZE_USE_NEAREST_NEIGHBOUR", NULL );
2646 : if( pszOpt )
2647 : NCSecwSetConfig( NCSCFG_OPTIMIZE_USE_NEAREST_NEIGHBOUR,
2648 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2649 :
2650 :
2651 : pszOpt = CPLGetConfigOption( "ECW_RESILIENT_DECODING", NULL );
2652 : if( pszOpt )
2653 : NCSecwSetConfig( NCSCFG_RESILIENT_DECODING,
2654 : (BOOLEAN) CSLTestBoolean( pszOpt ) );
2655 : #endif
2656 : }
2657 :
2658 : /************************************************************************/
2659 : /* GDALDeregister_ECW() */
2660 : /************************************************************************/
2661 :
2662 550 : void GDALDeregister_ECW( GDALDriver * )
2663 :
2664 : {
2665 : /* For unknown reason, this cleanup can take up to 3 seconds (see #3134). */
2666 : /* Not worth it */
2667 : #ifdef notdef
2668 : if( bNCSInitialized )
2669 : {
2670 : bNCSInitialized = FALSE;
2671 : #ifndef WIN32
2672 : NCSecwShutdown();
2673 : #endif
2674 : }
2675 :
2676 : if( hECWDatasetMutex != NULL )
2677 : {
2678 : CPLDestroyMutex( hECWDatasetMutex );
2679 : hECWDatasetMutex = NULL;
2680 : }
2681 : #endif
2682 550 : }
2683 :
2684 : /************************************************************************/
2685 : /* GDALRegister_ECW() */
2686 : /************************************************************************/
2687 :
2688 : /* Needed for v4.3 and v5.0 */
2689 : #if !defined(NCS_ECWSDK_VERSION_STRING) && defined(NCS_ECWJP2_VERSION_STRING)
2690 : #define NCS_ECWSDK_VERSION_STRING NCS_ECWJP2_VERSION_STRING
2691 : #endif
2692 :
2693 610 : void GDALRegister_ECW()
2694 :
2695 : {
2696 : #ifdef FRMT_ecw
2697 : GDALDriver *poDriver;
2698 :
2699 610 : if (! GDAL_CHECK_VERSION("ECW driver"))
2700 0 : return;
2701 :
2702 610 : if( GDALGetDriverByName( "ECW" ) == NULL )
2703 : {
2704 588 : poDriver = new GDALDriver();
2705 :
2706 588 : poDriver->SetDescription( "ECW" );
2707 :
2708 588 : CPLString osLongName = "ERDAS Compressed Wavelets (SDK ";
2709 :
2710 : #ifdef NCS_ECWSDK_VERSION_STRING
2711 : osLongName += NCS_ECWSDK_VERSION_STRING;
2712 : #else
2713 588 : osLongName += "3.x";
2714 : #endif
2715 588 : osLongName += ")";
2716 :
2717 588 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2718 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2719 588 : "frmt_ecw.html" );
2720 588 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "ecw" );
2721 :
2722 588 : poDriver->pfnIdentify = ECWDataset::IdentifyECW;
2723 588 : poDriver->pfnOpen = ECWDataset::OpenECW;
2724 588 : poDriver->pfnUnloadDriver = GDALDeregister_ECW;
2725 : #ifdef HAVE_COMPRESS
2726 : // The create method seems not to work properly.
2727 : // poDriver->pfnCreate = ECWCreateECW;
2728 588 : poDriver->pfnCreateCopy = ECWCreateCopyECW;
2729 : #if ECWSDK_VERSION >= 50
2730 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2731 : "Byte UInt16" );
2732 : #else
2733 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2734 588 : "Byte" );
2735 : #endif
2736 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2737 : "<CreationOptionList>"
2738 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2739 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2740 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2741 :
2742 : #if ECWSDK_VERSION < 40
2743 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2744 : #else
2745 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2746 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2747 : #endif
2748 :
2749 : #if ECWSDK_VERSION >= 50
2750 : " <Option name='ECW_FORMAT_VERSION' type='integer' description='ECW format version (2 or 3).' default='2'/>"
2751 : #endif
2752 :
2753 588 : "</CreationOptionList>" );
2754 : #else
2755 : /* In read-only mode, we support VirtualIO. This is not the case */
2756 : /* for ECWCreateCopyECW() */
2757 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2758 : #endif
2759 :
2760 588 : GetGDALDriverManager()->RegisterDriver( poDriver );
2761 : }
2762 : #endif /* def FRMT_ecw */
2763 : }
2764 :
2765 : /************************************************************************/
2766 : /* GDALRegister_ECW_JP2ECW() */
2767 : /* */
2768 : /* This function exists so that when built as a plugin, there */
2769 : /* is a function that will register both drivers. */
2770 : /************************************************************************/
2771 :
2772 0 : void GDALRegister_ECW_JP2ECW()
2773 :
2774 : {
2775 0 : GDALRegister_ECW();
2776 0 : GDALRegister_JP2ECW();
2777 0 : }
2778 :
2779 : /************************************************************************/
2780 : /* ECWDatasetOpenJPEG2000() */
2781 : /************************************************************************/
2782 17 : GDALDataset* ECWDatasetOpenJPEG2000(GDALOpenInfo* poOpenInfo)
2783 : {
2784 17 : return ECWDataset::OpenJPEG2000(poOpenInfo);
2785 : }
2786 :
2787 : /************************************************************************/
2788 : /* GDALRegister_JP2ECW() */
2789 : /************************************************************************/
2790 610 : void GDALRegister_JP2ECW()
2791 :
2792 : {
2793 : #ifdef FRMT_ecw
2794 : GDALDriver *poDriver;
2795 :
2796 610 : if (! GDAL_CHECK_VERSION("JP2ECW driver"))
2797 0 : return;
2798 :
2799 610 : if( GDALGetDriverByName( "JP2ECW" ) == NULL )
2800 : {
2801 588 : poDriver = new GDALDriver();
2802 :
2803 588 : poDriver->SetDescription( "JP2ECW" );
2804 :
2805 588 : CPLString osLongName = "ERDAS JPEG2000 (SDK ";
2806 :
2807 : #ifdef NCS_ECWSDK_VERSION_STRING
2808 : osLongName += NCS_ECWSDK_VERSION_STRING;
2809 : #else
2810 588 : osLongName += "3.x";
2811 : #endif
2812 588 : osLongName += ")";
2813 :
2814 588 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, osLongName );
2815 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC,
2816 588 : "frmt_jp2ecw.html" );
2817 588 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
2818 588 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
2819 :
2820 588 : poDriver->pfnIdentify = ECWDataset::IdentifyJPEG2000;
2821 588 : poDriver->pfnOpen = ECWDataset::OpenJPEG2000;
2822 : #ifdef HAVE_COMPRESS
2823 588 : poDriver->pfnCreate = ECWCreateJPEG2000;
2824 588 : poDriver->pfnCreateCopy = ECWCreateCopyJPEG2000;
2825 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
2826 588 : "Byte UInt16 Int16 UInt32 Int32 Float32 Float64" );
2827 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
2828 : "<CreationOptionList>"
2829 : " <Option name='TARGET' type='float' description='Compression Percentage' />"
2830 : " <Option name='PROJ' type='string' description='ECW Projection Name'/>"
2831 : " <Option name='DATUM' type='string' description='ECW Datum Name' />"
2832 : " <Option name='UNITS' type='string-select' description='ECW Projection Units'>"
2833 : " <Value>METERS</Value>"
2834 : " <Value>FEET</Value>"
2835 : " </Option>"
2836 :
2837 : #if ECWSDK_VERSION < 40
2838 : " <Option name='LARGE_OK' type='boolean' description='Enable compressing 500+MB files'/>"
2839 : #else
2840 : " <Option name='ECW_ENCODE_KEY' type='string' description='OEM Compress Key from ERDAS.'/>"
2841 : " <Option name='ECW_ENCODE_COMPANY' type='string' description='OEM Company Name.'/>"
2842 : #endif
2843 :
2844 : " <Option name='GeoJP2' type='boolean' description='defaults to ON'/>"
2845 : " <Option name='GMLJP2' type='boolean' description='defaults to ON'/>"
2846 : " <Option name='PROFILE' type='string-select'>"
2847 : " <Value>BASELINE_0</Value>"
2848 : " <Value>BASELINE_1</Value>"
2849 : " <Value>BASELINE_2</Value>"
2850 : " <Value>NPJE</Value>"
2851 : " <Value>EPJE</Value>"
2852 : " </Option>"
2853 : " <Option name='PROGRESSION' type='string-select'>"
2854 : " <Value>LRCP</Value>"
2855 : " <Value>RLCP</Value>"
2856 : " <Value>RPCL</Value>"
2857 : " </Option>"
2858 : " <Option name='CODESTREAM_ONLY' type='boolean' description='No JP2 wrapper'/>"
2859 : " <Option name='LEVELS' type='int'/>"
2860 : " <Option name='LAYERS' type='int'/>"
2861 : " <Option name='PRECINCT_WIDTH' type='int'/>"
2862 : " <Option name='PRECINCT_HEIGHT' type='int'/>"
2863 : " <Option name='TILE_WIDTH' type='int'/>"
2864 : " <Option name='TILE_HEIGHT' type='int'/>"
2865 : " <Option name='INCLUDE_SOP' type='boolean'/>"
2866 : " <Option name='INCLUDE_EPH' type='boolean'/>"
2867 : " <Option name='DECOMPRESS_LAYERS' type='int'/>"
2868 : " <Option name='DECOMPRESS_RECONSTRUCTION_PARAMETER' type='float'/>"
2869 588 : "</CreationOptionList>" );
2870 : #endif
2871 :
2872 588 : GetGDALDriverManager()->RegisterDriver( poDriver );
2873 : }
2874 : #endif /* def FRMT_ecw */
2875 : }
|