1 : /******************************************************************************
2 : * $Id: ecwcreatecopy.cpp 23076 2011-09-07 18:28:51Z 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 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "gdal_ecw.h"
31 : #include "ogr_spatialref.h"
32 :
33 : CPL_CVSID("$Id: ecwcreatecopy.cpp 23076 2011-09-07 18:28:51Z rouault $");
34 :
35 : #if defined(FRMT_ecw) && defined(HAVE_COMPRESS)
36 :
37 : class GDALECWCompressor : public CNCSFile {
38 :
39 : public:
40 : GDALECWCompressor();
41 : virtual ~GDALECWCompressor();
42 :
43 : virtual CNCSError WriteReadLine(UINT32 nNextLine, void **ppInputArray);
44 : virtual void WriteStatus(UINT32 nCurrentLine);
45 : virtual bool WriteCancel();
46 :
47 : CPLErr Initialize( const char *pszFilename, char **papszOptions,
48 : int nXSize, int nYSize, int nBands, int bRGBA,
49 : GDALDataType eType,
50 : const char *pszWKT, double *padfGeoTransform,
51 : int nGCPCount, const GDAL_GCP *pasGCPList,
52 : int bIsJPEG2000 );
53 : CPLErr CloseDown();
54 :
55 : CPLErr PrepareCoverageBox( const char *pszWKT, double *padfGeoTransform );
56 : CPLErr WriteJP2Box( GDALJP2Box * );
57 :
58 : #ifdef ECW_FW
59 : CNCSJP2File::CNCSJPXAssocBox m_oGMLAssoc;
60 : #endif
61 :
62 : // Data
63 :
64 : GDALDataset *m_poSrcDS;
65 :
66 : VSIIOStream m_OStream;
67 : int m_nPercentComplete;
68 :
69 : int m_bCancelled;
70 :
71 : GDALProgressFunc pfnProgress;
72 : void *pProgressData;
73 :
74 : NCSFileViewFileInfoEx sFileInfo;
75 : GDALDataType eWorkDT;
76 :
77 : JP2UserBox** papoJP2UserBox;
78 : int nJP2UserBox;
79 : };
80 :
81 : /************************************************************************/
82 : /* GDALECWCompressor() */
83 : /************************************************************************/
84 :
85 47 : GDALECWCompressor::GDALECWCompressor()
86 :
87 : {
88 47 : m_poSrcDS = NULL;
89 47 : m_nPercentComplete = -1;
90 47 : m_bCancelled = FALSE;
91 47 : pfnProgress = GDALDummyProgress;
92 47 : pProgressData = NULL;
93 47 : papoJP2UserBox = NULL;
94 47 : nJP2UserBox = 0;
95 47 : }
96 :
97 : /************************************************************************/
98 : /* ~GDALECWCompressor() */
99 : /************************************************************************/
100 :
101 47 : GDALECWCompressor::~GDALECWCompressor()
102 :
103 : {
104 : int i;
105 87 : for(i=0;i<nJP2UserBox;i++)
106 40 : delete papoJP2UserBox[i];
107 47 : CPLFree(papoJP2UserBox);
108 47 : }
109 :
110 : /************************************************************************/
111 : /* CloseDown() */
112 : /************************************************************************/
113 :
114 17 : CPLErr GDALECWCompressor::CloseDown()
115 :
116 : {
117 52 : for( int i = 0; i < sFileInfo.nBands; i++ )
118 : {
119 35 : CPLFree( sFileInfo.pBands[i].szDesc );
120 : }
121 17 : CPLFree( sFileInfo.pBands );
122 :
123 17 : Close( true );
124 17 : m_OStream.Close();
125 :
126 17 : return CE_None;
127 : }
128 :
129 : /************************************************************************/
130 : /* WriteReadLine() */
131 : /************************************************************************/
132 :
133 640 : CNCSError GDALECWCompressor::WriteReadLine( UINT32 nNextLine,
134 : void **ppInputArray )
135 :
136 : {
137 : int iBand, *panBandMap;
138 : CPLErr eErr;
139 : GByte *pabyLineBuf;
140 640 : int nWordSize = GDALGetDataTypeSize( eWorkDT ) / 8;
141 :
142 640 : panBandMap = (int *) CPLMalloc(sizeof(int) * sFileInfo.nBands);
143 2350 : for( iBand = 0; iBand < sFileInfo.nBands; iBand++ )
144 1710 : panBandMap[iBand] = iBand+1;
145 :
146 : pabyLineBuf = (GByte *) CPLMalloc( sFileInfo.nSizeX * sFileInfo.nBands
147 640 : * nWordSize );
148 :
149 : eErr = m_poSrcDS->RasterIO( GF_Read, 0, nNextLine, sFileInfo.nSizeX, 1,
150 : pabyLineBuf, sFileInfo.nSizeX, 1,
151 : eWorkDT,
152 : sFileInfo.nBands, panBandMap,
153 640 : nWordSize, 0, nWordSize * sFileInfo.nSizeX );
154 :
155 2350 : for( iBand = 0; iBand < (int) sFileInfo.nBands; iBand++ )
156 : {
157 : memcpy( ppInputArray[iBand],
158 : pabyLineBuf + nWordSize * sFileInfo.nSizeX * iBand,
159 1710 : nWordSize * sFileInfo.nSizeX );
160 : }
161 :
162 640 : CPLFree( pabyLineBuf );
163 640 : CPLFree( panBandMap );
164 :
165 640 : if( eErr == CE_None )
166 640 : return NCS_SUCCESS;
167 : else
168 0 : return NCS_FILEIO_ERROR;
169 : }
170 :
171 : /************************************************************************/
172 : /* WriteStatus() */
173 : /************************************************************************/
174 :
175 640 : void GDALECWCompressor::WriteStatus( UINT32 nCurrentLine )
176 :
177 : {
178 : m_bCancelled =
179 : !pfnProgress( nCurrentLine / (float) sFileInfo.nSizeY,
180 640 : NULL, pProgressData );
181 640 : }
182 :
183 : /************************************************************************/
184 : /* WriteCancel() */
185 : /************************************************************************/
186 :
187 640 : bool GDALECWCompressor::WriteCancel()
188 :
189 : {
190 640 : return (bool) m_bCancelled;
191 : }
192 :
193 : /************************************************************************/
194 : /* PrepareCoverageBox() */
195 : /************************************************************************/
196 :
197 0 : CPLErr GDALECWCompressor::PrepareCoverageBox( const char *pszWKT,
198 : double *padfGeoTransform )
199 :
200 : {
201 : #ifndef ECW_FW
202 0 : return CE_Failure;
203 : #else
204 : /* -------------------------------------------------------------------- */
205 : /* Try do determine a PCS or GCS code we can use. */
206 : /* -------------------------------------------------------------------- */
207 : OGRSpatialReference oSRS;
208 : char *pszWKTCopy = (char *) pszWKT;
209 : int nEPSGCode = 0;
210 : char szSRSName[100];
211 :
212 : if( oSRS.importFromWkt( &pszWKTCopy ) != OGRERR_NONE )
213 : return CE_Failure;
214 :
215 : if( oSRS.IsProjected() )
216 : {
217 : const char *pszAuthName = oSRS.GetAuthorityName( "PROJCS" );
218 :
219 : if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
220 : {
221 : nEPSGCode = atoi(oSRS.GetAuthorityCode( "PROJCS" ));
222 : }
223 : }
224 : else if( oSRS.IsGeographic() )
225 : {
226 : const char *pszAuthName = oSRS.GetAuthorityName( "GEOGCS" );
227 :
228 : if( pszAuthName != NULL && EQUAL(pszAuthName,"epsg") )
229 : {
230 : nEPSGCode = atoi(oSRS.GetAuthorityCode( "GEOGCS" ));
231 : }
232 : }
233 :
234 : if( nEPSGCode != 0 )
235 : sprintf( szSRSName, "urn:ogc:def:crs:EPSG::%d", nEPSGCode );
236 : else
237 : strcpy( szSRSName,
238 : "gmljp2://xml/CRSDictionary.gml#ogrcrs1" );
239 :
240 : /* -------------------------------------------------------------------- */
241 : /* For now we hardcode for a minimal instance format. */
242 : /* -------------------------------------------------------------------- */
243 : char szDoc[4000];
244 :
245 : sprintf( szDoc,
246 : "<gml:FeatureCollection\n"
247 : " xmlns:gml=\"http://www.opengis.net/gml\"\n"
248 : " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
249 : " xsi:schemaLocation=\"http://www.opengis.net/gml http://www.math.ubc.ca/~burggraf/gml/gml4jp2.xsd\">\n"
250 : " <gml:boundedBy>\n"
251 : " <gml:Null>withheld</gml:Null>\n"
252 : " </gml:boundedBy>\n"
253 : " <gml:featureMember>\n"
254 : " <gml:FeatureCollection>\n"
255 : " <gml:featureMember>\n"
256 : " <gml:RectifiedGridCoverage dimension=\"2\" gml:id=\"RGC0001\">\n"
257 : " <gml:rectifiedGridDomain>\n"
258 : " <gml:RectifiedGrid dimension=\"2\">\n"
259 : " <gml:limits>\n"
260 : " <gml:GridEnvelope>\n"
261 : " <gml:low>0 0</gml:low>\n"
262 : " <gml:high>%d %d</gml:high>\n"
263 : " </gml:GridEnvelope>\n"
264 : " </gml:limits>\n"
265 : " <gml:axisName>x</gml:axisName>\n"
266 : " <gml:axisName>y</gml:axisName>\n"
267 : " <gml:origin>\n"
268 : " <gml:Point gml:id=\"P0001\" srsName=\"%s\">\n"
269 : " <gml:pos>%.15g %.15g</gml:pos>\n"
270 : " </gml:Point>\n"
271 : " </gml:origin>\n"
272 : " <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
273 : " <gml:offsetVector srsName=\"%s\">%.15g %.15g</gml:offsetVector>\n"
274 : " </gml:RectifiedGrid>\n"
275 : " </gml:rectifiedGridDomain>\n"
276 : " <gml:rangeSet>\n"
277 : " <gml:File>\n"
278 : " <gml:fileName>urn:ogc:tc:gmljp2:codestream:0</gml:fileName>\n"
279 : " <gml:fileStructure>Record Interleaved</gml:fileStructure>\n"
280 : " </gml:File>\n"
281 : " </gml:rangeSet>\n"
282 : " </gml:RectifiedGridCoverage>\n"
283 : " </gml:featureMember>\n"
284 : " </gml:FeatureCollection>\n"
285 : " </gml:featureMember>\n"
286 : "</gml:FeatureCollection>\n",
287 : sFileInfo.nSizeX-1, sFileInfo.nSizeY-1,
288 : szSRSName,
289 : padfGeoTransform[0] + padfGeoTransform[1] * 0.5
290 : + padfGeoTransform[4] * 0.5,
291 : padfGeoTransform[3] + padfGeoTransform[2] * 0.5
292 : + padfGeoTransform[5] * 0.5,
293 : szSRSName,
294 : padfGeoTransform[1], padfGeoTransform[2],
295 : szSRSName,
296 : padfGeoTransform[4], padfGeoTransform[5] );
297 :
298 : /* -------------------------------------------------------------------- */
299 : /* If we need a user defined CRSDictionary entry, prepare it */
300 : /* here. */
301 : /* -------------------------------------------------------------------- */
302 : char *pszDictBox = NULL;
303 :
304 : if( nEPSGCode == 0 )
305 : {
306 : char *pszGMLDef = NULL;
307 :
308 : if( oSRS.exportToXML( &pszGMLDef, NULL ) == OGRERR_NONE )
309 : {
310 : pszDictBox = (char *) CPLMalloc(strlen(pszGMLDef) + 4000);
311 :
312 : sprintf( pszDictBox,
313 : "<gml:Dictionary gml:id=\"CRSU1\" \n"
314 : " xmlns:gml=\"http://www.opengis.net/gml\"\n"
315 : " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
316 : " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"
317 : " <gml:dictionaryEntry>\n"
318 : "%s\n"
319 : " </gml:dictionaryEntry>\n"
320 : "</gml:Dictionary>\n",
321 : pszGMLDef );
322 : }
323 : CPLFree( pszGMLDef );
324 : }
325 :
326 : /* -------------------------------------------------------------------- */
327 : /* Setup the various required boxes. */
328 : /* -------------------------------------------------------------------- */
329 : JP2UserBox *poGMLData;
330 : CNCSJP2File::CNCSJPXAssocBox *poAssoc;
331 : CNCSJP2File::CNCSJPXLabelBox *poLabel;
332 :
333 : poLabel = new CNCSJP2File::CNCSJPXLabelBox();
334 : poLabel->SetLabel( "gml.data" );
335 : poLabel->m_bValid = true;
336 : m_oGMLAssoc.m_OtherBoxes.push_back( poLabel );
337 : m_oGMLAssoc.m_OwnedBoxes.push_back( poLabel );
338 :
339 : poAssoc = new CNCSJP2File::CNCSJPXAssocBox();
340 : m_oGMLAssoc.m_OtherBoxes.push_back( poAssoc );
341 : m_oGMLAssoc.m_OwnedBoxes.push_back( poAssoc );
342 : poAssoc->m_bValid = true;
343 :
344 : poLabel = new CNCSJP2File::CNCSJPXLabelBox();
345 : poLabel->SetLabel( "gml.root-instance" );
346 : poLabel->m_bValid = true;
347 : poAssoc->m_OtherBoxes.push_back( poLabel );
348 : poAssoc->m_OwnedBoxes.push_back( poLabel );
349 :
350 : poGMLData = new JP2UserBox();
351 : poGMLData->m_nTBox = 'xml '; /* Is it correct on a big-endian host ? Does ECW work on big-endian hosts ;-) */
352 : poGMLData->SetData( strlen( szDoc ), (unsigned char *) szDoc );
353 : poAssoc->m_OtherBoxes.push_back( poGMLData );
354 : poAssoc->m_OwnedBoxes.push_back( poGMLData );
355 :
356 : if( pszDictBox != NULL )
357 : {
358 : poAssoc = new CNCSJP2File::CNCSJPXAssocBox();
359 : m_oGMLAssoc.m_OtherBoxes.push_back( poAssoc );
360 : m_oGMLAssoc.m_OwnedBoxes.push_back( poAssoc );
361 : poAssoc->m_bValid = true;
362 :
363 : poLabel = new CNCSJP2File::CNCSJPXLabelBox();
364 : poLabel->SetLabel( "CRSDictionary.gml" );
365 : poLabel->m_bValid = true;
366 : poAssoc->m_OtherBoxes.push_back( poLabel );
367 : poAssoc->m_OwnedBoxes.push_back( poLabel );
368 :
369 : poGMLData = new JP2UserBox();
370 : poGMLData->m_nTBox = 'xml '; /* Is it correct on a big-endian host ? Does ECW work on big-endian hosts ;-) */
371 : poGMLData->SetData( strlen(pszDictBox),
372 : (unsigned char *) pszDictBox );
373 : poAssoc->m_OtherBoxes.push_back( poGMLData );
374 : poAssoc->m_OwnedBoxes.push_back( poGMLData );
375 :
376 : CPLFree( pszDictBox );
377 : }
378 :
379 : m_oGMLAssoc.m_bValid = true;
380 : AddBox( &m_oGMLAssoc );
381 :
382 : return CE_None;
383 : #endif /* def ECW_FW */
384 : }
385 :
386 : /************************************************************************/
387 : /* WriteJP2Box() */
388 : /************************************************************************/
389 :
390 42 : CPLErr GDALECWCompressor::WriteJP2Box( GDALJP2Box * poBox )
391 :
392 : {
393 : JP2UserBox *poECWBox;
394 :
395 42 : if( poBox == NULL )
396 2 : return CE_None;
397 :
398 40 : poECWBox = new JP2UserBox();
399 40 : memcpy( &(poECWBox->m_nTBox), poBox->GetType(), 4 );
400 40 : CPL_MSBPTR32( &(poECWBox->m_nTBox) );
401 :
402 : poECWBox->SetData( (int) poBox->GetDataLength(),
403 40 : poBox->GetWritableData() );
404 :
405 40 : AddBox( poECWBox );
406 :
407 80 : delete poBox;
408 :
409 : papoJP2UserBox =(JP2UserBox**) CPLRealloc(papoJP2UserBox,
410 40 : (nJP2UserBox + 1) * sizeof(JP2UserBox*));
411 40 : papoJP2UserBox[nJP2UserBox] = poECWBox;
412 40 : nJP2UserBox ++;
413 :
414 40 : return CE_None;
415 : }
416 :
417 :
418 : /************************************************************************/
419 : /* Initialize() */
420 : /* */
421 : /* Initialize compressor output. */
422 : /************************************************************************/
423 :
424 21 : CPLErr GDALECWCompressor::Initialize(
425 : const char *pszFilename, char **papszOptions,
426 : int nXSize, int nYSize, int nBands, int bRGBA,
427 : GDALDataType eType,
428 : const char *pszWKT, double *padfGeoTransform,
429 : int nGCPCount, const GDAL_GCP *pasGCPList,
430 : int bIsJPEG2000 )
431 :
432 : {
433 : /* -------------------------------------------------------------------- */
434 : /* For 4.x and beyond you need a license key to compress data. */
435 : /* Check for it as a configuration option or a creation option. */
436 : /* -------------------------------------------------------------------- */
437 : #if ECWSDK_VERSION >= 40
438 : const char* pszECWKey = CSLFetchNameValue( papszOptions, "ECW_ENCODE_KEY");
439 : if( pszECWKey == NULL )
440 : pszECWKey = CPLGetConfigOption( "ECW_ENCODE_KEY", NULL );
441 :
442 : const char* pszECWCompany =
443 : CSLFetchNameValue( papszOptions, "ECW_ENCODE_COMPANY");
444 : if( pszECWCompany == NULL )
445 : pszECWCompany = CPLGetConfigOption( "ECW_ENCODE_COMPANY", NULL );
446 :
447 : if( pszECWKey && pszECWCompany)
448 : {
449 : CPLDebug( "ECW", "SetOEMKey(%s,%s)", pszECWCompany, pszECWKey );
450 : CNCSFile::SetOEMKey( (char *) pszECWCompany, (char *)pszECWKey );
451 : }
452 : else if( pszECWKey || pszECWCompany )
453 : {
454 : CPLError( CE_Failure, CPLE_AppDefined,
455 : "Only one of ECW_ENCODE_KEY and ECW_ENCODE_COMPANY were provided.\nBoth are required." );
456 : return CE_Failure;
457 : }
458 :
459 : #endif /* ECWSDK_VERSION >= 40 */
460 :
461 : /* -------------------------------------------------------------------- */
462 : /* Do some rudimentary checking in input. */
463 : /* -------------------------------------------------------------------- */
464 21 : if( nBands == 0 )
465 : {
466 : CPLError( CE_Failure, CPLE_NotSupported,
467 0 : "ECW driver requires at least one band." );
468 0 : return CE_Failure;
469 : }
470 :
471 : /* -------------------------------------------------------------------- */
472 : /* Parse out some known options. */
473 : /* -------------------------------------------------------------------- */
474 : float fTargetCompression;
475 :
476 : // Default compression based on image type per request from Paul Beaty.
477 21 : if( nBands > 1 )
478 9 : fTargetCompression = 95.0;
479 : else
480 12 : fTargetCompression = 90.0;
481 :
482 21 : if( CSLFetchNameValue(papszOptions, "TARGET") != NULL )
483 : {
484 : fTargetCompression = (float)
485 6 : atof(CSLFetchNameValue(papszOptions, "TARGET"));
486 :
487 6 : if( fTargetCompression < 0.0 || fTargetCompression > 99.0 )
488 : {
489 : CPLError( CE_Failure, CPLE_NotSupported,
490 : "TARGET compression of %.3f invalid, should be a\n"
491 : "value between 0 and 99 percent.\n",
492 0 : (double) fTargetCompression );
493 0 : return CE_Failure;
494 : }
495 : }
496 :
497 : /* -------------------------------------------------------------------- */
498 : /* Create and initialize compressor. */
499 : /* -------------------------------------------------------------------- */
500 21 : NCSFileViewFileInfoEx *psClient = &(sFileInfo);
501 :
502 21 : psClient->nBands = (UINT16) nBands;
503 21 : psClient->nSizeX = nXSize;
504 21 : psClient->nSizeY = nYSize;
505 21 : psClient->nCompressionRate = (UINT16) MAX(1,100/(100-fTargetCompression));
506 21 : psClient->eCellSizeUnits = ECW_CELL_UNITS_METERS;
507 :
508 21 : if( nBands == 1 )
509 12 : psClient->eColorSpace = NCSCS_GREYSCALE;
510 9 : else if( nBands == 3 )
511 4 : psClient->eColorSpace = NCSCS_sRGB;
512 : #if ECWSDK_VERSION >= 40
513 : else if( nBands == 4 && bRGBA )
514 : psClient->eColorSpace = NCSCS_sRGB;
515 : #endif
516 : else
517 5 : psClient->eColorSpace = NCSCS_MULTIBAND;
518 :
519 : /* -------------------------------------------------------------------- */
520 : /* Figure out the data type. */
521 : /* -------------------------------------------------------------------- */
522 21 : int bSigned = FALSE;
523 21 : int nBits = 8;
524 21 : eWorkDT = eType;
525 :
526 21 : switch( eWorkDT )
527 : {
528 : case GDT_Byte:
529 15 : psClient->eCellType = NCSCT_UINT8;
530 15 : nBits = 8;
531 15 : bSigned = FALSE;
532 15 : break;
533 :
534 : case GDT_UInt16:
535 1 : psClient->eCellType = NCSCT_UINT16;
536 1 : nBits = 16;
537 1 : bSigned = FALSE;
538 1 : break;
539 :
540 : case GDT_UInt32:
541 1 : psClient->eCellType = NCSCT_UINT32;
542 1 : nBits = 32;
543 1 : bSigned = FALSE;
544 1 : break;
545 :
546 : case GDT_Int16:
547 2 : psClient->eCellType = NCSCT_INT16;
548 2 : nBits = 16;
549 2 : bSigned = TRUE;
550 2 : break;
551 :
552 : case GDT_Int32:
553 1 : psClient->eCellType = NCSCT_INT32;
554 1 : nBits = 32;
555 1 : bSigned = TRUE;
556 1 : break;
557 :
558 : case GDT_Float32:
559 1 : psClient->eCellType = NCSCT_IEEE4;
560 1 : nBits = 32;
561 1 : bSigned = TRUE;
562 1 : break;
563 :
564 : case GDT_Float64:
565 0 : psClient->eCellType = NCSCT_IEEE8;
566 0 : nBits = 64;
567 0 : bSigned = TRUE;
568 0 : break;
569 :
570 : default:
571 : // We treat complex types as float.
572 0 : psClient->eCellType = NCSCT_IEEE4;
573 0 : nBits = 32;
574 0 : bSigned = TRUE;
575 0 : eWorkDT = GDT_Float32;
576 : break;
577 : }
578 :
579 : /* -------------------------------------------------------------------- */
580 : /* Create band information structures. */
581 : /* -------------------------------------------------------------------- */
582 : int iBand;
583 :
584 : psClient->pBands = (NCSFileBandInfo *)
585 21 : CPLMalloc( sizeof(NCSFileBandInfo) * nBands );
586 60 : for( iBand = 0; iBand < nBands; iBand++ )
587 : {
588 39 : psClient->pBands[iBand].nBits = (UINT8) nBits;
589 39 : psClient->pBands[iBand].bSigned = (BOOLEAN)bSigned;
590 39 : psClient->pBands[iBand].szDesc = CPLStrdup(
591 39 : CPLSPrintf("Band%d",iBand+1) );
592 : }
593 :
594 : /* -------------------------------------------------------------------- */
595 : /* Allow CNCSFile::SetParameter() requests. */
596 : /* -------------------------------------------------------------------- */
597 : const char *pszOption;
598 :
599 21 : if( bIsJPEG2000 )
600 : {
601 18 : pszOption = CSLFetchNameValue(papszOptions, "PROFILE");
602 18 : if( pszOption != NULL && EQUAL(pszOption,"BASELINE_0") )
603 : SetParameter(
604 0 : CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_0 );
605 18 : else if( pszOption != NULL && EQUAL(pszOption,"BASELINE_1") )
606 : SetParameter(
607 0 : CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_1 );
608 18 : else if( pszOption != NULL && EQUAL(pszOption,"BASELINE_2") )
609 : SetParameter(
610 0 : CNCSJP2FileView::JP2_COMPRESS_PROFILE_BASELINE_2 );
611 21 : else if( pszOption != NULL && EQUAL(pszOption,"NPJE") )
612 : SetParameter(
613 3 : CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_NPJE );
614 15 : else if( pszOption != NULL && EQUAL(pszOption,"EPJE") )
615 : SetParameter(
616 0 : CNCSJP2FileView::JP2_COMPRESS_PROFILE_NITF_BIIF_EPJE );
617 :
618 18 : pszOption = CSLFetchNameValue(papszOptions, "CODESTREAM_ONLY" );
619 18 : if( pszOption != NULL )
620 : SetParameter(
621 : CNCSJP2FileView::JP2_COMPRESS_CODESTREAM_ONLY,
622 3 : (bool) CSLTestBoolean( pszOption ) );
623 :
624 18 : pszOption = CSLFetchNameValue(papszOptions, "LEVELS");
625 18 : if( pszOption != NULL )
626 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_LEVELS,
627 0 : (UINT32) atoi(pszOption) );
628 :
629 18 : pszOption = CSLFetchNameValue(papszOptions, "LAYERS");
630 18 : if( pszOption != NULL )
631 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_LAYERS,
632 0 : (UINT32) atoi(pszOption) );
633 :
634 18 : pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_WIDTH");
635 18 : if( pszOption != NULL )
636 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_PRECINCT_WIDTH,
637 0 : (UINT32) atoi(pszOption) );
638 :
639 18 : pszOption = CSLFetchNameValue(papszOptions, "PRECINCT_HEIGHT");
640 18 : if( pszOption != NULL )
641 : SetParameter(CNCSJP2FileView::JP2_COMPRESS_PRECINCT_HEIGHT,
642 0 : (UINT32) atoi(pszOption) );
643 :
644 18 : pszOption = CSLFetchNameValue(papszOptions, "TILE_WIDTH");
645 18 : if( pszOption != NULL )
646 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_TILE_WIDTH,
647 0 : (UINT32) atoi(pszOption) );
648 :
649 18 : pszOption = CSLFetchNameValue(papszOptions, "TILE_HEIGHT");
650 18 : if( pszOption != NULL )
651 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_TILE_HEIGHT,
652 0 : (UINT32) atoi(pszOption) );
653 :
654 18 : pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_SOP");
655 18 : if( pszOption != NULL )
656 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_INCLUDE_SOP,
657 0 : (bool) CSLTestBoolean( pszOption ) );
658 :
659 18 : pszOption = CSLFetchNameValue(papszOptions, "INCLUDE_EPH");
660 18 : if( pszOption != NULL )
661 : SetParameter( CNCSJP2FileView::JP2_COMPRESS_INCLUDE_EPH,
662 0 : (bool) CSLTestBoolean( pszOption ) );
663 :
664 18 : pszOption = CSLFetchNameValue(papszOptions, "PROGRESSION");
665 18 : if( pszOption != NULL && EQUAL(pszOption,"LRCP") )
666 : SetParameter(
667 0 : CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_LRCP );
668 :
669 18 : else if( pszOption != NULL && EQUAL(pszOption,"RLCP") )
670 : SetParameter(
671 0 : CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RLCP );
672 :
673 18 : else if( pszOption != NULL && EQUAL(pszOption,"RPCL") )
674 : SetParameter(
675 0 : CNCSJP2FileView::JP2_COMPRESS_PROGRESSION_RPCL );
676 :
677 18 : pszOption = CSLFetchNameValue(papszOptions, "GEODATA_USAGE");
678 18 : if( pszOption == NULL )
679 : // Default to supressing ECW SDK geodata, just use our own stuff.
680 18 : SetGeodataUsage( JP2_GEODATA_USE_NONE );
681 0 : else if( EQUAL(pszOption,"NONE") )
682 0 : SetGeodataUsage( JP2_GEODATA_USE_NONE );
683 0 : else if( EQUAL(pszOption,"PCS_ONLY") )
684 0 : SetGeodataUsage( JP2_GEODATA_USE_PCS_ONLY );
685 0 : else if( EQUAL(pszOption,"GML_ONLY") )
686 0 : SetGeodataUsage( JP2_GEODATA_USE_GML_ONLY );
687 0 : else if( EQUAL(pszOption,"PCS_GML") )
688 0 : SetGeodataUsage( JP2_GEODATA_USE_PCS_GML );
689 0 : else if( EQUAL(pszOption,"GML_PCS") )
690 0 : SetGeodataUsage( JP2_GEODATA_USE_GML_PCS );
691 0 : else if( EQUAL(pszOption,"ALL") )
692 0 : SetGeodataUsage( JP2_GEODATA_USE_GML_PCS_WLD );
693 :
694 18 : pszOption = CSLFetchNameValue(papszOptions, "DECOMPRESS_LAYERS");
695 18 : if( pszOption != NULL )
696 : SetParameter(
697 : CNCSJP2FileView::JP2_DECOMPRESS_LAYERS,
698 0 : (UINT32) atoi(pszOption) );
699 :
700 : pszOption = CSLFetchNameValue(papszOptions,
701 18 : "DECOMPRESS_RECONSTRUCTION_PARAMETER");
702 18 : if( pszOption != NULL )
703 : SetParameter(
704 : CNCSJP2FileView::JPC_DECOMPRESS_RECONSTRUCTION_PARAMETER,
705 0 : (IEEE4) atof(pszOption) );
706 : }
707 :
708 : /* -------------------------------------------------------------------- */
709 : /* Georeferencing. */
710 : /* -------------------------------------------------------------------- */
711 :
712 21 : psClient->fOriginX = 0.0;
713 21 : psClient->fOriginY = psClient->nSizeY;
714 21 : psClient->fCellIncrementX = 1.0;
715 21 : psClient->fCellIncrementY = -1.0;
716 21 : psClient->fCWRotationDegrees = 0.0;
717 :
718 21 : if( padfGeoTransform[2] != 0.0 || padfGeoTransform[4] != 0.0 )
719 : CPLError( CE_Warning, CPLE_NotSupported,
720 : "Rotational coefficients ignored, georeferencing of\n"
721 0 : "output ECW file will be incorrect.\n" );
722 : else
723 : {
724 21 : psClient->fOriginX = padfGeoTransform[0];
725 21 : psClient->fOriginY = padfGeoTransform[3];
726 21 : psClient->fCellIncrementX = padfGeoTransform[1];
727 21 : psClient->fCellIncrementY = padfGeoTransform[5];
728 : }
729 :
730 : /* -------------------------------------------------------------------- */
731 : /* Projection. */
732 : /* -------------------------------------------------------------------- */
733 : char szProjection[128];
734 : char szDatum[128];
735 : char szUnits[128];
736 :
737 21 : strcpy( szProjection, "RAW" );
738 21 : strcpy( szDatum, "RAW" );
739 :
740 21 : if( CSLFetchNameValue(papszOptions, "PROJ") != NULL )
741 : {
742 : strncpy( szProjection,
743 0 : CSLFetchNameValue(papszOptions, "PROJ"), sizeof(szProjection) );
744 0 : szProjection[sizeof(szProjection)-1] = 0;
745 : }
746 :
747 21 : if( CSLFetchNameValue(papszOptions, "DATUM") != NULL )
748 : {
749 0 : strncpy( szDatum, CSLFetchNameValue(papszOptions, "DATUM"), sizeof(szDatum) );
750 0 : szDatum[sizeof(szDatum)-1] = 0;
751 0 : if( EQUAL(szProjection,"RAW") )
752 0 : strcpy( szProjection, "GEODETIC" );
753 : }
754 :
755 21 : const char* pszUnits = CSLFetchNameValue(papszOptions, "UNITS");
756 21 : if( pszUnits != NULL )
757 : {
758 0 : psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(pszUnits);
759 : }
760 :
761 21 : if( EQUAL(szProjection,"RAW") && pszWKT != NULL )
762 : {
763 20 : ECWTranslateFromWKT( pszWKT, szProjection, sizeof(szProjection), szDatum, sizeof(szDatum), szUnits );
764 20 : psClient->eCellSizeUnits = ECWTranslateToCellSizeUnits(szUnits);
765 : }
766 :
767 21 : psClient->szDatum = szDatum;
768 21 : psClient->szProjection = szProjection;
769 :
770 : CPLDebug( "ECW", "Writing with PROJ=%s, DATUM=%s, UNITS=%s",
771 21 : szProjection, szDatum, ECWTranslateFromCellSizeUnits(psClient->eCellSizeUnits) );
772 :
773 : /* -------------------------------------------------------------------- */
774 : /* Setup GML and GeoTIFF information. */
775 : /* -------------------------------------------------------------------- */
776 21 : GDALJP2Metadata oJP2MD;
777 :
778 21 : oJP2MD.SetProjection( pszWKT );
779 21 : oJP2MD.SetGeoTransform( padfGeoTransform );
780 21 : oJP2MD.SetGCPs( nGCPCount, pasGCPList );
781 :
782 21 : if( CSLFetchBoolean( papszOptions, "GMLJP2", TRUE ) )
783 21 : WriteJP2Box( oJP2MD.CreateGMLJP2(nXSize,nYSize) );
784 21 : if( CSLFetchBoolean( papszOptions, "GeoJP2", TRUE ) )
785 21 : WriteJP2Box( oJP2MD.CreateJP2GeoTIFF() );
786 :
787 : /* -------------------------------------------------------------------- */
788 : /* We handle all jpeg2000 files via the VSIIOStream, but ECW */
789 : /* files cannot be done this way for some reason. */
790 : /* -------------------------------------------------------------------- */
791 21 : VSILFILE *fpVSIL = NULL;
792 :
793 21 : if( bIsJPEG2000 )
794 : {
795 18 : fpVSIL = VSIFOpenL( pszFilename, "wb+" );
796 18 : if( fpVSIL == NULL )
797 : {
798 : CPLError( CE_Failure, CPLE_OpenFailed,
799 2 : "Failed to open %s.", pszFilename );
800 2 : return CE_Failure;
801 : }
802 :
803 16 : m_OStream.Access( fpVSIL, TRUE, pszFilename, 0, -1 );
804 : }
805 :
806 : /* -------------------------------------------------------------------- */
807 : /* Check if we can enable large files. This option should only */
808 : /* be set when the application is adhering to one of the */
809 : /* ERMapper options for licensing larger than 500MB input */
810 : /* files. See Bug 767. This option no longer exists with */
811 : /* version 4+. */
812 : /* -------------------------------------------------------------------- */
813 : #if ECWSDK_VERSION < 40
814 19 : const char *pszLargeOK = CSLFetchNameValue(papszOptions, "LARGE_OK");
815 19 : if( pszLargeOK == NULL )
816 19 : pszLargeOK = "NO";
817 :
818 19 : pszLargeOK = CPLGetConfigOption( "ECW_LARGE_OK", pszLargeOK );
819 :
820 19 : if( CSLTestBoolean(pszLargeOK) )
821 : {
822 0 : CNCSFile::SetKeySize();
823 0 : CPLDebug( "ECW", "Large file generation enabled." );
824 : }
825 : #endif /* ECWSDK_VERSION < 40 */
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Set the file info. */
829 : /* -------------------------------------------------------------------- */
830 19 : CNCSError oError;
831 :
832 19 : oError = SetFileInfo( sFileInfo );
833 :
834 19 : if( oError.GetErrorNumber() == NCS_SUCCESS )
835 : {
836 19 : if( fpVSIL == NULL )
837 3 : oError = Open( (char *) pszFilename, false, true );
838 : else
839 16 : oError = CNCSJP2FileView::Open( &(m_OStream) );
840 : }
841 :
842 19 : if( oError.GetErrorNumber() == NCS_SUCCESS )
843 17 : return CE_None;
844 2 : else if( oError.GetErrorNumber() == NCS_INPUT_SIZE_EXCEEDED )
845 : {
846 : CPLError( CE_Failure, CPLE_AppDefined,
847 0 : "ECW SDK 500MB compress limit exceeded." );
848 0 : return CE_Failure;
849 : }
850 : else
851 : {
852 2 : char* pszErrorMessage = oError.GetErrorMessage();
853 : CPLError( CE_Failure, CPLE_AppDefined,
854 2 : "%s", pszErrorMessage );
855 2 : NCSFree(pszErrorMessage);
856 :
857 2 : return CE_Failure;
858 0 : }
859 : }
860 :
861 : /************************************************************************/
862 : /* ECWCreateCopy() */
863 : /************************************************************************/
864 :
865 : static GDALDataset *
866 19 : ECWCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
867 : int bStrict, char ** papszOptions,
868 : GDALProgressFunc pfnProgress, void * pProgressData,
869 : int bIsJPEG2000 )
870 :
871 : {
872 19 : ECWInitialize();
873 :
874 : /* -------------------------------------------------------------------- */
875 : /* Get various values from the source dataset. */
876 : /* -------------------------------------------------------------------- */
877 19 : int nBands = poSrcDS->GetRasterCount();
878 19 : int nXSize = poSrcDS->GetRasterXSize();
879 19 : int nYSize = poSrcDS->GetRasterYSize();
880 :
881 19 : if (nBands == 0)
882 : {
883 : CPLError( CE_Failure, CPLE_NotSupported,
884 0 : "ECW driver does not support source dataset with zero band.\n");
885 0 : return NULL;
886 : }
887 :
888 19 : GDALDataType eType = poSrcDS->GetRasterBand(1)->GetRasterDataType();
889 :
890 19 : const char *pszWKT = poSrcDS->GetProjectionRef();
891 19 : double adfGeoTransform[6] = { 0, 1, 0, 0, 0, 1 };;
892 :
893 19 : poSrcDS->GetGeoTransform( adfGeoTransform );
894 :
895 19 : if( poSrcDS->GetGCPCount() > 0 )
896 1 : pszWKT = poSrcDS->GetGCPProjection();
897 :
898 : /* -------------------------------------------------------------------- */
899 : /* Confirm the datatype is 8bit. It appears no other datatype */
900 : /* is supported in ECW format. */
901 : /* -------------------------------------------------------------------- */
902 19 : if( eType != GDT_Byte && !bIsJPEG2000 )
903 : {
904 0 : if( bStrict )
905 : {
906 : CPLError( CE_Failure, CPLE_AppDefined,
907 : "Attempt to create ECW file with pixel data type %s failed.\n"
908 : "Only Byte data type supported.",
909 0 : GDALGetDataTypeName( eType ) );
910 : }
911 : else
912 : {
913 : CPLError( CE_Warning, CPLE_AppDefined,
914 : "ECW only supports Byte pixel data type, ignoring request for %s.",
915 0 : GDALGetDataTypeName( eType ) );
916 0 : eType = GDT_Byte;
917 : }
918 : }
919 :
920 : /* -------------------------------------------------------------------- */
921 : /* Is the input RGBA? */
922 : /* -------------------------------------------------------------------- */
923 19 : int bRGBA = FALSE;
924 :
925 19 : if( nBands == 4 )
926 : {
927 1 : bRGBA = (poSrcDS->GetRasterBand(4)->GetColorInterpretation()
928 2 : == GCI_AlphaBand);
929 : }
930 :
931 : /* -------------------------------------------------------------------- */
932 : /* Setup the compressor. */
933 : /* -------------------------------------------------------------------- */
934 19 : GDALECWCompressor oCompressor;
935 19 : CNCSError oErr;
936 :
937 19 : oCompressor.pfnProgress = pfnProgress;
938 19 : oCompressor.pProgressData = pProgressData;
939 19 : oCompressor.m_poSrcDS = poSrcDS;
940 :
941 19 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
942 0 : return NULL;
943 :
944 38 : if( oCompressor.Initialize( pszFilename, papszOptions,
945 : nXSize, nYSize, nBands, bRGBA,
946 : eType, pszWKT, adfGeoTransform,
947 19 : poSrcDS->GetGCPCount(),
948 19 : poSrcDS->GetGCPs(),
949 : bIsJPEG2000 )
950 : != CE_None )
951 4 : return NULL;
952 :
953 : /* -------------------------------------------------------------------- */
954 : /* Start the compression. */
955 : /* -------------------------------------------------------------------- */
956 15 : oErr = oCompressor.Write();
957 :
958 15 : if( oErr.GetErrorNumber() != NCS_SUCCESS )
959 : {
960 0 : char* pszErrorMessage = oErr.GetErrorMessage();
961 : CPLError( CE_Failure, CPLE_AppDefined,
962 0 : "%s", pszErrorMessage );
963 0 : NCSFree(pszErrorMessage);
964 :
965 0 : return NULL;
966 : }
967 :
968 : /* -------------------------------------------------------------------- */
969 : /* Cleanup, and return read-only handle. */
970 : /* -------------------------------------------------------------------- */
971 15 : oCompressor.CloseDown();
972 15 : pfnProgress( 1.001, NULL, pProgressData );
973 :
974 : /* -------------------------------------------------------------------- */
975 : /* Re-open dataset, and copy any auxilary pam information. */
976 : /* -------------------------------------------------------------------- */
977 15 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
978 : GDALPamDataset *poDS;
979 :
980 15 : if (bIsJPEG2000)
981 14 : poDS = (GDALPamDataset*) ECWDatasetOpenJPEG2000(&oOpenInfo);
982 : else
983 1 : poDS = (GDALPamDataset*) GDALOpen(pszFilename, GA_ReadOnly);
984 :
985 15 : if( poDS )
986 15 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
987 :
988 15 : return poDS;
989 : }
990 :
991 : /************************************************************************/
992 : /* ECWCreateCopyECW() */
993 : /************************************************************************/
994 :
995 : GDALDataset *
996 19 : ECWCreateCopyECW( const char * pszFilename, GDALDataset *poSrcDS,
997 : int bStrict, char ** papszOptions,
998 : GDALProgressFunc pfnProgress, void * pProgressData )
999 :
1000 : {
1001 19 : int nBands = poSrcDS->GetRasterCount();
1002 19 : if (nBands == 0)
1003 : {
1004 : CPLError( CE_Failure, CPLE_NotSupported,
1005 1 : "ECW driver does not support source dataset with zero band.\n");
1006 1 : return NULL;
1007 : }
1008 :
1009 18 : if( !EQUAL(CPLGetExtension(pszFilename),"ecw") )
1010 : {
1011 : CPLError( CE_Failure, CPLE_AppDefined,
1012 : "ECW driver does not support creating ECW files\n"
1013 0 : "with an extension other than .ecw" );
1014 0 : return NULL;
1015 : }
1016 :
1017 18 : if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
1018 : && bStrict )
1019 : {
1020 : CPLError( CE_Failure, CPLE_NotSupported,
1021 : "ECW driver doesn't support data type %s. "
1022 : "Only eight bit bands supported.\n",
1023 : GDALGetDataTypeName(
1024 10 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
1025 :
1026 10 : return NULL;
1027 : }
1028 :
1029 8 : if( poSrcDS->GetRasterXSize() < 128 || poSrcDS->GetRasterYSize() < 128 )
1030 : {
1031 : CPLError( CE_Failure, CPLE_NotSupported,
1032 : "ECW driver requires image to be at least 128x128,\n"
1033 : "the source image is %dx%d.\n",
1034 : poSrcDS->GetRasterXSize(),
1035 5 : poSrcDS->GetRasterYSize() );
1036 :
1037 5 : return NULL;
1038 : }
1039 :
1040 3 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
1041 : {
1042 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
1043 : "ECW driver ignores color table. "
1044 : "The source raster band will be considered as grey level.\n"
1045 0 : "Consider using color table expansion (-expand option in gdal_translate)\n");
1046 0 : if (bStrict)
1047 0 : return NULL;
1048 : }
1049 :
1050 : return ECWCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
1051 3 : pfnProgress, pProgressData, FALSE );
1052 : }
1053 :
1054 : /************************************************************************/
1055 : /* ECWCreateCopyJPEG2000() */
1056 : /************************************************************************/
1057 :
1058 : GDALDataset *
1059 21 : ECWCreateCopyJPEG2000( const char * pszFilename, GDALDataset *poSrcDS,
1060 : int bStrict, char ** papszOptions,
1061 : GDALProgressFunc pfnProgress, void * pProgressData )
1062 :
1063 : {
1064 21 : int nBands = poSrcDS->GetRasterCount();
1065 21 : if (nBands == 0)
1066 : {
1067 : CPLError( CE_Failure, CPLE_NotSupported,
1068 1 : "JP2ECW driver does not support source dataset with zero band.\n");
1069 1 : return NULL;
1070 : }
1071 :
1072 20 : if( EQUAL(CPLGetExtension(pszFilename),"ecw") )
1073 : {
1074 : CPLError( CE_Failure, CPLE_AppDefined,
1075 : "JP2ECW driver does not support creating JPEG2000 files\n"
1076 0 : "with a .ecw extension. Please use anything else." );
1077 0 : return NULL;
1078 : }
1079 :
1080 20 : if( poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
1081 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte
1082 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int16
1083 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt16
1084 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Int32
1085 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_UInt32
1086 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Float32
1087 : && poSrcDS->GetRasterBand(1)->GetRasterDataType() != GDT_Float64
1088 : && bStrict )
1089 : {
1090 : CPLError( CE_Failure, CPLE_NotSupported,
1091 : "JP2ECW driver doesn't support data type %s. ",
1092 : GDALGetDataTypeName(
1093 4 : poSrcDS->GetRasterBand(1)->GetRasterDataType()) );
1094 :
1095 4 : return NULL;
1096 : }
1097 :
1098 16 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
1099 : {
1100 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
1101 : "JP2ECW driver ignores color table. "
1102 : "The source raster band will be considered as grey level.\n"
1103 0 : "Consider using color table expansion (-expand option in gdal_translate)\n");
1104 0 : if (bStrict)
1105 0 : return NULL;
1106 : }
1107 :
1108 : return ECWCreateCopy( pszFilename, poSrcDS, bStrict, papszOptions,
1109 16 : pfnProgress, pProgressData, TRUE );
1110 : }
1111 :
1112 : /************************************************************************/
1113 : /************************************************************************
1114 :
1115 : ECW/JPEG200 Create() Support
1116 : ----------------------------
1117 :
1118 : The remainder of the file is code to implement the Create() method.
1119 : New dataset and raster band classes are defined specifically for the
1120 : purpose of being write-only. In particular, you cannot read back data
1121 : from these datasets, and writing must occur in a pretty specific order.
1122 :
1123 : That is, you need to write all metadata (projection, georef, etc) first
1124 : and then write the image data. All bands data for the first scanline
1125 : should be written followed by all bands for the second scanline and so on.
1126 :
1127 : Creation supports the same virtual subfile names as CreateCopy() supports.
1128 :
1129 : ************************************************************************/
1130 : /************************************************************************/
1131 :
1132 : /************************************************************************/
1133 : /* ==================================================================== */
1134 : /* ECWWriteDataset */
1135 : /* ==================================================================== */
1136 : /************************************************************************/
1137 :
1138 : class ECWWriteRasterBand;
1139 :
1140 : class CPL_DLL ECWWriteDataset : public GDALDataset
1141 : {
1142 : friend class ECWWriteRasterBand;
1143 :
1144 : char *pszFilename;
1145 :
1146 : int bIsJPEG2000;
1147 : GDALDataType eDataType;
1148 : char **papszOptions;
1149 :
1150 : char *pszProjection;
1151 : double adfGeoTransform[6];
1152 :
1153 : GDALECWCompressor oCompressor;
1154 : int bCrystalized;
1155 :
1156 : int nLoadedLine;
1157 : GByte *pabyBILBuffer;
1158 :
1159 : CPLErr Crystalize();
1160 : CPLErr FlushLine();
1161 :
1162 : public:
1163 : ECWWriteDataset( const char *, int, int, int,
1164 : GDALDataType, char **papszOptions,
1165 : int );
1166 : ~ECWWriteDataset();
1167 :
1168 : virtual void FlushCache( void );
1169 :
1170 : virtual CPLErr GetGeoTransform( double * );
1171 : virtual const char* GetProjectionRef();
1172 : virtual CPLErr SetGeoTransform( double * );
1173 : virtual CPLErr SetProjection( const char *pszWKT );
1174 : };
1175 :
1176 : /************************************************************************/
1177 : /* ==================================================================== */
1178 : /* ECWWriteRasterBand */
1179 : /* ==================================================================== */
1180 : /************************************************************************/
1181 :
1182 : class ECWWriteRasterBand : public GDALRasterBand
1183 59 : {
1184 : friend class ECWWriteDataset;
1185 :
1186 : // NOTE: poDS may be altered for NITF/JPEG2000 files!
1187 : ECWWriteDataset *poGDS;
1188 :
1189 : GDALColorInterp eInterp;
1190 :
1191 : public:
1192 :
1193 : ECWWriteRasterBand( ECWWriteDataset *, int );
1194 :
1195 0 : virtual CPLErr SetColorInterpretation( GDALColorInterp eInterpIn )
1196 0 : { eInterp = eInterpIn; return CE_None; }
1197 3 : virtual GDALColorInterp GetColorInterpretation()
1198 3 : { return eInterp; }
1199 :
1200 : virtual CPLErr IReadBlock( int, int, void * );
1201 : virtual CPLErr IWriteBlock( int, int, void * );
1202 : };
1203 :
1204 : /************************************************************************/
1205 : /* ECWWriteDataset() */
1206 : /************************************************************************/
1207 :
1208 28 : ECWWriteDataset::ECWWriteDataset( const char *pszFilename,
1209 : int nXSize, int nYSize, int nBandCount,
1210 : GDALDataType eType,
1211 28 : char **papszOptions, int bIsJPEG2000 )
1212 :
1213 : {
1214 28 : bCrystalized = FALSE;
1215 28 : pabyBILBuffer = NULL;
1216 28 : nLoadedLine = -1;
1217 :
1218 28 : eAccess = GA_Update;
1219 :
1220 28 : this->bIsJPEG2000 = bIsJPEG2000;
1221 28 : this->eDataType = eType;
1222 28 : this->papszOptions = CSLDuplicate( papszOptions );
1223 28 : this->pszFilename = CPLStrdup( pszFilename );
1224 :
1225 28 : nRasterXSize = nXSize;
1226 28 : nRasterYSize = nYSize;
1227 28 : pszProjection = NULL;
1228 :
1229 28 : adfGeoTransform[0] = 0.0;
1230 28 : adfGeoTransform[1] = 1.0;
1231 28 : adfGeoTransform[2] = 0.0;
1232 28 : adfGeoTransform[3] = 0.0;
1233 28 : adfGeoTransform[4] = 0.0;
1234 28 : adfGeoTransform[5] = 1.0;
1235 :
1236 : // create band objects.
1237 87 : for( int iBand = 1; iBand <= nBandCount; iBand++ )
1238 : {
1239 59 : SetBand( iBand, new ECWWriteRasterBand( this, iBand ) );
1240 : }
1241 28 : }
1242 :
1243 : /************************************************************************/
1244 : /* ~ECWWriteDataset() */
1245 : /************************************************************************/
1246 :
1247 28 : ECWWriteDataset::~ECWWriteDataset()
1248 :
1249 : {
1250 28 : FlushCache();
1251 :
1252 28 : if( bCrystalized )
1253 : {
1254 2 : if( nLoadedLine == nRasterYSize - 1 )
1255 2 : FlushLine();
1256 2 : oCompressor.CloseDown();
1257 : }
1258 :
1259 28 : CPLFree( pabyBILBuffer );
1260 28 : CPLFree( pszProjection );
1261 28 : CSLDestroy( papszOptions );
1262 28 : CPLFree( pszFilename );
1263 28 : }
1264 :
1265 : /************************************************************************/
1266 : /* FlushCache() */
1267 : /************************************************************************/
1268 :
1269 29 : void ECWWriteDataset::FlushCache()
1270 :
1271 : {
1272 29 : BlockBasedFlushCache();
1273 29 : }
1274 :
1275 : /************************************************************************/
1276 : /* GetProjectionRef() */
1277 : /************************************************************************/
1278 :
1279 0 : const char* ECWWriteDataset::GetProjectionRef()
1280 : {
1281 0 : return pszProjection;
1282 : }
1283 :
1284 : /************************************************************************/
1285 : /* GetGeoTransform() */
1286 : /************************************************************************/
1287 :
1288 26 : CPLErr ECWWriteDataset::GetGeoTransform( double *padfGeoTransform )
1289 :
1290 : {
1291 26 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
1292 26 : return CE_None;
1293 : }
1294 :
1295 : /************************************************************************/
1296 : /* SetGeoTransform() */
1297 : /************************************************************************/
1298 :
1299 27 : CPLErr ECWWriteDataset::SetGeoTransform( double *padfGeoTransform )
1300 :
1301 : {
1302 27 : memcpy( adfGeoTransform, padfGeoTransform, sizeof(double) * 6 );
1303 27 : return CE_None;
1304 : }
1305 :
1306 : /************************************************************************/
1307 : /* SetProjection() */
1308 : /************************************************************************/
1309 :
1310 27 : CPLErr ECWWriteDataset::SetProjection( const char *pszWKT )
1311 :
1312 : {
1313 27 : CPLFree( pszProjection );
1314 27 : pszProjection = CPLStrdup( pszWKT );
1315 :
1316 27 : return CE_None;
1317 : }
1318 :
1319 :
1320 : /************************************************************************/
1321 : /* Crystalize() */
1322 : /************************************************************************/
1323 :
1324 2 : CPLErr ECWWriteDataset::Crystalize()
1325 :
1326 : {
1327 2 : int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1328 :
1329 : CPLErr eErr;
1330 2 : CNCSError oError;
1331 :
1332 2 : if( bCrystalized )
1333 0 : return CE_None;
1334 :
1335 : eErr = oCompressor.Initialize( pszFilename, papszOptions,
1336 : nRasterXSize, nRasterYSize, nBands, FALSE,
1337 : eDataType,
1338 : pszProjection, adfGeoTransform,
1339 : 0, NULL,
1340 2 : bIsJPEG2000 );
1341 :
1342 2 : if( eErr == CE_None )
1343 2 : bCrystalized = TRUE;
1344 :
1345 2 : nLoadedLine = -1;
1346 2 : pabyBILBuffer = (GByte *) CPLMalloc( nWordSize * nBands * nRasterXSize );
1347 :
1348 2 : return eErr;
1349 : }
1350 :
1351 : /************************************************************************/
1352 : /* FlushLine() */
1353 : /************************************************************************/
1354 :
1355 202 : CPLErr ECWWriteDataset::FlushLine()
1356 :
1357 : {
1358 202 : int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1359 : CPLErr eErr;
1360 :
1361 : /* -------------------------------------------------------------------- */
1362 : /* Crystalize if not already done. */
1363 : /* -------------------------------------------------------------------- */
1364 202 : if( !bCrystalized )
1365 : {
1366 2 : eErr = Crystalize();
1367 :
1368 2 : if( eErr != CE_None )
1369 0 : return eErr;
1370 : }
1371 :
1372 : /* -------------------------------------------------------------------- */
1373 : /* Write out the currently loaded line. */
1374 : /* -------------------------------------------------------------------- */
1375 202 : if( nLoadedLine != -1 )
1376 : {
1377 200 : CNCSError oError;
1378 : void **papOutputLine;
1379 :
1380 200 : papOutputLine = (void **) CPLMalloc(sizeof(void*) * nBands);
1381 600 : for( int i = 0; i < nBands; i++ )
1382 400 : papOutputLine[i] =
1383 400 : (void *) (pabyBILBuffer + i * nWordSize * nRasterXSize);
1384 :
1385 :
1386 : oError = oCompressor.WriteLineBIL( oCompressor.sFileInfo.eCellType,
1387 200 : (UINT16) nBands, papOutputLine );
1388 200 : CPLFree( papOutputLine );
1389 200 : if( oError.GetErrorNumber() != NCS_SUCCESS )
1390 : {
1391 0 : char* pszErrorMessage = oError.GetErrorMessage();
1392 : CPLError( CE_Failure, CPLE_AppDefined,
1393 : "Scanline write write failed.\n%s",
1394 0 : pszErrorMessage );
1395 0 : NCSFree(pszErrorMessage);
1396 :
1397 0 : return CE_Failure;
1398 0 : }
1399 : }
1400 :
1401 : /* -------------------------------------------------------------------- */
1402 : /* Clear the buffer and increment the "current line" indicator. */
1403 : /* -------------------------------------------------------------------- */
1404 202 : memset( pabyBILBuffer, 0, nWordSize * nRasterXSize * nBands );
1405 202 : nLoadedLine++;
1406 :
1407 202 : return CE_None;
1408 : }
1409 :
1410 :
1411 : /************************************************************************/
1412 : /* ==================================================================== */
1413 : /* ECWWriteRasterBand */
1414 : /* ==================================================================== */
1415 : /************************************************************************/
1416 :
1417 : /************************************************************************/
1418 : /* ECWWriteRasterBand() */
1419 : /************************************************************************/
1420 :
1421 59 : ECWWriteRasterBand::ECWWriteRasterBand( ECWWriteDataset *poDSIn,
1422 59 : int nBandIn )
1423 :
1424 : {
1425 59 : nBand = nBandIn;
1426 59 : poDS = poDSIn;
1427 59 : poGDS = poDSIn;
1428 59 : nBlockXSize = poDSIn->GetRasterXSize();
1429 59 : nBlockYSize = 1;
1430 59 : eDataType = poDSIn->eDataType;
1431 59 : eInterp = GCI_Undefined;
1432 59 : }
1433 :
1434 : /************************************************************************/
1435 : /* IReadBlock() */
1436 : /************************************************************************/
1437 :
1438 0 : CPLErr ECWWriteRasterBand::IReadBlock( int nBlockX, int nBlockY,
1439 : void *pBuffer )
1440 :
1441 : {
1442 0 : int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1443 :
1444 : // We zero stuff out here, but we can't really read stuff from
1445 : // a write only stream.
1446 :
1447 0 : memset( pBuffer, 0, nBlockXSize * nWordSize );
1448 :
1449 0 : return CE_None;
1450 : }
1451 :
1452 : /************************************************************************/
1453 : /* IWriteBlock() */
1454 : /************************************************************************/
1455 :
1456 400 : CPLErr ECWWriteRasterBand::IWriteBlock( int nBlockX, int nBlockY,
1457 : void *pBuffer )
1458 :
1459 : {
1460 400 : int nWordSize = GDALGetDataTypeSize( eDataType ) / 8;
1461 : CPLErr eErr;
1462 :
1463 : /* -------------------------------------------------------------------- */
1464 : /* Flush previous line if needed. */
1465 : /* -------------------------------------------------------------------- */
1466 400 : if( nBlockY == poGDS->nLoadedLine + 1 )
1467 : {
1468 200 : eErr = poGDS->FlushLine();
1469 200 : if( eErr != CE_None )
1470 0 : return eErr;
1471 : }
1472 :
1473 : /* -------------------------------------------------------------------- */
1474 : /* Blow a gasket if we have been asked to write something out */
1475 : /* of order. */
1476 : /* -------------------------------------------------------------------- */
1477 400 : if( nBlockY != poGDS->nLoadedLine )
1478 : {
1479 : CPLError( CE_Failure, CPLE_AppDefined,
1480 : "Apparent attempt to write to ECW non-sequentially.\n"
1481 : "Loaded line is %d, but %d of band %d was written to.",
1482 0 : poGDS->nLoadedLine, nBlockY, nBand );
1483 0 : return CE_Failure;
1484 : }
1485 :
1486 : /* -------------------------------------------------------------------- */
1487 : /* Copy passed data into current line buffer. */
1488 : /* -------------------------------------------------------------------- */
1489 : memcpy( poGDS->pabyBILBuffer + (nBand-1) * nWordSize * nRasterXSize,
1490 : pBuffer,
1491 400 : nWordSize * nRasterXSize );
1492 :
1493 400 : return CE_None;
1494 : }
1495 :
1496 : /************************************************************************/
1497 : /* ECWCreateJPEG2000() */
1498 : /************************************************************************/
1499 :
1500 : GDALDataset *
1501 28 : ECWCreateJPEG2000(const char *pszFilename, int nXSize, int nYSize, int nBands,
1502 : GDALDataType eType, char **papszOptions )
1503 :
1504 : {
1505 28 : ECWInitialize();
1506 :
1507 : return new ECWWriteDataset( pszFilename, nXSize, nYSize, nBands,
1508 28 : eType, papszOptions, TRUE );
1509 : }
1510 :
1511 : /************************************************************************/
1512 : /* ECWCreateECW() */
1513 : /************************************************************************/
1514 :
1515 : GDALDataset *
1516 0 : ECWCreateECW( const char *pszFilename, int nXSize, int nYSize, int nBands,
1517 : GDALDataType eType, char **papszOptions )
1518 :
1519 : {
1520 0 : ECWInitialize();
1521 :
1522 : return new ECWWriteDataset( pszFilename, nXSize, nYSize, nBands,
1523 0 : eType, papszOptions, FALSE );
1524 1947 : }
1525 :
1526 : #endif /* def FRMT_ecw && def HAVE_COMPRESS */
|