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