1 /******************************************************************************
2 * $Id: ecwcreatecopy.cpp 29054 2015-04-29 19:31:41Z rouault $
3 *
4 * Project: GDAL ECW Driver
5 * Purpose: ECW CreateCopy method implementation.
6 * Author: Frank Warmerdam, warmerdam@pobox.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2001, 2004, Frank Warmerdam <warmerdam@pobox.com>
10 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 * DEALINGS IN THE SOFTWARE.
29 ****************************************************************************/
30
31 #include "gdal_ecw.h"
32 #include "gdaljp2metadata.h"
33 #include "ogr_spatialref.h"
34
35 CPL_CVSID("$Id: ecwcreatecopy.cpp 29054 2015-04-29 19:31:41Z rouault $");
36
37 #if defined(FRMT_ecw) && defined(HAVE_COMPRESS)
38
39 #define OPTIMIZED_FOR_GDALWARP
40
41 #if ECWSDK_VERSION>=50
42 static
GetCompressionSoftwareName()43 CPLString GetCompressionSoftwareName(){
44 CPLString osRet;
45 char szProcessName[2048];
46
47 /* For privacy reason, allow the user to not write the software name in the ECW */
48 if( !CSLTestBoolean(CPLGetConfigOption("GDAL_ECW_WRITE_COMPRESSION_SOFTWARE", "YES")) )
49 return osRet;
50
51 if( CPLGetExecPath( szProcessName, sizeof(szProcessName) - 1 ) )
52 {
53 szProcessName[sizeof(szProcessName) - 1] = 0;
54 #ifdef WIN32
55 char* szLastSlash = strrchr(szProcessName, '\\');
56 #else
57 char* szLastSlash = strrchr(szProcessName, '/');
58 #endif
59 if( szLastSlash != NULL )
60 memmove(szProcessName, szLastSlash + 1, strlen(szLastSlash + 1) + 1);
61 }
62 else
63 strcpy(szProcessName, "Unknown");
64
65 osRet.Printf("%s/GDAL v%d.%d.%d.%d/ECWJP2 SDK v%s",
66 szProcessName,
67 GDAL_VERSION_MAJOR,
68 GDAL_VERSION_MINOR,
69 GDAL_VERSION_REV,
70 GDAL_VERSION_BUILD,
71 NCS_ECWJP2_FULL_VERSION_STRING_DOT_DEL);
72 return osRet;
73 };
74 #endif
75
76 class GDALECWCompressor : public CNCSFile {
77
78 public:
79 GDALECWCompressor();
80 virtual ~GDALECWCompressor();
81 virtual CNCSError WriteReadLine(UINT32 nNextLine, void **ppInputArray);
82 #if ECWSDK_VERSION>=50
83 virtual void WriteStatus(IEEE4 fPercentComplete, const NCS::CString &sStatusText, const CompressionCounters &Counters);
84 #else
85 virtual void WriteStatus(UINT32 nCurrentLine);
86 #endif
87
88 virtual bool WriteCancel();
89
90 CPLErr Initialize( const char *pszFilename, char **papszOptions,
91 int nXSize, int nYSize, int nBands, const char * const * papszBandDescriptions, int bRGBColorSpace,
92 GDALDataType eType,
93 const char *pszWKT, double *padfGeoTransform,
94 int nGCPCount, const GDAL_GCP *pasGCPList,
95 int bIsJPEG2000, int bPixelIsPoint, char** papszRPCMD,
96 GDALDataset* poSrcDS = NULL );
97 CPLErr CloseDown();
98
99 CPLErr PrepareCoverageBox( const char *pszWKT, double *padfGeoTransform );
100 CPLErr WriteJP2Box( GDALJP2Box * );
101 void WriteXMLBoxes();
102 CPLErr WriteLineBIL(UINT16 nBands, void **ppOutputLine, UINT32 *pLineSteps = NULL);
WriteReadLineGetCellType()103 virtual NCSEcwCellType WriteReadLineGetCellType() {
104 return sFileInfo.eCellType;
105 }
106 #ifdef ECW_FW
107 CNCSJP2File::CNCSJPXAssocBox m_oGMLAssoc;
108 #endif
109
110 // Data
111
112 GDALDataset *m_poSrcDS;
113
114 VSIIOStream m_OStream;
115 int m_nPercentComplete;
116
117 int m_bCancelled;
118
119 GDALProgressFunc pfnProgress;
120 void *pProgressData;
121
122
123 GDALDataType eWorkDT;
124
125 JP2UserBox** papoJP2UserBox;
126 int nJP2UserBox;
127
128 private :
129 NCSFileViewFileInfoEx sFileInfo;
130 };
131
132 /************************************************************************/
133 /* GDALECWCompressor() */
134 /************************************************************************/
135
GDALECWCompressor()136 GDALECWCompressor::GDALECWCompressor()
137
138 {
139 m_poSrcDS = NULL;
140 m_nPercentComplete = -1;
141 m_bCancelled = FALSE;
142 pfnProgress = GDALDummyProgress;
143 pProgressData = NULL;
144 papoJP2UserBox = NULL;
145 nJP2UserBox = 0;
146 #if ECWSDK_VERSION>=50
147 NCSInitFileInfo(&sFileInfo);
148 #else
149 NCSInitFileInfoEx(&sFileInfo);
150 #endif
151 }
152
153 /************************************************************************/
154 /* ~GDALECWCompressor() */
155 /************************************************************************/
156
~GDALECWCompressor()157 GDALECWCompressor::~GDALECWCompressor()
158
159 {
160 int i;
161 for(i=0;i<nJP2UserBox;i++)
162 delete papoJP2UserBox[i];
163 CPLFree(papoJP2UserBox);
164 }
165
166 /************************************************************************/
167 /* CloseDown() */
168 /************************************************************************/
169
CloseDown()170 CPLErr GDALECWCompressor::CloseDown()
171
172 {
173 #if ECWSDK_VERSION>=50
174 NCSFreeFileInfo(&sFileInfo);
175 #else
176 for( int i = 0; i < sFileInfo.nBands; i++ )
177 {
178 CPLFree( sFileInfo.pBands[i].szDesc );
179 }
180 CPLFree( sFileInfo.pBands );
181 #endif
182
183 Close( true );
184 m_OStream.Close();
185
186 return CE_None;
187 }
188
189 /************************************************************************/
190 /* WriteReadLine() */
191 /************************************************************************/
192
WriteReadLine(UINT32 nNextLine,void ** ppInputArray)193 CNCSError GDALECWCompressor::WriteReadLine( UINT32 nNextLine,
194 void **ppInputArray )
195
196 {
197 int iBand, *panBandMap;
198 CPLErr eErr;
199 GByte *pabyLineBuf;
200 int nWordSize = GDALGetDataTypeSize( eWorkDT ) / 8;
201
202 #ifdef DEBUG_VERBOSE
203 CPLDebug("ECW", "nNextLine = %d", nNextLine);
204 #endif
205
206 panBandMap = (int *) CPLMalloc(sizeof(int) * sFileInfo.nBands);
207 for( iBand = 0; iBand < sFileInfo.nBands; iBand++ )
208 panBandMap[iBand] = iBand+1;
209
210 pabyLineBuf = (GByte *) CPLMalloc( sFileInfo.nSizeX * sFileInfo.nBands
211 * nWordSize );
212
213 eErr = m_poSrcDS->RasterIO( GF_Read, 0, nNextLine, sFileInfo.nSizeX, 1,
214 pabyLineBuf, sFileInfo.nSizeX, 1,
215 eWorkDT,
216 sFileInfo.nBands, panBandMap,
217 nWordSize, 0, nWordSize * sFileInfo.nSizeX, NULL );
218
219 for( iBand = 0; iBand < (int) sFileInfo.nBands; iBand++ )
220 {
221 memcpy( ppInputArray[iBand],
222 pabyLineBuf + nWordSize * sFileInfo.nSizeX * iBand,
223 nWordSize * sFileInfo.nSizeX );
224 }
225
226 CPLFree( pabyLineBuf );
227 CPLFree( panBandMap );
228
229 if( eErr == CE_None )
230 return NCS_SUCCESS;
231 else
232 return NCS_FILEIO_ERROR;
233 }
234
235 /************************************************************************/
236 /* WriteStatus() */
237 /************************************************************************/
238 #if ECWSDK_VERSION>=50
WriteStatus(IEEE4 fPercentComplete,const NCS::CString & sStatusText,const CompressionCounters & Counters)239 void GDALECWCompressor::WriteStatus(IEEE4 fPercentComplete, const NCS::CString &sStatusText, const CompressionCounters &Counters)
240 {
241 std::string sStatusUTF8;
242 sStatusText.utf8_str(sStatusUTF8);
243
244 m_bCancelled = !pfnProgress(
245 fPercentComplete/100.0,
246 sStatusUTF8.c_str(),
247 pProgressData );
248 }
249 #else
250
WriteStatus(UINT32 nCurrentLine)251 void GDALECWCompressor::WriteStatus( UINT32 nCurrentLine )
252
253 {
254 m_bCancelled =
255 !pfnProgress( nCurrentLine / (float) sFileInfo.nSizeY,
256 NULL, pProgressData );
257 }
258 #endif
259 /************************************************************************/
260 /* WriteCancel() */
261 /************************************************************************/
262
WriteCancel()263 bool GDALECWCompressor::WriteCancel()
264
265 {
266 return (bool) m_bCancelled;
267 }
268
269 /************************************************************************/
270 /* PrepareCoverageBox() */
271 /************************************************************************/
272
PrepareCoverageBox(CPL_UNUSED const char * pszWKT,CPL_UNUSED double * padfGeoTransform)273 CPLErr GDALECWCompressor::PrepareCoverageBox(
274 #ifndef ECW_FW
275 CPL_UNUSED
276 #endif
277 const char *pszWKT,
278 #ifndef ECW_FW
279 CPL_UNUSED
280 #endif
281 double *padfGeoTransform )
282
283 {
284 #ifndef ECW_FW
285 return CE_Failure;
286 #else
287 /* -------------------------------------------------------------------- */
288 /* Try do determine a PCS or GCS code we can use. */
289 /* -------------------------------------------------------------------- */
290 OGRSpatialReference oSRS;
291 char *pszWKTCopy = (char *) pszWKT;
292 int nEPSGCode = 0;
293 char szSRSName[100];
294
295 if( oSRS.importFromWkt( &pszWKTCopy ) != OGRERR_NONE )
296 return CE_Failure;
297
298 if( oSRS.IsProjected() )
299 {
300 const char *pszAuthName = oSRS.GetAuthorityName( "PROJCS" );
301
302 if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
303 {
304 nEPSGCode = atoi(oSRS.GetAuthorityCode( "PROJCS" ));
305 }
306 }
307 else if( oSRS.IsGeographic() )
308 {
309 const char *pszAuthName = oSRS.GetAuthorityName( "GEOGCS" );
310
311 if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
312 {
313 nEPSGCode = atoi(oSRS.GetAuthorityCode( "GEOGCS" ));
314 }
315 }
316
317 if( nEPSGCode != 0 )
318 sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
319 else
320 strcpy( szSRSName,
321 "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
322
323 /* -------------------------------------------------------------------- */
324 /* For now we hardcode for a minimal instance format. */
325 /* -------------------------------------------------------------------- */
326 char szDoc[4000];
327
328 CPLsprintf( szDoc,
329 "<gml:FeatureCollection\n"
330 " xmlns:gml=\"http://www.opengis.net/gml\"\n"
331 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
332 " xsi:schemaLocation=\"http://www.opengis.net/gml http://www.math.ubc.ca/~burggraf/gml/gml4jp2.xsd\">\n"
333 " <gml:boundedBy>\n"
334 " <gml:Null>withheld</gml:Null>\n"
335 " </gml:boundedBy>\n"
336 " <gml:featureMember>\n"
337 " <gml:FeatureCollection>\n"
338 " <gml:featureMember>\n"
339 " <gml:RectifiedGridCoverage dimension=\"2\" gml:id=\"RGC0001\">\n"
340 " <gml:rectifiedGridDomain>\n"
341 " <gml:RectifiedGrid dimension=\"2\">\n"
342 " <gml:limits>\n"
343 " <gml:GridEnvelope>\n"
344 " <gml:low>0 0</gml:low>\n"
345 " <gml:high>%d %d</gml:high>\n"
346 " </gml:GridEnvelope>\n"
347 " </gml:limits>\n"
348 " <gml:axisName>x</gml:axisName>\n"
349 " <gml:axisName>y</gml:axisName>\n"
350 " <gml:origin>\n"
351 " <gml:Point gml:id=\"P0001\" srsName=\"%s\">\n"
352 " <gml:pos>%.15g %.15g</gml:pos>\n"
353 " </gml:Point>\n"
354 " </gml:origin>\n"
355 " <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
356 " <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
357 " </gml:RectifiedGrid>\n"
358 " </gml:rectifiedGridDomain>\n"
359 " <gml:rangeSet>\n"
360 " <gml:File>\n"
361 " <gml:fileName>urn:ogc:tc:gmljp2:codestream:0</gml:fileName>\n"
362 " <gml:fileStructure>Record Interleaved</gml:fileStructure>\n"
363 " </gml:File>\n"
364 " </gml:rangeSet>\n"
365 " </gml:RectifiedGridCoverage>\n"
366 " </gml:featureMember>\n"
367 " </gml:FeatureCollection>\n"
368 " </gml:featureMember>\n"
369 "</gml:FeatureCollection>\n",
370 sFileInfo.nSizeX-1, sFileInfo.nSizeY-1,
371 szSRSName,
372 padfGeoTransform[0] + padfGeoTransform[1] * 0.5
373 + padfGeoTransform[4] * 0.5,
374 padfGeoTransform[3] + padfGeoTransform[2] * 0.5
375 + padfGeoTransform[5] * 0.5,
376 szSRSName,
377 padfGeoTransform[1], padfGeoTransform[2],
378 szSRSName,
379 padfGeoTransform[4], padfGeoTransform[5] );
380
381 /* -------------------------------------------------------------------- */
382 /* If we need a user defined CRSDictionary entry, prepare it */
383 /* here. */
384 /* -------------------------------------------------------------------- */
385 char *pszDictBox = NULL;
386
387 if( nEPSGCode == 0 )
388 {
389 char *pszGMLDef = NULL;
390
391 if( oSRS.exportToXML( &pszGMLDef, NULL ) == OGRERR_NONE )
392 {
393 pszDictBox = (char *) CPLMalloc(strlen(pszGMLDef) + 4000);
394
395 sprintf( pszDictBox,
396 "<gml:Dictionary gml:id=\"CRSU1\" \n"
397 " xmlns:gml=\"http://www.opengis.net/gml\"\n"
398 " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
399 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
400 " <gml:dictionaryEntry>\n"
401 "%s\n"
402 " </gml:dictionaryEntry>\n"
403 "</gml:Dictionary>\n",
404 pszGMLDef );
405 }
406 CPLFree( pszGMLDef );
407 }
408
409 /* -------------------------------------------------------------------- */
410 /* Setup the various required boxes. */
411 /* -------------------------------------------------------------------- */
412 JP2UserBox *poGMLData;
413 CNCSJP2File::CNCSJPXAssocBox *poAssoc;
414 CNCSJP2File::CNCSJPXLabelBox *poLabel;
415
416 poLabel = new CNCSJP2File::CNCSJPXLabelBox();
417 poLabel->SetLabel( "gml.data" );
418 poLabel->m_bValid = true;
419 m_oGMLAssoc.m_OtherBoxes.push_back( poLabel );
420 m_oGMLAssoc.m_OwnedBoxes.push_back( poLabel );
421
422 poAssoc = new CNCSJP2File::CNCSJPXAssocBox();
423 m_oGMLAssoc.m_OtherBoxes.push_back( poAssoc );
424 m_oGMLAssoc.m_OwnedBoxes.push_back( poAssoc );
425 poAssoc->m_bValid = true;
426
427 poLabel = new CNCSJP2File::CNCSJPXLabelBox();
428 poLabel->SetLabel( "gml.root-instance" );
429 poLabel->m_bValid = true;
430 poAssoc->m_OtherBoxes.push_back( poLabel );
431 poAssoc->m_OwnedBoxes.push_back( poLabel );
432
433 poGMLData = new JP2UserBox();
434 poGMLData->m_nTBox = 'xml '; /* Is it correct on a big-endian host ? Does ECW work on big-endian hosts ;-) */
435 poGMLData->SetData( strlen( szDoc ), (unsigned char *) szDoc );
436 poAssoc->m_OtherBoxes.push_back( poGMLData );
437 poAssoc->m_OwnedBoxes.push_back( poGMLData );
438
439 if( pszDictBox != NULL )
440 {
441 poAssoc = new CNCSJP2File::CNCSJPXAssocBox();
442 m_oGMLAssoc.m_OtherBoxes.push_back( poAssoc );
443 m_oGMLAssoc.m_OwnedBoxes.push_back( poAssoc );
444 poAssoc->m_bValid = true;
445
446 poLabel = new CNCSJP2File::CNCSJPXLabelBox();
447 poLabel->SetLabel( "CRSDictionary.gml" );
448 poLabel->m_bValid = true;
449 poAssoc->m_OtherBoxes.push_back( poLabel );
450 poAssoc->m_OwnedBoxes.push_back( poLabel );
451
452 poGMLData = new JP2UserBox();
453 poGMLData->m_nTBox = 'xml '; /* Is it correct on a big-endian host ? Does ECW work on big-endian hosts ;-) */
454 poGMLData->SetData( strlen(pszDictBox),
455 (unsigned char *) pszDictBox );
456 poAssoc->m_OtherBoxes.push_back( poGMLData );
457 poAssoc->m_OwnedBoxes.push_back( poGMLData );
458
459 CPLFree( pszDictBox );
460 }
461
462 m_oGMLAssoc.m_bValid = true;
463 AddBox( &m_oGMLAssoc );
464
465 return CE_None;
466 #endif /* def ECW_FW */
467 }
468
469 /************************************************************************/
470 /* WriteJP2Box() */
471 /************************************************************************/
472
WriteJP2Box(GDALJP2Box * poBox)473 CPLErr GDALECWCompressor::WriteJP2Box( GDALJP2Box * poBox )
474
475 {
476 JP2UserBox *poECWBox;
477
478 if( poBox == NULL )
479 return CE_None;
480
481 poECWBox = new JP2UserBox();
482 memcpy( &(poECWBox->m_nTBox), poBox->GetType(), 4 );
483 CPL_MSBPTR32( &(poECWBox->m_nTBox) );
484
485 poECWBox->SetData( (int) poBox->GetDataLength(),
486 poBox->GetWritableData() );
487
488 AddBox( poECWBox );
489
490 delete poBox;
491
492 papoJP2UserBox =(JP2UserBox**) CPLRealloc(papoJP2UserBox,
493 (nJP2UserBox + 1) * sizeof(JP2UserBox*));
494 papoJP2UserBox[nJP2UserBox] = poECWBox;
495 nJP2UserBox ++;
496
497 return CE_None;
498 }
499
500 /************************************************************************/
501 /* WriteXMLBoxes() */
502 /************************************************************************/
503
WriteXMLBoxes()504 void GDALECWCompressor::WriteXMLBoxes()
505 {
506 int nBoxes = 0;
507 GDALJP2Box** papoBoxes = GDALJP2Metadata::CreateXMLBoxes(m_poSrcDS, &nBoxes);
508 for(int i=0;i<nBoxes;i++)
509 {
510 WriteJP2Box(papoBoxes[i]);
511 }
512 CPLFree(papoBoxes);
513 }
514
515 /************************************************************************/
516 /* WriteLineBIL() */
517 /************************************************************************/
518
WriteLineBIL(UINT16 nBands,void ** ppOutputLine,UINT32 * pLineSteps)519 CPLErr GDALECWCompressor::WriteLineBIL(UINT16 nBands, void **ppOutputLine, UINT32 *pLineSteps){
520
521 CNCSError oError = CNCSFile::WriteLineBIL(sFileInfo.eCellType,nBands, ppOutputLine, pLineSteps);
522
523 if( oError.GetErrorNumber() != NCS_SUCCESS )
524 {
525 ECWReportError(oError, "Scanline write write failed.\n");
526 return CE_Failure;
527 }
528 return CE_None;
529 }
530 /************************************************************************/
531 /* Initialize() */
532 /* */
533 /* Initialize compressor output. */
534 /************************************************************************/
535
Initialize(const char * pszFilename,char ** papszOptions,int nXSize,int nYSize,int nBands,const char * const * papszBandDescriptions,int bRGBColorSpace,GDALDataType eType,const char * pszWKT,double * padfGeoTransform,int nGCPCount,const GDAL_GCP * pasGCPList,int bIsJPEG2000,int bPixelIsPoint,char ** papszRPCMD,GDALDataset * poSrcDS)536 CPLErr GDALECWCompressor::Initialize(
537 const char *pszFilename, char **papszOptions,
538 int nXSize, int nYSize, int nBands, const char * const * papszBandDescriptions, int bRGBColorSpace,
539 GDALDataType eType,
540 const char *pszWKT, double *padfGeoTransform,
541 int nGCPCount, const GDAL_GCP *pasGCPList,
542 int bIsJPEG2000, int bPixelIsPoint, char** papszRPCMD,
543 GDALDataset* poSrcDS )
544
545 {
546 const char *pszOption;
547 /* -------------------------------------------------------------------- */
548 /* For 4.x and beyond you need a license key to compress data. */
549 /* Check for it as a configuration option or a creation option. */
550 /* -------------------------------------------------------------------- */
551 #if ECWSDK_VERSION >= 40
552 const char* pszECWKey = CSLFetchNameValue( papszOptions, "ECW_ENCODE_KEY");
553 if( pszECWKey == NULL )
554 pszECWKey = CPLGetConfigOption( "ECW_ENCODE_KEY", NULL );
555
556 const char* pszECWCompany =
557 CSLFetchNameValue( papszOptions, "ECW_ENCODE_COMPANY");
558 if( pszECWCompany == NULL )
559 pszECWCompany = CPLGetConfigOption( "ECW_ENCODE_COMPANY", NULL );
560
561 if( pszECWKey && pszECWCompany)
562 {
563 CPLDebug( "ECW", "SetOEMKey(%s,%s)", pszECWCompany, pszECWKey );
564 CNCSFile::SetOEMKey( (char *) pszECWCompany, (char *)pszECWKey );
565 }
566 else if( pszECWKey || pszECWCompany )
567 {
568 CPLError( CE_Failure, CPLE_AppDefined,
569 "Only one of ECW_ENCODE_KEY and ECW_ENCODE_COMPANY were provided.\nBoth are required." );
570 return CE_Failure;
571 }else{
572 CPLError( CE_Failure, CPLE_AppDefined,
573 "None of ECW_ENCODE_KEY and ECW_ENCODE_COMPANY were provided.\nBoth are required." );
574 return CE_Failure;
575 }
576
577 #endif /* ECWSDK_VERSION >= 40 */
578
579 /* -------------------------------------------------------------------- */
580 /* Do some rudimentary checking in input. */
581 /* -------------------------------------------------------------------- */
582 if( nBands == 0 )
583 {
584 CPLError( CE_Failure, CPLE_NotSupported,
585 "ECW driver requires at least one band." );
586 return CE_Failure;
587 }
588
589 /* -------------------------------------------------------------------- */
590 /* Parse out some known options. */
591 /* -------------------------------------------------------------------- */
592 float fTargetCompression;
593
594 // Default compression based on image type per request from Paul Beaty.
595 if( nBands > 1 )
596 fTargetCompression = 95.0;
597 else
598 fTargetCompression = 90.0;
599
600 if( CSLFetchNameValue(papszOptions, "TARGET") != NULL )
601 {
602 fTargetCompression = (float)
603 CPLAtof(CSLFetchNameValue(papszOptions, "TARGET"));
604
605 /* The max allowed value should be 100 - 100 / 65535 = 99.9984740978 */
606 /* so that nCompressionRate fits on a uint16 (see below) */
607 /* No need to be so pedantic, so we will limit to 99.99 % */
608 /* (compression rate = 10 000) */
609 if( fTargetCompression < 0.0 || fTargetCompression > 99.99 )
610 {
611 CPLError( CE_Failure, CPLE_NotSupported,
612 "TARGET compression of %.3f invalid, should be a\n"
613 "value between 0 and 99.99 percent.\n",
614 (double) fTargetCompression );
615 return CE_Failure;
616 }
617 }
618
619 /* -------------------------------------------------------------------- */
620 /* Create and initialize compressor. */
621 /* -------------------------------------------------------------------- */
622 NCSFileViewFileInfoEx *psClient = &(sFileInfo);
623 #if ECWSDK_VERSION >= 50
624 if( bIsJPEG2000 == FALSE )
625 {
626 bool bECWV3 = false;
627 pszOption = CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
628 if( pszOption != NULL )
629 {
630 bECWV3 = (3 == atoi(pszOption));
631 }
632 psClient->nFormatVersion = (bECWV3)?3:2;
633 }
634 else
635 {
636 psClient->nFormatVersion = 1;
637 }
638 #endif
639 psClient->nBands = (UINT16) nBands;
640 psClient->nSizeX = nXSize;
641 psClient->nSizeY = nYSize;
642 psClient->nCompressionRate = (UINT16) MAX(1,100/(100-fTargetCompression));
643 psClient->eCellSizeUnits = ECW_CELL_UNITS_METERS;
644
645 if( nBands == 1 )
646 psClient->eColorSpace = NCSCS_GREYSCALE;
647 else if( nBands == 3 && bRGBColorSpace)
648 psClient->eColorSpace = NCSCS_sRGB;
649 #if ECWSDK_VERSION >= 40
650 else if( nBands == 4 && bRGBColorSpace )
651 psClient->eColorSpace = NCSCS_sRGB;
652 #endif
653 else
654 psClient->eColorSpace = NCSCS_MULTIBAND;
655
656 /* -------------------------------------------------------------------- */
657 /* Figure out the data type. */
658 /* -------------------------------------------------------------------- */
659 int bSigned = FALSE;
660 int nBits = 8;
661 eWorkDT = eType;
662
663 switch( eWorkDT )
664 {
665 case GDT_Byte:
666 #if ECWSDK_VERSION >=50
667 psClient->nCellBitDepth = 8;
668 #endif
669 psClient->eCellType = NCSCT_UINT8;
670 nBits = 8;
671 bSigned = FALSE;
672 break;
673
674 case GDT_UInt16:
675 #if ECWSDK_VERSION >=50
676 psClient->nCellBitDepth = 16;
677 #endif
678 psClient->eCellType = NCSCT_UINT16;
679 nBits = 16;
680 bSigned = FALSE;
681 break;
682
683 case GDT_UInt32:
684 #if ECWSDK_VERSION >=50
685 psClient->nCellBitDepth = 32;
686 #endif
687 psClient->eCellType = NCSCT_UINT32;
688 nBits = 32;
689 bSigned = FALSE;
690 break;
691
692 case GDT_Int16:
693 #if ECWSDK_VERSION >=50
694 psClient->nCellBitDepth = 16;
695 #endif
696 psClient->eCellType = NCSCT_INT16;
697 nBits = 16;
698 bSigned = TRUE;
699 break;
700
701 case GDT_Int32:
702 #if ECWSDK_VERSION >=50
703 psClient->nCellBitDepth = 32;
704 #endif
705 psClient->eCellType = NCSCT_INT32;
706 nBits = 32;
707 bSigned = TRUE;
708 break;
709
710 case GDT_Float32:
711 psClient->eCellType = NCSCT_IEEE4;
712 nBits = 32;
713 bSigned = TRUE;
714 break;
715
716 case GDT_Float64:
717 psClient->eCellType = NCSCT_IEEE8;
718 nBits = 64;
719 bSigned = TRUE;
720 break;
721
722 default:
723 // We treat complex types as float.
724 psClient->eCellType = NCSCT_IEEE4;
725 nBits = 32;
726 bSigned = TRUE;
727 eWorkDT = GDT_Float32;
728 break;
729 }
730
731 /* -------------------------------------------------------------------- */
732 /* Create band information structures. */
733 /* -------------------------------------------------------------------- */
734 int iBand;
735
736 #if ECWSDK_VERSION>=50
737 psClient->pBands = (NCSFileBandInfo *)
738 NCSMalloc( sizeof(NCSFileBandInfo) * nBands, true );
739 #else
740 psClient->pBands = (NCSFileBandInfo *)
741 CPLMalloc( sizeof(NCSFileBandInfo) * nBands );
742 #endif
743 for( iBand = 0; iBand < nBands; iBand++ )
744 {
745 psClient->pBands[iBand].nBits = (UINT8) nBits;
746 psClient->pBands[iBand].bSigned = (BOOLEAN)bSigned;
747 #if ECWSDK_VERSION>=50
748 psClient->pBands[iBand].szDesc = NCSStrDup(papszBandDescriptions[iBand]);
749 #else
750 psClient->pBands[iBand].szDesc = CPLStrdup(papszBandDescriptions[iBand]);
751 #endif
752 }
753
754 /* -------------------------------------------------------------------- */
755 /* Allow CNCSFile::SetParameter() requests. */
756 /* -------------------------------------------------------------------- */
757
758 if( bIsJPEG2000 )
759 {
760 pszOption = CSLFetchNameValue(papszOptions, "PROFILE");
761 if( pszOption != NULL && EQUAL(pszOption,"BASELINE_0") )
762 SetParameter(
763 CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_0 );
764 else if( pszOption != NULL && EQUAL(pszOption,"BASELINE_1") )
765 SetParameter(
766 CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_1 );
767 else if( pszOption != NULL && EQUAL(pszOption,"BASELINE_2") )
768 SetParameter(
769 CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_2 );
770 else if( pszOption != NULL && EQUAL(pszOption,"NPJE") )
771 SetParameter(
772 CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_NPJE );
773 else if( pszOption != NULL && EQUAL(pszOption,"EPJE") )
774 SetParameter(
775 CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_EPJE );
776
777 pszOption = CSLFetchNameValue(papszOptions, "CODESTREAM_ONLY" );
778 if( pszOption != NULL )
779 SetParameter(
780 CNCSJP2FileView::JP2_COMPRESS_CODESTREAM_ONLY,
781 (bool) CSLTestBoolean( pszOption ) );
782
783 pszOption = CSLFetchNameValue(papszOptions, "LEVELS");
784 if( pszOption != NULL )
785 SetParameter( CNCSJP2FileView::JP2_COMPRESS_LEVELS,
786 (UINT32) atoi(pszOption) );
787
788 pszOption = CSLFetchNameValue(papszOptions, "LAYERS");
789 if( pszOption != NULL )
790 SetParameter( CNCSJP2FileView::JP2_COMPRESS_LAYERS,
791 (UINT32) atoi(pszOption) );
792
793 pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_WIDTH");
794 if( pszOption != NULL )
795 SetParameter( CNCSJP2FileView::JP2_COMPRESS_PRECINCT_WIDTH,
796 (UINT32) atoi(pszOption) );
797
798 pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_HEIGHT");
799 if( pszOption != NULL )
800 SetParameter(CNCSJP2FileView::JP2_COMPRESS_PRECINCT_HEIGHT,
801 (UINT32) atoi(pszOption) );
802
803 pszOption = CSLFetchNameValue(papszOptions, "TILE_WIDTH");
804 if( pszOption != NULL )
805 SetParameter( CNCSJP2FileView::JP2_COMPRESS_TILE_WIDTH,
806 (UINT32) atoi(pszOption) );
807
808 pszOption = CSLFetchNameValue(papszOptions, "TILE_HEIGHT");
809 if( pszOption != NULL )
810 SetParameter( CNCSJP2FileView::JP2_COMPRESS_TILE_HEIGHT,
811 (UINT32) atoi(pszOption) );
812
813 pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_SOP");
814 if( pszOption != NULL )
815 SetParameter( CNCSJP2FileView::JP2_COMPRESS_INCLUDE_SOP,
816 (bool) CSLTestBoolean( pszOption ) );
817
818 pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_EPH");
819 if( pszOption != NULL )
820 SetParameter( CNCSJP2FileView::JP2_COMPRESS_INCLUDE_EPH,
821 (bool) CSLTestBoolean( pszOption ) );
822
823 pszOption = CSLFetchNameValue(papszOptions, "PROGRESSION");
824 if( pszOption != NULL && EQUAL(pszOption,"LRCP") )
825 SetParameter(
826 CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_LRCP );
827
828 else if( pszOption != NULL && EQUAL(pszOption,"RLCP") )
829 SetParameter(
830 CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RLCP );
831
832 else if( pszOption != NULL && EQUAL(pszOption,"RPCL") )
833 SetParameter(
834 CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RPCL );
835
836 pszOption = CSLFetchNameValue(papszOptions, "GEODATA_USAGE");
837 if( pszOption == NULL )
838 // Default to suppressing ECW SDK geodata, just use our own stuff.
839 SetGeodataUsage( JP2_GEODATA_USE_NONE );
840 else if( EQUAL(pszOption,"NONE") )
841 SetGeodataUsage( JP2_GEODATA_USE_NONE );
842 else if( EQUAL(pszOption,"PCS_ONLY") )
843 SetGeodataUsage( JP2_GEODATA_USE_PCS_ONLY );
844 else if( EQUAL(pszOption,"GML_ONLY") )
845 SetGeodataUsage( JP2_GEODATA_USE_GML_ONLY );
846 else if( EQUAL(pszOption,"PCS_GML") )
847 SetGeodataUsage( JP2_GEODATA_USE_PCS_GML );
848 else if( EQUAL(pszOption,"GML_PCS") )
849 SetGeodataUsage( JP2_GEODATA_USE_GML_PCS );
850 else if( EQUAL(pszOption,"ALL") )
851 SetGeodataUsage( JP2_GEODATA_USE_GML_PCS_WLD );
852
853 pszOption = CSLFetchNameValue(papszOptions, "DECOMPRESS_LAYERS");
854 if( pszOption != NULL )
855 SetParameter(
856 CNCSJP2FileView::JP2_DECOMPRESS_LAYERS,
857 (UINT32) atoi(pszOption) );
858
859 pszOption = CSLFetchNameValue(papszOptions,
860 "DECOMPRESS_RECONSTRUCTION_PARAMETER");
861 if( pszOption != NULL )
862 SetParameter(
863 CNCSJP2FileView::JPC_DECOMPRESS_RECONSTRUCTION_PARAMETER,
864 (IEEE4) CPLAtof(pszOption) );
865 }
866
867 /* -------------------------------------------------------------------- */
868 /* Georeferencing. */
869 /* -------------------------------------------------------------------- */
870
871 psClient->fOriginX = 0.0;
872 psClient->fOriginY = psClient->nSizeY;
873 psClient->fCellIncrementX = 1.0;
874 psClient->fCellIncrementY = -1.0;
875 psClient->fCWRotationDegrees = 0.0;
876
877 if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 )
878 CPLError( CE_Warning, CPLE_NotSupported,
879 "Rotational coefficients ignored, georeferencing of\n"
880 "output ECW file will be incorrect.\n" );
881 else
882 {
883 psClient->fOriginX = padfGeoTransform[0];
884 psClient->fOriginY = padfGeoTransform[3];
885 psClient->fCellIncrementX = padfGeoTransform[1];
886 psClient->fCellIncrementY = padfGeoTransform[5];
887 }
888
889 /* -------------------------------------------------------------------- */
890 /* Projection. */
891 /* -------------------------------------------------------------------- */
892 char szProjection[128];
893 char szDatum[128];
894 char szUnits[128];
895
896 strcpy( szProjection, "RAW" );
897 strcpy( szDatum, "RAW" );
898
899 if( CSLFetchNameValue(papszOptions, "PROJ") != NULL )
900 {
901 strncpy( szProjection,
902 CSLFetchNameValue(papszOptions, "PROJ"), sizeof(szProjection) );
903 szProjection[sizeof(szProjection)-1] = 0;
904 }
905
906 if( CSLFetchNameValue(papszOptions, "DATUM") != NULL )
907 {
908 strncpy( szDatum, CSLFetchNameValue(papszOptions, "DATUM"), sizeof(szDatum) );
909 szDatum[sizeof(szDatum)-1] = 0;
910 if( EQUAL(szProjection,"RAW") )
911 strcpy( szProjection, "GEODETIC" );
912 }
913
914 const char* pszUnits = CSLFetchNameValue(papszOptions, "UNITS");
915 if( pszUnits != NULL )
916 {
917 psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(pszUnits);
918 }
919
920 if( EQUAL(szProjection,"RAW") && pszWKT != NULL )
921 {
922 ECWTranslateFromWKT( pszWKT, szProjection, sizeof(szProjection), szDatum, sizeof(szDatum), szUnits );
923 psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
924 }
925
926 #if ECWSDK_VERSION>=50
927 NCSFree(psClient->szDatum);
928 psClient->szDatum = NCSStrDup(szDatum);
929 NCSFree(psClient->szProjection);
930 psClient->szProjection = NCSStrDup(szProjection);
931 #else
932 psClient->szDatum = szDatum;
933 psClient->szProjection = szProjection;
934 #endif
935
936 CPLDebug( "ECW", "Writing with PROJ=%s, DATUM=%s, UNITS=%s",
937 szProjection, szDatum, ECWTranslateFromCellSizeUnits(psClient->eCellSizeUnits) );
938
939 /* -------------------------------------------------------------------- */
940 /* Setup GML and GeoTIFF information. */
941 /* -------------------------------------------------------------------- */
942 if( (pszWKT != NULL && pszWKT[0] != '\0') ||
943 !(padfGeoTransform[0] == 0.0 &&
944 padfGeoTransform[1] == 1.0 &&
945 padfGeoTransform[2] == 0.0 &&
946 padfGeoTransform[3] == 0.0 &&
947 padfGeoTransform[4] == 0.0 &&
948 padfGeoTransform[5] == 1.0) ||
949 nGCPCount > 0 || papszRPCMD != NULL )
950 {
951 GDALJP2Metadata oJP2MD;
952
953 oJP2MD.SetProjection( pszWKT );
954 oJP2MD.SetGeoTransform( padfGeoTransform );
955 oJP2MD.SetGCPs( nGCPCount, pasGCPList );
956 oJP2MD.bPixelIsPoint = bPixelIsPoint;
957 oJP2MD.SetRPCMD( papszRPCMD );
958
959 if (bIsJPEG2000) {
960 if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
961 {
962 if( !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
963 {
964 WriteXMLBoxes();
965 }
966 WriteJP2Box(GDALJP2Metadata::CreateGDALMultiDomainMetadataXMLBox(
967 m_poSrcDS, CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE)));
968 }
969 if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) )
970 {
971 const char* pszGMLJP2V2Def = CSLFetchNameValue( papszOptions, "GMLJP2V2_DEF" );
972 if( pszGMLJP2V2Def != NULL )
973 WriteJP2Box( oJP2MD.CreateGMLJP2V2(nXSize,nYSize,pszGMLJP2V2Def,poSrcDS) );
974 else
975 WriteJP2Box( oJP2MD.CreateGMLJP2(nXSize,nYSize) );
976 }
977 if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) )
978 WriteJP2Box( oJP2MD.CreateJP2GeoTIFF() );
979 if( CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) &&
980 !CSLFetchBoolean(papszOptions, "MAIN_MD_DOMAIN_ONLY", FALSE) )
981 {
982 WriteJP2Box(GDALJP2Metadata::CreateXMPBox(m_poSrcDS));
983 }
984 }
985 }
986 /* -------------------------------------------------------------------- */
987 /* We handle all jpeg2000 files via the VSIIOStream, but ECW */
988 /* files cannot be done this way for some reason. */
989 /* -------------------------------------------------------------------- */
990 VSILFILE *fpVSIL = NULL;
991
992 if( bIsJPEG2000 )
993 {
994 int bSeekable = !
995 ( strncmp(pszFilename, "/vsistdout/", strlen("/vsistdout/")) == 0 ||
996 strncmp(pszFilename, "/vsizip/", strlen("/vsizip/")) == 0 ||
997 strncmp(pszFilename, "/vsigzip/", strlen("/vsigzip/")) == 0 );
998 fpVSIL = VSIFOpenL( pszFilename, (bSeekable) ? "wb+": "wb" );
999 if( fpVSIL == NULL )
1000 {
1001 CPLError( CE_Failure, CPLE_OpenFailed,
1002 "Failed to open %s.", pszFilename );
1003 return CE_Failure;
1004 }
1005
1006 m_OStream.Access( fpVSIL, TRUE, (BOOLEAN) bSeekable, pszFilename,
1007 0, -1 );
1008 }
1009
1010 /* -------------------------------------------------------------------- */
1011 /* Check if we can enable large files. This option should only */
1012 /* be set when the application is adhering to one of the */
1013 /* ERMapper options for licensing larger than 500MB input */
1014 /* files. See Bug 767. This option no longer exists with */
1015 /* version 4+. */
1016 /* -------------------------------------------------------------------- */
1017 #if ECWSDK_VERSION < 40
1018 const char *pszLargeOK = CSLFetchNameValue(papszOptions, "LARGE_OK");
1019 if( pszLargeOK == NULL )
1020 pszLargeOK = "NO";
1021
1022 pszLargeOK = CPLGetConfigOption( "ECW_LARGE_OK", pszLargeOK );
1023
1024 if( CSLTestBoolean(pszLargeOK) )
1025 {
1026 CNCSFile::SetKeySize();
1027 CPLDebug( "ECW", "Large file generation enabled." );
1028 }
1029 #endif /* ECWSDK_VERSION < 40 */
1030 /* -------------------------------------------------------------------- */
1031 /* Infer metadata information from source dataset if possible */
1032 /* -------------------------------------------------------------------- */
1033 #if ECWSDK_VERSION>=50
1034 if (psClient->nFormatVersion>2){
1035 if (psClient->pFileMetaData == NULL){
1036 NCSEcwInitMetaData(&psClient->pFileMetaData);
1037 }
1038 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_ACQUISITION_DATE")!=NULL){
1039 psClient->pFileMetaData->sAcquisitionDate = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_ACQUISITION_DATE")).c_str());
1040 }
1041
1042 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_ACQUISITION_SENSOR_NAME")!=NULL){
1043 psClient->pFileMetaData->sAcquisitionSensorName = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_ACQUISITION_SENSOR_NAME")).c_str());
1044 }
1045 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_ADDRESS")!=NULL){
1046 psClient->pFileMetaData->sAddress = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_ADDRESS")).c_str());
1047 }
1048 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_AUTHOR")!=NULL){
1049 psClient->pFileMetaData->sAuthor = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_AUTHOR")).c_str());
1050 }
1051 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_CLASSIFICATION")!=NULL){
1052 psClient->pFileMetaData->sClassification = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_CLASSIFICATION")).c_str());
1053 }
1054 if ( pszECWCompany != NULL && CSLTestBoolean(CPLGetConfigOption("GDAL_ECW_WRITE_COMPANY", "YES")) ){
1055 psClient->pFileMetaData->sCompany = NCSStrDupT(NCS::CString(pszECWCompany).c_str());
1056 }
1057 CPLString osCompressionSoftware = GetCompressionSoftwareName();
1058 if ( osCompressionSoftware.size() > 0 ) {
1059 psClient->pFileMetaData->sCompressionSoftware = NCSStrDupT(NCS::CString(osCompressionSoftware.c_str()).c_str());
1060 }
1061 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_COPYRIGHT")!=NULL){
1062 psClient->pFileMetaData->sCopyright = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_COPYRIGHT")).c_str());
1063 }
1064 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_EMAIL")!=NULL){
1065 psClient->pFileMetaData->sEmail = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_EMAIL")).c_str());
1066 }
1067 if (m_poSrcDS && m_poSrcDS->GetMetadataItem("FILE_METADATA_TELEPHONE")!=NULL){
1068 psClient->pFileMetaData->sTelephone = NCSStrDupT(NCS::CString(m_poSrcDS->GetMetadataItem("FILE_METADATA_TELEPHONE")).c_str());
1069 }
1070 }
1071 #endif
1072 /* -------------------------------------------------------------------- */
1073 /* Set the file info. */
1074 /* -------------------------------------------------------------------- */
1075 CNCSError oError;
1076
1077 oError = SetFileInfo( sFileInfo );
1078
1079 if( oError.GetErrorNumber() == NCS_SUCCESS )
1080 {
1081 if( fpVSIL == NULL )
1082 oError = Open( (char *) pszFilename, false, true );
1083 else
1084 oError = CNCSJP2FileView::Open( &(m_OStream) );
1085 }
1086
1087 if( oError.GetErrorNumber() == NCS_SUCCESS )
1088 return CE_None;
1089 else if( oError.GetErrorNumber() == NCS_INPUT_SIZE_EXCEEDED )
1090 {
1091 CPLError( CE_Failure, CPLE_AppDefined,
1092 "ECW SDK compress limit exceeded." );
1093 return CE_Failure;
1094 }
1095 else
1096 {
1097 ECWReportError(oError);
1098
1099 return CE_Failure;
1100 }
1101 }
1102
1103 /************************************************************************/
1104 /* ECWIsInputRGBColorSpace() */
1105 /************************************************************************/
1106
ECWIsInputRGBColorSpace(GDALDataset * poSrcDS)1107 static int ECWIsInputRGBColorSpace(GDALDataset* poSrcDS)
1108 {
1109 int nBands = poSrcDS->GetRasterCount();
1110
1111 /* -------------------------------------------------------------------- */
1112 /* Is the input RGB or RGBA? */
1113 /* -------------------------------------------------------------------- */
1114 int bRGBColorSpace = FALSE;
1115 int bRGB = FALSE;
1116 if ( nBands>=3 ) {
1117 bRGB = (poSrcDS->GetRasterBand(1)->GetColorInterpretation()
1118 == GCI_RedBand);
1119 bRGB &= (poSrcDS->GetRasterBand(2)->GetColorInterpretation()
1120 == GCI_GreenBand);
1121 bRGB &= (poSrcDS->GetRasterBand(3)->GetColorInterpretation()
1122 == GCI_BlueBand);
1123 }
1124 if( nBands == 3 )
1125 {
1126 bRGBColorSpace = bRGB;
1127 }
1128 else if( nBands == 4 && bRGB )
1129 {
1130 bRGBColorSpace = (poSrcDS->GetRasterBand(4)->GetColorInterpretation()
1131 == GCI_AlphaBand);
1132 }
1133
1134 return bRGBColorSpace;
1135 }
1136
1137 /************************************************************************/
1138 /* ECWCreateCopy() */
1139 /************************************************************************/
1140
1141 static GDALDataset *
ECWCreateCopy(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData,int bIsJPEG2000)1142 ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
1143 int bStrict, char ** papszOptions,
1144 GDALProgressFunc pfnProgress, void * pProgressData,
1145 int bIsJPEG2000 )
1146
1147 {
1148 ECWInitialize();
1149
1150 /* -------------------------------------------------------------------- */
1151 /* Get various values from the source dataset. */
1152 /* -------------------------------------------------------------------- */
1153 int nBands = poSrcDS->GetRasterCount();
1154 int nXSize = poSrcDS->GetRasterXSize();
1155 int nYSize = poSrcDS->GetRasterYSize();
1156
1157 if (nBands == 0)
1158 {
1159 CPLError( CE_Failure, CPLE_NotSupported,
1160 "ECW driver does not support source dataset with zero band.\n");
1161 return NULL;
1162 }
1163
1164 GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
1165
1166 const char *pszWKT = poSrcDS->GetProjectionRef();
1167 double adfGeoTransform[6] = { 0, 1, 0, 0, 0, 1 };;
1168
1169 poSrcDS->GetGeoTransform( adfGeoTransform );
1170
1171 if( poSrcDS->GetGCPCount() > 0 )
1172 pszWKT = poSrcDS->GetGCPProjection();
1173
1174 /* -------------------------------------------------------------------- */
1175 /* For ECW, confirm the datatype is 8bit (or uint16 for ECW v3) */
1176 /* -------------------------------------------------------------------- */
1177 bool bECWV3 = false;
1178
1179 #if ECWSDK_VERSION >= 50
1180 if (bIsJPEG2000 == FALSE){
1181 const char* pszOption = CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
1182 if( pszOption != NULL )
1183 {
1184 bECWV3 = (3 == atoi(pszOption));
1185 }
1186 }
1187 #endif
1188 if( !(eType == GDT_Byte || (bECWV3 && eType == GDT_UInt16 ) || bIsJPEG2000 ) )
1189 {
1190 if( bStrict )
1191 {
1192 CPLError( CE_Failure, CPLE_AppDefined,
1193 "Attempt to create ECW file with pixel data type %s failed.\n"
1194 "Only Byte data type supported for ECW version 2 files."
1195 #if ECWSDK_VERSION >= 50
1196 " ECW version 3 files supports UInt16 as well."
1197 " Specify ECW_FORMAT_VERSION=3 creation option to write version 3 file. \n"
1198 #else
1199 ". \n"
1200 #endif
1201 , GDALGetDataTypeName( eType ) );
1202 }
1203 else
1204 {
1205 #if ECWSDK_VERSION>=50
1206 if (eType == GDT_UInt16)
1207 {
1208 CPLError( CE_Warning, CPLE_AppDefined,
1209 "ECW version 2 does not support UInt16 data type, truncating to Byte."
1210 " Consider specifying ECW_FORMAT_VERSION=3 for full UInt16 support available in ECW version 3. \n");
1211 }
1212 else
1213 #endif
1214 CPLError( CE_Warning, CPLE_AppDefined,
1215 "ECW v2 does not support data type, ignoring request for %s. \n",
1216 GDALGetDataTypeName( eType ) );
1217
1218 eType = GDT_Byte;
1219 }
1220 }
1221
1222 /* -------------------------------------------------------------------- */
1223 /* Is the input RGB or RGBA? */
1224 /* -------------------------------------------------------------------- */
1225 int bRGBColorSpace = ECWIsInputRGBColorSpace(poSrcDS);
1226
1227 /* -------------------------------------------------------------------- */
1228 /* Setup the compressor. */
1229 /* -------------------------------------------------------------------- */
1230 GDALECWCompressor oCompressor;
1231 CNCSError oErr;
1232
1233 oCompressor.pfnProgress = pfnProgress;
1234 oCompressor.pProgressData = pProgressData;
1235 oCompressor.m_poSrcDS = poSrcDS;
1236
1237 if( !pfnProgress( 0.0, NULL, pProgressData ) )
1238 return NULL;
1239
1240 char** papszBandDescriptions = (char**) CPLMalloc(nBands * sizeof(char*));
1241 int i;
1242 for (i=0;i<nBands;i++){
1243 /* Make a copy since ECWGetColorInterpretationName() can return a string generated */
1244 /* by CPLSPrintf(), which has just a few rotating entries. */
1245 papszBandDescriptions[i] = CPLStrdup(ECWGetColorInterpretationName(poSrcDS->GetRasterBand(i+1)->GetColorInterpretation(), i));
1246 }
1247
1248 const char* pszAreaOrPoint = poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT);
1249 int bPixelIsPoint = pszAreaOrPoint != NULL && EQUAL(pszAreaOrPoint, GDALMD_AOP_POINT);
1250
1251 if( oCompressor.Initialize( pszFilename, papszOptions,
1252 nXSize, nYSize, nBands, papszBandDescriptions, bRGBColorSpace,
1253 eType, pszWKT, adfGeoTransform,
1254 poSrcDS->GetGCPCount(),
1255 poSrcDS->GetGCPs(),
1256 bIsJPEG2000, bPixelIsPoint,
1257 poSrcDS->GetMetadata("RPC"),
1258 poSrcDS )
1259 != CE_None )
1260 {
1261 for (i=0;i<nBands;i++)
1262 CPLFree(papszBandDescriptions[i]);
1263 CPLFree(papszBandDescriptions);
1264 return NULL;
1265 }
1266
1267 /* -------------------------------------------------------------------- */
1268 /* Start the compression. */
1269 /* -------------------------------------------------------------------- */
1270 oErr = oCompressor.Write();
1271
1272 if( oErr.GetErrorNumber() != NCS_SUCCESS )
1273 {
1274 ECWReportError(oErr);
1275 return NULL;
1276 }
1277
1278 /* -------------------------------------------------------------------- */
1279 /* Cleanup, and return read-only handle. */
1280 /* -------------------------------------------------------------------- */
1281 oCompressor.CloseDown();
1282 for (i=0;i<nBands;i++)
1283 CPLFree(papszBandDescriptions[i]);
1284 CPLFree(papszBandDescriptions);
1285 pfnProgress( 1.001, NULL, pProgressData );
1286
1287 /* -------------------------------------------------------------------- */
1288 /* Re-open dataset, and copy any auxiliary pam information. */
1289 /* -------------------------------------------------------------------- */
1290 GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
1291 GDALPamDataset *poDS;
1292
1293 if (bIsJPEG2000)
1294 poDS = (GDALPamDataset*) ECWDatasetOpenJPEG2000(&oOpenInfo);
1295 else
1296 poDS = (GDALPamDataset*) ECWDataset::OpenECW(&oOpenInfo);
1297
1298 if( poDS )
1299 {
1300 #if ECWSDK_VERSION>=50
1301 for (int i=1;i<=poSrcDS->GetRasterCount();i++){
1302 double dMin, dMax, dMean, dStdDev;
1303 if (poSrcDS->GetRasterBand(i)->GetStatistics(FALSE, FALSE, &dMin, &dMax, &dMean, &dStdDev)==CE_None){
1304 poDS->GetRasterBand(i)->SetStatistics(dMin, dMax, dMean, dStdDev);
1305 }
1306 double dHistMin, dHistMax;
1307 int nBuckets;
1308 GUIntBig *pHistogram;
1309 if (poSrcDS->GetRasterBand(i)->GetDefaultHistogram(&dHistMin, &dHistMax,&nBuckets,&pHistogram, FALSE, NULL, NULL) == CE_None){
1310 poDS->GetRasterBand(i)->SetDefaultHistogram(dHistMin, dHistMax, nBuckets, pHistogram);
1311 VSIFree(pHistogram);
1312 }
1313 }
1314 #endif
1315
1316 ((ECWDataset *)poDS)->SetPreventCopyingSomeMetadata(TRUE);
1317 int nFlags = GCIF_PAM_DEFAULT;
1318 if( bIsJPEG2000 &&
1319 !CSLFetchBoolean(papszOptions, "WRITE_METADATA", FALSE) )
1320 nFlags &= ~GCIF_METADATA;
1321 poDS->CloneInfo( poSrcDS, nFlags );
1322 ((ECWDataset *)poDS)->SetPreventCopyingSomeMetadata(FALSE);
1323 }
1324
1325 return poDS;
1326 }
1327
1328 /************************************************************************/
1329 /* ECWCreateCopyECW() */
1330 /************************************************************************/
1331
1332 GDALDataset *
ECWCreateCopyECW(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1333 ECWCreateCopyECW( const char * pszFilename, GDALDataset *poSrcDS,
1334 int bStrict, char ** papszOptions,
1335 GDALProgressFunc pfnProgress, void * pProgressData )
1336
1337 {
1338 int nBands = poSrcDS->GetRasterCount();
1339 if (nBands == 0)
1340 {
1341 CPLError( CE_Failure, CPLE_NotSupported,
1342 "ECW driver does not support source dataset with zero band.\n");
1343 return NULL;
1344 }
1345
1346 if( !EQUAL(CPLGetExtension(pszFilename),"ecw") )
1347 {
1348 CPLError( CE_Failure, CPLE_AppDefined,
1349 "ECW driver does not support creating ECW files\n"
1350 "with an extension other than .ecw" );
1351 return NULL;
1352 }
1353 bool bECWV3 = false;
1354
1355 #if ECWSDK_VERSION >= 50
1356
1357 const char* pszOption = CSLFetchNameValue(papszOptions, "ECW_FORMAT_VERSION");
1358 if( pszOption != NULL )
1359 {
1360 bECWV3 = (3 == atoi(pszOption));
1361 }
1362
1363 #endif
1364
1365 GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
1366 if( eDataType != GDT_Byte
1367 && !(bECWV3 && (eDataType == GDT_UInt16))
1368 && bStrict )
1369 {
1370 #if ECWSDK_VERSION >= 50
1371 if (eDataType == GDT_UInt16){
1372 CPLError( CE_Failure, CPLE_NotSupported,
1373 "ECW v2 does not support UInt16 data type. Consider "
1374 " specifying ECW_FORMAT_VERSION=3 for full UInt16 support available in ECW v3. \n"
1375 );
1376 }
1377 else
1378 #endif
1379 {
1380 CPLError( CE_Failure, CPLE_NotSupported,
1381 "ECW driver doesn't support data type %s. "
1382 "Only unsigned eight "
1383 #if ECWSDK_VERSION >= 50
1384 "or sixteen "
1385 #endif
1386 "bit bands supported. \n",
1387 GDALGetDataTypeName(eDataType) );
1388 }
1389
1390 return NULL;
1391 }
1392
1393 if( poSrcDS->GetRasterXSize() < 128 || poSrcDS->GetRasterYSize() < 128 )
1394 {
1395 CPLError( CE_Failure, CPLE_NotSupported,
1396 "ECW driver requires image to be at least 128x128,\n"
1397 "the source image is %dx%d.\n",
1398 poSrcDS->GetRasterXSize(),
1399 poSrcDS->GetRasterYSize() );
1400
1401 return NULL;
1402 }
1403
1404 if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
1405 {
1406 CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
1407 "ECW driver ignores color table. "
1408 "The source raster band will be considered as grey level.\n"
1409 "Consider using color table expansion (-expand option in gdal_translate)\n");
1410 if (bStrict)
1411 return NULL;
1412 }
1413
1414 return ECWCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
1415 pfnProgress, pProgressData, FALSE );
1416 }
1417
1418 /************************************************************************/
1419 /* ECWCreateCopyJPEG2000() */
1420 /************************************************************************/
1421
1422 GDALDataset *
ECWCreateCopyJPEG2000(const char * pszFilename,GDALDataset * poSrcDS,int bStrict,char ** papszOptions,GDALProgressFunc pfnProgress,void * pProgressData)1423 ECWCreateCopyJPEG2000( const char * pszFilename, GDALDataset *poSrcDS,
1424 int bStrict, char ** papszOptions,
1425 GDALProgressFunc pfnProgress, void * pProgressData )
1426
1427 {
1428 int nBands = poSrcDS->GetRasterCount();
1429 if (nBands == 0)
1430 {
1431 CPLError( CE_Failure, CPLE_NotSupported,
1432 "JP2ECW driver does not support source dataset with zero band.\n");
1433 return NULL;
1434 }
1435
1436 if( EQUAL(CPLGetExtension(pszFilename),"ecw") )
1437 {
1438 CPLError( CE_Failure, CPLE_AppDefined,
1439 "JP2ECW driver does not support creating JPEG2000 files\n"
1440 "with a .ecw extension. Please use anything else." );
1441 return NULL;
1442 }
1443
1444 GDALDataType eDataType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
1445 if( eDataType != GDT_Byte
1446 && eDataType != GDT_Byte
1447 && eDataType != GDT_Int16
1448 && eDataType != GDT_UInt16
1449 && eDataType != GDT_Int32
1450 && eDataType != GDT_UInt32
1451 && eDataType != GDT_Float32
1452 && eDataType != GDT_Float64
1453 && bStrict )
1454 {
1455 CPLError( CE_Failure, CPLE_NotSupported,
1456 "JP2ECW driver doesn't support data type %s. ",
1457 GDALGetDataTypeName(eDataType) );
1458
1459 return NULL;
1460 }
1461
1462 if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
1463 {
1464 CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
1465 "JP2ECW driver ignores color table. "
1466 "The source raster band will be considered as grey level.\n"
1467 "Consider using color table expansion (-expand option in gdal_translate)\n");
1468 if (bStrict)
1469 return NULL;
1470 }
1471
1472 return ECWCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
1473 pfnProgress, pProgressData, TRUE );
1474 }
1475
1476 /************************************************************************/
1477 /************************************************************************
1478
1479 ECW/JPEG200 Create() Support
1480 ----------------------------
1481
1482 The remainder of the file is code to implement the Create() method.
1483 New dataset and raster band classes are defined specifically for the
1484 purpose of being write-only. In particular, you cannot read back data
1485 from these datasets, and writing must occur in a pretty specific order.
1486
1487 That is, you need to write all metadata (projection, georef, etc) first
1488 and then write the image data. All bands data for the first scanline
1489 should be written followed by all bands for the second scanline and so on.
1490
1491 Creation supports the same virtual subfile names as CreateCopy() supports.
1492
1493 ************************************************************************/
1494 /************************************************************************/
1495
1496 /************************************************************************/
1497 /* ==================================================================== */
1498 /* ECWWriteDataset */
1499 /* ==================================================================== */
1500 /************************************************************************/
1501
1502 class ECWWriteRasterBand;
1503
1504 #ifdef OPTIMIZED_FOR_GDALWARP
1505 class IRasterIORequest
1506 {
1507 public:
1508 GDALRasterBand* poBand;
1509 int nXOff;
1510 int nYOff;
1511 int nXSize;
1512 int nYSize;
1513 GByte* pabyData;
1514 int nBufXSize;
1515 int nBufYSize;
1516
IRasterIORequest(GDALRasterBand * poBand,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace)1517 IRasterIORequest( GDALRasterBand* poBand,
1518 int nXOff, int nYOff, int nXSize, int nYSize,
1519 void * pData, int nBufXSize, int nBufYSize,
1520 GDALDataType eBufType,
1521 GSpacing nPixelSpace, GSpacing nLineSpace ) :
1522 poBand(poBand),
1523 nXOff(nXOff),
1524 nYOff(nYOff),
1525 nXSize(nXSize),
1526 nYSize(nYSize),
1527 pabyData(NULL),
1528 nBufXSize(nBufXSize),
1529 nBufYSize(nBufYSize)
1530 {
1531 GDALDataType eDataType = poBand->GetRasterDataType();
1532 int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8;
1533 pabyData = (GByte*)CPLMalloc(nBufXSize * nBufYSize * nDataTypeSize);
1534 for(int iY = 0; iY < nBufYSize; iY ++)
1535 {
1536 GDALCopyWords((GByte*)pData + iY * nLineSpace,
1537 eBufType, nPixelSpace,
1538 pabyData + iY * nBufXSize * nDataTypeSize,
1539 eDataType, nDataTypeSize,
1540 nBufXSize);
1541 }
1542 }
~IRasterIORequest()1543 ~IRasterIORequest() { CPLFree(pabyData); }
1544 };
1545 #endif
1546
1547 class CPL_DLL ECWWriteDataset : public GDALDataset
1548 {
1549 friend class ECWWriteRasterBand;
1550
1551 char *pszFilename;
1552
1553 int bIsJPEG2000;
1554 GDALDataType eDataType;
1555 char **papszOptions;
1556
1557 char *pszProjection;
1558 double adfGeoTransform[6];
1559
1560 GDALECWCompressor oCompressor;
1561 int bCrystalized;
1562
1563 int nLoadedLine;
1564 GByte *pabyBILBuffer;
1565
1566 int bOutOfOrderWriteOccured;
1567 #ifdef OPTIMIZED_FOR_GDALWARP
1568 int nPrevIRasterIOBand;
1569 #endif
1570
1571 CPLErr Crystalize();
1572 CPLErr FlushLine();
1573
1574 public:
1575 ECWWriteDataset( const char *, int, int, int,
1576 GDALDataType, char **papszOptions,
1577 int );
1578 ~ECWWriteDataset();
1579
1580 virtual void FlushCache( void );
1581
1582 virtual CPLErr GetGeoTransform( double * );
1583 virtual const char* GetProjectionRef();
1584 virtual CPLErr SetGeoTransform( double * );
1585 virtual CPLErr SetProjection( const char *pszWKT );
1586
1587 #ifdef OPTIMIZED_FOR_GDALWARP
1588 virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
1589 int nXOff, int nYOff, int nXSize, int nYSize,
1590 void * pData, int nBufXSize, int nBufYSize,
1591 GDALDataType eBufType,
1592 int nBandCount, int *panBandMap,
1593 GSpacing nPixelSpace, GSpacing nLineSpace,
1594 GSpacing nBandSpace,
1595 GDALRasterIOExtraArg* psExtraArg);
1596 #endif
1597 };
1598
1599 /************************************************************************/
1600 /* ==================================================================== */
1601 /* ECWWriteRasterBand */
1602 /* ==================================================================== */
1603 /************************************************************************/
1604
1605 class ECWWriteRasterBand : public GDALRasterBand
1606 {
1607 friend class ECWWriteDataset;
1608
1609 // NOTE: poDS may be altered for NITF/JPEG2000 files!
1610 ECWWriteDataset *poGDS;
1611
1612 GDALColorInterp eInterp;
1613
1614 #ifdef OPTIMIZED_FOR_GDALWARP
1615 IRasterIORequest *poIORequest;
1616 #endif
1617
1618 public:
1619
1620 ECWWriteRasterBand( ECWWriteDataset *, int );
1621 ~ECWWriteRasterBand();
1622
SetColorInterpretation(GDALColorInterp eInterpIn)1623 virtual CPLErr SetColorInterpretation( GDALColorInterp eInterpIn )
1624 { eInterp = eInterpIn;
1625 if( strlen(GetDescription()) == 0 )
1626 SetDescription(ECWGetColorInterpretationName(eInterp, nBand-1));
1627 return CE_None;
1628 }
GetColorInterpretation()1629 virtual GDALColorInterp GetColorInterpretation()
1630 { return eInterp; }
1631
1632 virtual CPLErr IReadBlock( int, int, void * );
1633 virtual CPLErr IWriteBlock( int, int, void * );
1634
1635 #ifdef OPTIMIZED_FOR_GDALWARP
1636 virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
1637 int nXOff, int nYOff, int nXSize, int nYSize,
1638 void * pData, int nBufXSize, int nBufYSize,
1639 GDALDataType eBufType,
1640 GSpacing nPixelSpace, GSpacing nLineSpace,
1641 GDALRasterIOExtraArg* psExtraArg);
1642 #endif
1643 };
1644
1645 /************************************************************************/
1646 /* ECWWriteDataset() */
1647 /************************************************************************/
1648
ECWWriteDataset(const char * pszFilename,int nXSize,int nYSize,int nBandCount,GDALDataType eType,char ** papszOptions,int bIsJPEG2000)1649 ECWWriteDataset::ECWWriteDataset( const char *pszFilename,
1650 int nXSize, int nYSize, int nBandCount,
1651 GDALDataType eType,
1652 char **papszOptions, int bIsJPEG2000 )
1653
1654 {
1655 bCrystalized = FALSE;
1656 pabyBILBuffer = NULL;
1657 nLoadedLine = -1;
1658
1659 eAccess = GA_Update;
1660
1661 this->bIsJPEG2000 = bIsJPEG2000;
1662 this->eDataType = eType;
1663 this->papszOptions = CSLDuplicate( papszOptions );
1664 this->pszFilename = CPLStrdup( pszFilename );
1665
1666 nRasterXSize = nXSize;
1667 nRasterYSize = nYSize;
1668 pszProjection = NULL;
1669
1670 adfGeoTransform[0] = 0.0;
1671 adfGeoTransform[1] = 1.0;
1672 adfGeoTransform[2] = 0.0;
1673 adfGeoTransform[3] = 0.0;
1674 adfGeoTransform[4] = 0.0;
1675 adfGeoTransform[5] = 1.0;
1676
1677 // create band objects.
1678 for( int iBand = 1; iBand <= nBandCount; iBand++ )
1679 {
1680 SetBand( iBand, new ECWWriteRasterBand( this, iBand ) );
1681 }
1682
1683 bOutOfOrderWriteOccured = FALSE;
1684 #ifdef OPTIMIZED_FOR_GDALWARP
1685 nPrevIRasterIOBand = -1;
1686 #endif
1687 }
1688
1689 /************************************************************************/
1690 /* ~ECWWriteDataset() */
1691 /************************************************************************/
1692
~ECWWriteDataset()1693 ECWWriteDataset::~ECWWriteDataset()
1694
1695 {
1696 FlushCache();
1697
1698 if( bCrystalized )
1699 {
1700 if( bOutOfOrderWriteOccured )
1701 {
1702 /* Otherwise there's a hang-up in the destruction of the oCompressor object */
1703 while( nLoadedLine < nRasterYSize - 1 )
1704 FlushLine();
1705 }
1706 if( nLoadedLine == nRasterYSize - 1 )
1707 FlushLine();
1708 oCompressor.CloseDown();
1709 }
1710
1711 CPLFree( pabyBILBuffer );
1712 CPLFree( pszProjection );
1713 CSLDestroy( papszOptions );
1714 CPLFree( pszFilename );
1715 }
1716
1717 /************************************************************************/
1718 /* FlushCache() */
1719 /************************************************************************/
1720
FlushCache()1721 void ECWWriteDataset::FlushCache()
1722
1723 {
1724 BlockBasedFlushCache();
1725 }
1726
1727 /************************************************************************/
1728 /* GetProjectionRef() */
1729 /************************************************************************/
1730
GetProjectionRef()1731 const char* ECWWriteDataset::GetProjectionRef()
1732 {
1733 return pszProjection;
1734 }
1735
1736 /************************************************************************/
1737 /* GetGeoTransform() */
1738 /************************************************************************/
1739
GetGeoTransform(double * padfGeoTransform)1740 CPLErr ECWWriteDataset::GetGeoTransform( double *padfGeoTransform )
1741
1742 {
1743 memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
1744 return CE_None;
1745 }
1746
1747 /************************************************************************/
1748 /* SetGeoTransform() */
1749 /************************************************************************/
1750
SetGeoTransform(double * padfGeoTransform)1751 CPLErr ECWWriteDataset::SetGeoTransform( double *padfGeoTransform )
1752
1753 {
1754 memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
1755 return CE_None;
1756 }
1757
1758 /************************************************************************/
1759 /* SetProjection() */
1760 /************************************************************************/
1761
SetProjection(const char * pszWKT)1762 CPLErr ECWWriteDataset::SetProjection( const char *pszWKT )
1763
1764 {
1765 CPLFree( pszProjection );
1766 pszProjection = CPLStrdup( pszWKT );
1767
1768 return CE_None;
1769 }
1770
1771
1772 /************************************************************************/
1773 /* Crystalize() */
1774 /************************************************************************/
1775
Crystalize()1776 CPLErr ECWWriteDataset::Crystalize()
1777
1778 {
1779 int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1780
1781 CPLErr eErr;
1782 CNCSError oError;
1783
1784 if( bCrystalized )
1785 return CE_None;
1786
1787 const char **paszBandDescriptions = (const char **) CPLMalloc(nBands * sizeof(char *));
1788 for (int i = 0; i < nBands; i++ ){
1789 paszBandDescriptions[i] = GetRasterBand(i+1)->GetDescription();
1790 }
1791
1792 int bRGBColorSpace = ECWIsInputRGBColorSpace(this);
1793
1794 eErr = oCompressor.Initialize( pszFilename, papszOptions,
1795 nRasterXSize, nRasterYSize, nBands,paszBandDescriptions, bRGBColorSpace,
1796 eDataType,
1797 pszProjection, adfGeoTransform,
1798 0, NULL,
1799 bIsJPEG2000, FALSE, NULL );
1800
1801 if( eErr == CE_None )
1802 bCrystalized = TRUE;
1803
1804 nLoadedLine = -1;
1805 pabyBILBuffer = (GByte *) CPLMalloc( nWordSize * nBands * nRasterXSize );
1806
1807 CPLFree(paszBandDescriptions);
1808
1809 return eErr;
1810 }
1811
1812 /************************************************************************/
1813 /* FlushLine() */
1814 /************************************************************************/
1815
FlushLine()1816 CPLErr ECWWriteDataset::FlushLine()
1817
1818 {
1819 int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1820 CPLErr eErr;
1821
1822 /* -------------------------------------------------------------------- */
1823 /* Crystalize if not already done. */
1824 /* -------------------------------------------------------------------- */
1825 if( !bCrystalized )
1826 {
1827 eErr = Crystalize();
1828
1829 if( eErr != CE_None )
1830 return eErr;
1831 }
1832
1833 /* -------------------------------------------------------------------- */
1834 /* Write out the currently loaded line. */
1835 /* -------------------------------------------------------------------- */
1836 if( nLoadedLine != -1 )
1837 {
1838
1839 void **papOutputLine;
1840
1841 papOutputLine = (void **) CPLMalloc(sizeof(void*) * nBands);
1842 for( int i = 0; i < nBands; i++ )
1843 papOutputLine[i] =
1844 (void *) (pabyBILBuffer + i * nWordSize * nRasterXSize);
1845
1846
1847 eErr = oCompressor.WriteLineBIL( (UINT16) nBands, papOutputLine );
1848 CPLFree( papOutputLine );
1849 if (eErr!=CE_None){
1850 return eErr;
1851 }
1852 }
1853
1854 /* -------------------------------------------------------------------- */
1855 /* Clear the buffer and increment the "current line" indicator. */
1856 /* -------------------------------------------------------------------- */
1857 memset( pabyBILBuffer, 0, nWordSize * nRasterXSize * nBands );
1858 nLoadedLine++;
1859
1860 return CE_None;
1861 }
1862
1863 #ifdef OPTIMIZED_FOR_GDALWARP
1864 /************************************************************************/
1865 /* IRasterIO() */
1866 /************************************************************************/
1867
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)1868 CPLErr ECWWriteDataset::IRasterIO( GDALRWFlag eRWFlag,
1869 int nXOff, int nYOff, int nXSize, int nYSize,
1870 void * pData, int nBufXSize, int nBufYSize,
1871 GDALDataType eBufType,
1872 int nBandCount, int *panBandMap,
1873 GSpacing nPixelSpace, GSpacing nLineSpace,
1874 GSpacing nBandSpace,
1875 GDALRasterIOExtraArg* psExtraArg)
1876 {
1877 ECWWriteRasterBand* po4thBand = NULL;
1878 IRasterIORequest* poIORequest = NULL;
1879
1880 if( bOutOfOrderWriteOccured )
1881 return CE_Failure;
1882
1883 if( eRWFlag == GF_Write && nBandCount == 3 && nBands == 4 )
1884 {
1885 po4thBand = (ECWWriteRasterBand*)GetRasterBand(4);
1886 poIORequest = po4thBand->poIORequest;
1887 if( poIORequest != NULL )
1888 {
1889 if( nXOff != poIORequest->nXOff ||
1890 nYOff != poIORequest->nYOff ||
1891 nXSize != poIORequest->nXSize ||
1892 nYSize != poIORequest->nYSize ||
1893 nBufXSize != poIORequest->nBufXSize ||
1894 nBufYSize != poIORequest->nBufYSize )
1895 {
1896 CPLError(CE_Failure, CPLE_AppDefined, "Out of order write");
1897 bOutOfOrderWriteOccured = TRUE;
1898 return CE_Failure;
1899 }
1900 }
1901 }
1902
1903 int nDataTypeSize = GDALGetDataTypeSize(eDataType) / 8;
1904 if( eRWFlag == GF_Write && nXOff == 0 && nXSize == nRasterXSize &&
1905 nBufXSize == nXSize && nBufYSize == nYSize && eBufType == eDataType &&
1906 (nBandCount == nBands || ( nBandCount == 3 && poIORequest != NULL && nBands == 4) ) &&
1907 nPixelSpace == nDataTypeSize && nLineSpace == nPixelSpace * nRasterXSize )
1908 {
1909 GByte* pabyData = (GByte*)pData;
1910 for(int iY = 0; iY < nYSize; iY ++)
1911 {
1912 for(int iBand = 0; iBand < nBandCount; iBand ++)
1913 {
1914 GetRasterBand(panBandMap[iBand])->WriteBlock(0, iY + nYOff,
1915 pabyData + iY * nLineSpace + iBand * nBandSpace);
1916 }
1917
1918 if( poIORequest != NULL )
1919 {
1920 po4thBand->WriteBlock(0, iY + nYOff,
1921 poIORequest->pabyData + iY * nDataTypeSize * nXSize);
1922 }
1923 }
1924
1925 if( poIORequest != NULL )
1926 {
1927 delete poIORequest;
1928 po4thBand->poIORequest = NULL;
1929 }
1930
1931 return CE_None;
1932 }
1933 else
1934 return GDALDataset::IRasterIO(eRWFlag,
1935 nXOff, nYOff, nXSize, nYSize,
1936 pData, nBufXSize, nBufYSize,
1937 eBufType,
1938 nBandCount, panBandMap,
1939 nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
1940 }
1941 #endif
1942
1943 /************************************************************************/
1944 /* ==================================================================== */
1945 /* ECWWriteRasterBand */
1946 /* ==================================================================== */
1947 /************************************************************************/
1948
1949 /************************************************************************/
1950 /* ECWWriteRasterBand() */
1951 /************************************************************************/
1952
ECWWriteRasterBand(ECWWriteDataset * poDSIn,int nBandIn)1953 ECWWriteRasterBand::ECWWriteRasterBand( ECWWriteDataset *poDSIn,
1954 int nBandIn )
1955
1956 {
1957 nBand = nBandIn;
1958 poDS = poDSIn;
1959 poGDS = poDSIn;
1960 nBlockXSize = poDSIn->GetRasterXSize();
1961 nBlockYSize = 1;
1962 eDataType = poDSIn->eDataType;
1963 eInterp = GCI_Undefined;
1964 #ifdef OPTIMIZED_FOR_GDALWARP
1965 poIORequest = NULL;
1966 #endif
1967 }
1968
1969 /************************************************************************/
1970 /* ~ECWWriteRasterBand() */
1971 /************************************************************************/
1972
~ECWWriteRasterBand()1973 ECWWriteRasterBand::~ECWWriteRasterBand()
1974
1975 {
1976 #ifdef OPTIMIZED_FOR_GDALWARP
1977 delete poIORequest;
1978 #endif
1979 }
1980
1981 /************************************************************************/
1982 /* IReadBlock() */
1983 /************************************************************************/
1984
IReadBlock(CPL_UNUSED int nBlockX,CPL_UNUSED int nBlockY,void * pBuffer)1985 CPLErr ECWWriteRasterBand::IReadBlock( CPL_UNUSED int nBlockX,
1986 CPL_UNUSED int nBlockY,
1987 void *pBuffer )
1988 {
1989 int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1990
1991 // We zero stuff out here, but we can't really read stuff from
1992 // a write only stream.
1993
1994 memset( pBuffer, 0, nBlockXSize * nWordSize );
1995
1996 return CE_None;
1997 }
1998
1999 #ifdef OPTIMIZED_FOR_GDALWARP
2000 /************************************************************************/
2001 /* IRasterIO() */
2002 /************************************************************************/
2003
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,GSpacing nPixelSpace,GSpacing nLineSpace,GDALRasterIOExtraArg * psExtraArg)2004 CPLErr ECWWriteRasterBand::IRasterIO( GDALRWFlag eRWFlag,
2005 int nXOff, int nYOff, int nXSize, int nYSize,
2006 void * pData, int nBufXSize, int nBufYSize,
2007 GDALDataType eBufType,
2008 GSpacing nPixelSpace, GSpacing nLineSpace,
2009 GDALRasterIOExtraArg* psExtraArg)
2010 {
2011 if( eRWFlag == GF_Write && nBand == 4 && poGDS->nBands == 4 &&
2012 poGDS->nPrevIRasterIOBand < 0 )
2013 {
2014 /* Triggered when gdalwarp outputs an alpha band */
2015 /* It is called before GDALDatasetRasterIO() on the 3 first bands */
2016 if( poIORequest != NULL )
2017 return CE_Failure;
2018 poIORequest = new IRasterIORequest( this,
2019 nXOff, nYOff, nXSize, nYSize,
2020 pData, nBufXSize, nBufYSize,
2021 eBufType,
2022 nPixelSpace, nLineSpace );
2023 return CE_None;
2024 }
2025
2026 poGDS->nPrevIRasterIOBand = nBand;
2027 return GDALRasterBand::IRasterIO( eRWFlag,
2028 nXOff, nYOff, nXSize, nYSize,
2029 pData, nBufXSize, nBufYSize,
2030 eBufType,
2031 nPixelSpace, nLineSpace, psExtraArg );
2032 }
2033 #endif
2034
2035 /************************************************************************/
2036 /* IWriteBlock() */
2037 /************************************************************************/
2038
IWriteBlock(CPL_UNUSED int nBlockX,int nBlockY,void * pBuffer)2039 CPLErr ECWWriteRasterBand::IWriteBlock( CPL_UNUSED int nBlockX,
2040 int nBlockY,
2041 void *pBuffer )
2042 {
2043 int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
2044 CPLErr eErr;
2045
2046 if( poGDS->bOutOfOrderWriteOccured )
2047 return CE_Failure;
2048
2049 /* -------------------------------------------------------------------- */
2050 /* Flush previous line if needed. */
2051 /* -------------------------------------------------------------------- */
2052 if( nBlockY == poGDS->nLoadedLine + 1 )
2053 {
2054 eErr = poGDS->FlushLine();
2055 if( eErr != CE_None )
2056 return eErr;
2057 }
2058
2059 /* -------------------------------------------------------------------- */
2060 /* Blow a gasket if we have been asked to write something out */
2061 /* of order. */
2062 /* -------------------------------------------------------------------- */
2063 if( nBlockY != poGDS->nLoadedLine )
2064 {
2065 CPLError( CE_Failure, CPLE_AppDefined,
2066 "Apparent attempt to write to ECW non-sequentially.\n"
2067 "Loaded line is %d, but %d of band %d was written to.",
2068 poGDS->nLoadedLine, nBlockY, nBand );
2069 poGDS->bOutOfOrderWriteOccured = TRUE;
2070 return CE_Failure;
2071 }
2072
2073 /* -------------------------------------------------------------------- */
2074 /* Copy passed data into current line buffer. */
2075 /* -------------------------------------------------------------------- */
2076 memcpy( poGDS->pabyBILBuffer + (nBand-1) * nWordSize * nRasterXSize,
2077 pBuffer,
2078 nWordSize * nRasterXSize );
2079
2080 return CE_None;
2081 }
2082
2083 /************************************************************************/
2084 /* ECWCreateJPEG2000() */
2085 /************************************************************************/
2086
2087 GDALDataset *
ECWCreateJPEG2000(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)2088 ECWCreateJPEG2000(const char *pszFilename, int nXSize, int nYSize, int nBands,
2089 GDALDataType eType, char **papszOptions )
2090
2091 {
2092 ECWInitialize();
2093
2094 return new ECWWriteDataset( pszFilename, nXSize, nYSize, nBands,
2095 eType, papszOptions, TRUE );
2096 }
2097
2098 /************************************************************************/
2099 /* ECWCreateECW() */
2100 /************************************************************************/
2101
2102 GDALDataset *
ECWCreateECW(const char * pszFilename,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)2103 ECWCreateECW( const char *pszFilename, int nXSize, int nYSize, int nBands,
2104 GDALDataType eType, char **papszOptions )
2105
2106 {
2107 ECWInitialize();
2108
2109 return new ECWWriteDataset( pszFilename, nXSize, nYSize, nBands,
2110 eType, papszOptions, FALSE );
2111 }
2112
2113 #endif /* def FRMT_ecw && def HAVE_COMPRESS */
2114