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