Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: Multi-resolution Seamless Image Database (MrSID)
4 : * Purpose: Read/write LizardTech's MrSID file format - Version 4+ SDK.
5 : * Author: Andrey Kiselev, dron@ak4719.spb.edu
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2003, Andrey Kiselev <dron@ak4719.spb.edu>
9 : * Copyright (c) 2007-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #define NO_DELETE
15 :
16 : #include "cpl_string.h"
17 : #include "gdal_frmts.h"
18 : #include "gdaljp2abstractdataset.h"
19 : #include "gdaljp2metadata.h"
20 : #include "ogr_spatialref.h"
21 :
22 : #include <algorithm>
23 : #include <string>
24 :
25 : #include "mrsiddrivercore.h"
26 :
27 : #include <geo_normalize.h>
28 : #include <geovalues.h>
29 :
30 : CPL_C_START
31 : double GTIFAngleToDD(double dfAngle, int nUOMAngle);
32 : void CPL_DLL LibgeotiffOneTimeInit();
33 : CPL_C_END
34 :
35 : #include "mrsiddataset_headers_include.h"
36 :
37 : #ifdef MRSID_POST5
38 : #define MRSID_HAVE_GETWKT
39 : #endif
40 :
41 : /* getTotalBandData is deprecated by getBandData, at least starting with 8.5 */
42 : #if defined(LTI_SDK_MAJOR) && \
43 : (LTI_SDK_MAJOR > 8 || (LTI_SDK_MAJOR >= 8 && LTI_SDK_MINOR >= 5))
44 : #define myGetTotalBandData getBandData
45 : #else
46 : #define myGetTotalBandData getTotalBandData
47 : #endif
48 :
49 : #include "mrsidstream.h"
50 :
51 : using namespace LizardTech;
52 :
53 : /* -------------------------------------------------------------------- */
54 : /* Various wrapper templates used to force new/delete to happen */
55 : /* in the same heap. See bug 1213 and MSDN knowledge base */
56 : /* article 122675. */
57 : /* -------------------------------------------------------------------- */
58 :
59 : template <class T> class LTIDLLPixel : public T
60 : {
61 : public:
62 62 : LTIDLLPixel(LTIColorSpace colorSpace, lt_uint16 numBands,
63 : LTIDataType dataType)
64 62 : : T(colorSpace, numBands, dataType)
65 : {
66 62 : }
67 :
68 124 : virtual ~LTIDLLPixel()
69 : {
70 124 : }
71 : };
72 :
73 : template <class T> class LTIDLLReader : public T
74 : {
75 : public:
76 : explicit LTIDLLReader(const LTFileSpec &fileSpec, bool useWorldFile = false)
77 : : T(fileSpec, useWorldFile)
78 : {
79 : }
80 :
81 : explicit LTIDLLReader(LTIOStreamInf &oStream, bool useWorldFile = false)
82 : : T(oStream, useWorldFile)
83 : {
84 : }
85 :
86 : explicit LTIDLLReader(LTIOStreamInf *poStream,
87 : LTIOStreamInf *poWorldFile = nullptr)
88 : : T(poStream, poWorldFile)
89 : {
90 : }
91 :
92 : virtual ~LTIDLLReader()
93 : {
94 : }
95 : };
96 :
97 : template <class T> class LTIDLLNavigator : public T
98 : {
99 : public:
100 62 : explicit LTIDLLNavigator(const LTIImage &image) : T(image)
101 : {
102 62 : }
103 :
104 124 : virtual ~LTIDLLNavigator()
105 : {
106 124 : }
107 : };
108 :
109 : template <class T> class LTIDLLBuffer : public T
110 : {
111 : public:
112 5 : LTIDLLBuffer(const LTIPixel &pixelProps, lt_uint32 totalNumCols,
113 : lt_uint32 totalNumRows, void **data)
114 5 : : T(pixelProps, totalNumCols, totalNumRows, data)
115 : {
116 5 : }
117 :
118 10 : virtual ~LTIDLLBuffer()
119 : {
120 10 : }
121 : };
122 :
123 : template <class T> class LTIDLLCopy : public T
124 : {
125 : public:
126 12 : explicit LTIDLLCopy(const T &original) : T(original)
127 : {
128 12 : }
129 :
130 24 : virtual ~LTIDLLCopy()
131 : {
132 24 : }
133 : };
134 :
135 : template <class T> class LTIDLLWriter : public T
136 : {
137 : public:
138 : explicit LTIDLLWriter(LTIImageStage *image) : T(image)
139 : {
140 : }
141 :
142 : virtual ~LTIDLLWriter()
143 : {
144 : }
145 : };
146 :
147 : template <class T> class LTIDLLDefault : public T
148 : {
149 : public:
150 : LTIDLLDefault() : T()
151 : {
152 : }
153 :
154 : virtual ~LTIDLLDefault()
155 : {
156 : }
157 : };
158 :
159 : /* -------------------------------------------------------------------- */
160 : /* Interface to MrSID SDK progress reporting. */
161 : /* -------------------------------------------------------------------- */
162 :
163 : class MrSIDProgress : public LTIProgressDelegate
164 : {
165 : public:
166 : MrSIDProgress(GDALProgressFunc f, void *arg) : m_f(f), m_arg(arg)
167 : {
168 : }
169 :
170 : virtual ~MrSIDProgress()
171 : {
172 : }
173 :
174 : LT_STATUS setProgressStatus(float fraction) override
175 : {
176 : if (!m_f)
177 : return LT_STS_BadContext;
178 : if (!m_f(fraction, nullptr, m_arg))
179 : return LT_STS_Failure;
180 : return LT_STS_Success;
181 : }
182 :
183 : private:
184 : GDALProgressFunc m_f;
185 : void *m_arg;
186 : };
187 :
188 : /************************************************************************/
189 : /* ==================================================================== */
190 : /* MrSIDDataset */
191 : /* ==================================================================== */
192 : /************************************************************************/
193 :
194 : class MrSIDDataset final : public GDALJP2AbstractDataset
195 : {
196 : friend class MrSIDRasterBand;
197 :
198 : LTIOStreamInf *poStream;
199 : LTIOFileStream oLTIStream;
200 : LTIVSIStream oVSIStream;
201 :
202 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
203 : LTIImageFilter *poImageReader;
204 : #else
205 : LTIImageReader *poImageReader;
206 : #endif
207 :
208 : #ifdef MRSID_ESDK
209 : LTIGeoFileImageWriter *poImageWriter;
210 : #endif
211 :
212 : LTIDLLNavigator<LTINavigator> *poLTINav;
213 : LTIDLLCopy<LTIMetadataDatabase> *poMetadata;
214 : const LTIPixel *poNDPixel;
215 :
216 : LTIDLLBuffer<LTISceneBuffer> *poBuffer;
217 : int nBlockXSize;
218 : int nBlockYSize;
219 : int bPrevBlockRead;
220 : int nPrevBlockXOff, nPrevBlockYOff;
221 :
222 : LTIDataType eSampleType;
223 : GDALDataType eDataType;
224 : LTIColorSpace eColorSpace;
225 :
226 : double dfCurrentMag;
227 :
228 : GTIFDefn *psDefn;
229 :
230 : MrSIDDataset *poParentDS;
231 : int bIsOverview;
232 : int nOverviewCount;
233 : MrSIDDataset **papoOverviewDS;
234 :
235 : CPLString osMETFilename;
236 :
237 : CPLErr OpenZoomLevel(lt_int32 iZoom);
238 : int GetMetadataElement(const char *, void *, int = 0);
239 : void FetchProjParams();
240 : void GetGTIFDefn();
241 : char *GetOGISDefn(GTIFDefn *);
242 :
243 : int m_nInRasterIO = 0; // Prevent infinite recursion in IRasterIO()
244 :
245 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
246 : GDALDataType, int, BANDMAP_TYPE, GSpacing nPixelSpace,
247 : GSpacing nLineSpace, GSpacing nBandSpace,
248 : GDALRasterIOExtraArg *psExtraArg) override;
249 :
250 : protected:
251 : int CloseDependentDatasets() override;
252 :
253 : CPLErr IBuildOverviews(const char *, int, const int *, int, const int *,
254 : GDALProgressFunc, void *,
255 : CSLConstList papszOptions) override;
256 :
257 : public:
258 : explicit MrSIDDataset(int bIsJPEG2000);
259 : ~MrSIDDataset() override;
260 :
261 : static GDALPamDataset *OpenPAM(GDALOpenInfo *poOpenInfo, int bIsJP2);
262 : static GDALDataset *Open(GDALOpenInfo *poOpenInfo, int bIsJP2);
263 :
264 : char **GetFileList() override;
265 :
266 : #ifdef MRSID_ESDK
267 : static GDALDataset *Create(const char *pszFilename, int nXSize, int nYSize,
268 : int nBands, GDALDataType eType,
269 : CSLConstList papszParamList);
270 : #endif
271 : };
272 :
273 : /************************************************************************/
274 : /* ==================================================================== */
275 : /* MrSIDRasterBand */
276 : /* ==================================================================== */
277 : /************************************************************************/
278 :
279 : class MrSIDRasterBand final : public GDALPamRasterBand
280 : {
281 : friend class MrSIDDataset;
282 :
283 : LTIPixel *poPixel;
284 :
285 : int nBlockSize;
286 :
287 : int bNoDataSet;
288 : double dfNoDataValue;
289 :
290 : MrSIDDataset *poGDS;
291 :
292 : GDALColorInterp eBandInterp;
293 :
294 : public:
295 : MrSIDRasterBand(MrSIDDataset *, int);
296 : ~MrSIDRasterBand() override;
297 :
298 : CPLErr IRasterIO(GDALRWFlag, int, int, int, int, void *, int, int,
299 : GDALDataType, GSpacing nPixelSpace, GSpacing nLineSpace,
300 : GDALRasterIOExtraArg *psExtraArg) override;
301 :
302 : CPLErr IReadBlock(int, int, void *) override;
303 : GDALColorInterp GetColorInterpretation() override;
304 : CPLErr SetColorInterpretation(GDALColorInterp eNewInterp) override;
305 : double GetNoDataValue(int *) override;
306 : int GetOverviewCount() override;
307 : GDALRasterBand *GetOverview(int) override;
308 :
309 : virtual CPLErr GetStatistics(int bApproxOK, int bForce, double *pdfMin,
310 : double *pdfMax, double *pdfMean,
311 : double *pdfStdDev) override;
312 :
313 : #ifdef MRSID_ESDK
314 : CPLErr IWriteBlock(int, int, void *) override;
315 : #endif
316 : };
317 :
318 : /************************************************************************/
319 : /* MrSIDRasterBand() */
320 : /************************************************************************/
321 :
322 62 : MrSIDRasterBand::MrSIDRasterBand(MrSIDDataset *poDSIn, int nBandIn)
323 : {
324 62 : this->poDS = poDSIn;
325 62 : poGDS = poDSIn;
326 62 : this->nBand = nBandIn;
327 62 : this->eDataType = poDSIn->eDataType;
328 :
329 : /* -------------------------------------------------------------------- */
330 : /* Set the block sizes and buffer parameters. */
331 : /* -------------------------------------------------------------------- */
332 62 : nBlockXSize = poDSIn->nBlockXSize;
333 62 : nBlockYSize = poDSIn->nBlockYSize;
334 : // #ifdef notdef
335 62 : if (poDS->GetRasterXSize() > 2048)
336 0 : nBlockXSize = 1024;
337 62 : if (poDS->GetRasterYSize() > 128)
338 36 : nBlockYSize = 128;
339 : else
340 26 : nBlockYSize = poDS->GetRasterYSize();
341 : // #endif
342 :
343 62 : nBlockSize = nBlockXSize * nBlockYSize;
344 62 : poPixel = new LTIDLLPixel<LTIPixel>(poDSIn->eColorSpace,
345 62 : static_cast<lt_uint16>(poDSIn->nBands),
346 62 : poDSIn->eSampleType);
347 :
348 : /* -------------------------------------------------------------------- */
349 : /* Set NoData values. */
350 : /* */
351 : /* This logic is disabled for now since the MrSID nodata */
352 : /* semantics are different than GDAL. In MrSID all bands must */
353 : /* match the nodata value for that band in order for the pixel */
354 : /* to be considered nodata, otherwise all values are valid. */
355 : /* -------------------------------------------------------------------- */
356 : #ifdef notdef
357 : if (poDS->poNDPixel)
358 : {
359 : switch (poDS->eSampleType)
360 : {
361 : case LTI_DATATYPE_UINT8:
362 : case LTI_DATATYPE_SINT8:
363 : dfNoDataValue =
364 : (double)poDS->poNDPixel->getSampleValueUint8(nBand - 1);
365 : break;
366 : case LTI_DATATYPE_UINT16:
367 : dfNoDataValue =
368 : (double)poDS->poNDPixel->getSampleValueUint16(nBand - 1);
369 : break;
370 : case LTI_DATATYPE_FLOAT32:
371 : dfNoDataValue =
372 : poDS->poNDPixel->getSampleValueFloat32(nBand - 1);
373 : break;
374 : case LTI_DATATYPE_SINT16:
375 : dfNoDataValue =
376 : (double)*(GInt16 *)poDS->poNDPixel->getSampleValueAddr(
377 : nBand - 1);
378 : break;
379 : case LTI_DATATYPE_UINT32:
380 : dfNoDataValue =
381 : (double)*(GUInt32 *)poDS->poNDPixel->getSampleValueAddr(
382 : nBand - 1);
383 : break;
384 : case LTI_DATATYPE_SINT32:
385 : dfNoDataValue =
386 : (double)*(GInt32 *)poDS->poNDPixel->getSampleValueAddr(
387 : nBand - 1);
388 : break;
389 : case LTI_DATATYPE_FLOAT64:
390 : dfNoDataValue =
391 : *(double *)poDS->poNDPixel->getSampleValueAddr(nBand - 1);
392 : break;
393 :
394 : case LTI_DATATYPE_INVALID:
395 : CPLAssert(false);
396 : break;
397 : }
398 : bNoDataSet = TRUE;
399 : }
400 : else
401 : #endif
402 : {
403 62 : dfNoDataValue = 0.0;
404 62 : bNoDataSet = FALSE;
405 : }
406 :
407 62 : switch (poGDS->eColorSpace)
408 : {
409 0 : case LTI_COLORSPACE_RGB:
410 0 : if (nBand == 1)
411 0 : eBandInterp = GCI_RedBand;
412 0 : else if (nBand == 2)
413 0 : eBandInterp = GCI_GreenBand;
414 0 : else if (nBand == 3)
415 0 : eBandInterp = GCI_BlueBand;
416 : else
417 0 : eBandInterp = GCI_Undefined;
418 0 : break;
419 :
420 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
421 0 : case LTI_COLORSPACE_RGBA:
422 0 : if (nBand == 1)
423 0 : eBandInterp = GCI_RedBand;
424 0 : else if (nBand == 2)
425 0 : eBandInterp = GCI_GreenBand;
426 0 : else if (nBand == 3)
427 0 : eBandInterp = GCI_BlueBand;
428 0 : else if (nBand == 4)
429 0 : eBandInterp = GCI_AlphaBand;
430 : else
431 0 : eBandInterp = GCI_Undefined;
432 0 : break;
433 : #endif
434 :
435 0 : case LTI_COLORSPACE_CMYK:
436 0 : if (nBand == 1)
437 0 : eBandInterp = GCI_CyanBand;
438 0 : else if (nBand == 2)
439 0 : eBandInterp = GCI_MagentaBand;
440 0 : else if (nBand == 3)
441 0 : eBandInterp = GCI_YellowBand;
442 0 : else if (nBand == 4)
443 0 : eBandInterp = GCI_BlackBand;
444 : else
445 0 : eBandInterp = GCI_Undefined;
446 0 : break;
447 :
448 62 : case LTI_COLORSPACE_GRAYSCALE:
449 62 : eBandInterp = GCI_GrayIndex;
450 62 : break;
451 :
452 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
453 0 : case LTI_COLORSPACE_GRAYSCALEA:
454 0 : if (nBand == 1)
455 0 : eBandInterp = GCI_GrayIndex;
456 0 : else if (nBand == 2)
457 0 : eBandInterp = GCI_AlphaBand;
458 : else
459 0 : eBandInterp = GCI_Undefined;
460 0 : break;
461 :
462 0 : case LTI_COLORSPACE_GRAYSCALEA_PM:
463 0 : if (nBand == 1)
464 0 : eBandInterp = GCI_GrayIndex;
465 0 : else if (nBand == 2)
466 0 : eBandInterp = GCI_AlphaBand;
467 : else
468 0 : eBandInterp = GCI_Undefined;
469 0 : break;
470 : #endif
471 :
472 0 : default:
473 0 : eBandInterp = GCI_Undefined;
474 0 : break;
475 : }
476 62 : }
477 :
478 : /************************************************************************/
479 : /* ~MrSIDRasterBand() */
480 : /************************************************************************/
481 :
482 124 : MrSIDRasterBand::~MrSIDRasterBand()
483 : {
484 62 : if (poPixel)
485 62 : delete poPixel;
486 124 : }
487 :
488 : /************************************************************************/
489 : /* IReadBlock() */
490 : /************************************************************************/
491 :
492 13 : CPLErr MrSIDRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
493 : {
494 : #ifdef MRSID_ESDK
495 : if (poGDS->eAccess == GA_Update)
496 : {
497 : CPLDebug("MrSID",
498 : "IReadBlock() - DSDK - read on updatable file fails.");
499 : memset(pImage, 0,
500 : static_cast<size_t>(nBlockSize) *
501 : GDALGetDataTypeSizeBytes(eDataType));
502 : return CE_None;
503 : }
504 : #endif /* MRSID_ESDK */
505 :
506 13 : CPLDebug("MrSID", "IReadBlock(%d,%d)", nBlockXOff, nBlockYOff);
507 :
508 13 : if (!poGDS->bPrevBlockRead || poGDS->nPrevBlockXOff != nBlockXOff ||
509 8 : poGDS->nPrevBlockYOff != nBlockYOff)
510 : {
511 13 : GInt32 nLine = nBlockYOff * nBlockYSize;
512 13 : GInt32 nCol = nBlockXOff * nBlockXSize;
513 :
514 : // XXX: The scene, passed to LTIImageStage::read() call must be
515 : // inside the image boundaries. So we should detect the last strip and
516 : // form the scene properly.
517 13 : CPLDebug("MrSID", "IReadBlock - read() %dx%d block at %d,%d.",
518 : nBlockXSize, nBlockYSize, nCol, nLine);
519 :
520 13 : if (!LT_SUCCESS(poGDS->poLTINav->setSceneAsULWH(
521 : nCol, nLine,
522 : (nCol + nBlockXSize > poGDS->GetRasterXSize())
523 : ? (poGDS->GetRasterXSize() - nCol)
524 : : nBlockXSize,
525 : (nLine + nBlockYSize > poGDS->GetRasterYSize())
526 : ? (poGDS->GetRasterYSize() - nLine)
527 : : nBlockYSize,
528 : poGDS->dfCurrentMag)))
529 : {
530 0 : CPLError(
531 : CE_Failure, CPLE_AppDefined,
532 : "MrSIDRasterBand::IReadBlock(): Failed to set scene position.");
533 0 : return CE_Failure;
534 : }
535 :
536 13 : if (!poGDS->poBuffer)
537 : {
538 5 : poGDS->poBuffer = new LTIDLLBuffer<LTISceneBuffer>(
539 5 : *poPixel, nBlockXSize, nBlockYSize, nullptr);
540 : // poGDS->poBuffer =
541 : // new LTISceneBuffer( *poPixel, nBlockXSize,
542 : // nBlockYSize, nullptr );
543 : }
544 :
545 13 : if (!LT_SUCCESS(poGDS->poImageReader->read(poGDS->poLTINav->getScene(),
546 : *poGDS->poBuffer)))
547 : {
548 0 : CPLError(CE_Failure, CPLE_AppDefined,
549 : "MrSIDRasterBand::IReadBlock(): Failed to load image.");
550 0 : return CE_Failure;
551 : }
552 :
553 13 : poGDS->bPrevBlockRead = TRUE;
554 13 : poGDS->nPrevBlockXOff = nBlockXOff;
555 13 : poGDS->nPrevBlockYOff = nBlockYOff;
556 : }
557 :
558 26 : memcpy(
559 : pImage,
560 26 : poGDS->poBuffer->myGetTotalBandData(static_cast<lt_uint16>(nBand - 1)),
561 13 : nBlockSize * GDALGetDataTypeSizeBytes(poGDS->eDataType));
562 :
563 13 : return CE_None;
564 : }
565 :
566 : #ifdef MRSID_ESDK
567 :
568 : /************************************************************************/
569 : /* IWriteBlock() */
570 : /************************************************************************/
571 :
572 : CPLErr MrSIDRasterBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
573 : void *pImage)
574 : {
575 : CPLAssert(poGDS != nullptr && nBlockXOff >= 0 && nBlockYOff >= 0 &&
576 : pImage != nullptr);
577 :
578 : #ifdef DEBUG
579 : CPLDebug("MrSID", "IWriteBlock(): nBlockXOff=%d, nBlockYOff=%d", nBlockXOff,
580 : nBlockYOff);
581 : #endif
582 :
583 : LTIScene oScene(nBlockXOff * nBlockXSize, nBlockYOff * nBlockYSize,
584 : nBlockXSize, nBlockYSize, 1.0);
585 : LTISceneBuffer oSceneBuf(*poPixel, poGDS->nBlockXSize, poGDS->nBlockYSize,
586 : &pImage);
587 :
588 : if (!LT_SUCCESS(poGDS->poImageWriter->writeBegin(oScene)))
589 : {
590 : CPLError(CE_Failure, CPLE_AppDefined,
591 : "MrSIDRasterBand::IWriteBlock(): writeBegin failed.");
592 : return CE_Failure;
593 : }
594 :
595 : if (!LT_SUCCESS(poGDS->poImageWriter->writeStrip(oSceneBuf, oScene)))
596 : {
597 : CPLError(CE_Failure, CPLE_AppDefined,
598 : "MrSIDRasterBand::IWriteBlock(): writeStrip failed.");
599 : return CE_Failure;
600 : }
601 :
602 : if (!LT_SUCCESS(poGDS->poImageWriter->writeEnd()))
603 : {
604 : CPLError(CE_Failure, CPLE_AppDefined,
605 : "MrSIDRasterBand::IWriteBlock(): writeEnd failed.");
606 : return CE_Failure;
607 : }
608 :
609 : return CE_None;
610 : }
611 :
612 : #endif /* MRSID_ESDK */
613 :
614 : /************************************************************************/
615 : /* IRasterIO() */
616 : /************************************************************************/
617 :
618 10 : CPLErr MrSIDRasterBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
619 : int nXSize, int nYSize, void *pData,
620 : int nBufXSize, int nBufYSize,
621 : GDALDataType eBufType, GSpacing nPixelSpace,
622 : GSpacing nLineSpace,
623 : GDALRasterIOExtraArg *psExtraArg)
624 :
625 : {
626 : /* -------------------------------------------------------------------- */
627 : /* Fallback to default implementation if the whole scanline */
628 : /* without subsampling requested. */
629 : /* -------------------------------------------------------------------- */
630 10 : if (nXSize == poGDS->GetRasterXSize() && nXSize == nBufXSize &&
631 : nYSize == nBufYSize)
632 : {
633 10 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
634 : pData, nBufXSize, nBufYSize, eBufType,
635 10 : nPixelSpace, nLineSpace, psExtraArg);
636 : }
637 :
638 : /* -------------------------------------------------------------------- */
639 : /* Handle via the dataset level IRasterIO() */
640 : /* -------------------------------------------------------------------- */
641 0 : return poGDS->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
642 : nBufXSize, nBufYSize, eBufType, 1, &nBand,
643 0 : nPixelSpace, nLineSpace, 0, psExtraArg);
644 : }
645 :
646 : /************************************************************************/
647 : /* GetColorInterpretation() */
648 : /************************************************************************/
649 :
650 0 : GDALColorInterp MrSIDRasterBand::GetColorInterpretation()
651 :
652 : {
653 0 : return eBandInterp;
654 : }
655 :
656 : /************************************************************************/
657 : /* SetColorInterpretation() */
658 : /* */
659 : /* This would normally just be used by folks using the MrSID code */
660 : /* to read JP2 streams in other formats (such as NITF) and */
661 : /* providing their own color interpretation regardless of what */
662 : /* MrSID might think the stream itself says. */
663 : /************************************************************************/
664 :
665 0 : CPLErr MrSIDRasterBand::SetColorInterpretation(GDALColorInterp eNewInterp)
666 :
667 : {
668 0 : eBandInterp = eNewInterp;
669 :
670 0 : return CE_None;
671 : }
672 :
673 : /************************************************************************/
674 : /* GetStatistics() */
675 : /* */
676 : /* We override this method so that we can force generation of */
677 : /* statistics if approx ok is true since we know that a small */
678 : /* overview is always available, and that computing statistics */
679 : /* from it is very fast. */
680 : /************************************************************************/
681 :
682 7 : CPLErr MrSIDRasterBand::GetStatistics(int bApproxOK, int bForce, double *pdfMin,
683 : double *pdfMax, double *pdfMean,
684 : double *pdfStdDev)
685 :
686 : {
687 7 : if (bApproxOK)
688 4 : bForce = TRUE;
689 :
690 7 : return GDALPamRasterBand::GetStatistics(bApproxOK, bForce, pdfMin, pdfMax,
691 7 : pdfMean, pdfStdDev);
692 : }
693 :
694 : /************************************************************************/
695 : /* GetNoDataValue() */
696 : /************************************************************************/
697 :
698 11 : double MrSIDRasterBand::GetNoDataValue(int *pbSuccess)
699 :
700 : {
701 11 : if (bNoDataSet)
702 : {
703 0 : if (pbSuccess)
704 0 : *pbSuccess = bNoDataSet;
705 :
706 0 : return dfNoDataValue;
707 : }
708 :
709 11 : return GDALPamRasterBand::GetNoDataValue(pbSuccess);
710 : }
711 :
712 : /************************************************************************/
713 : /* GetOverviewCount() */
714 : /************************************************************************/
715 :
716 14 : int MrSIDRasterBand::GetOverviewCount()
717 :
718 : {
719 14 : return poGDS->nOverviewCount;
720 : }
721 :
722 : /************************************************************************/
723 : /* GetOverview() */
724 : /************************************************************************/
725 :
726 10 : GDALRasterBand *MrSIDRasterBand::GetOverview(int i)
727 :
728 : {
729 10 : if (i < 0 || i >= poGDS->nOverviewCount)
730 0 : return nullptr;
731 : else
732 10 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
733 : }
734 :
735 : /************************************************************************/
736 : /* MrSIDDataset() */
737 : /************************************************************************/
738 :
739 62 : MrSIDDataset::MrSIDDataset(int bIsJPEG2000)
740 : : nBlockXSize(0), nBlockYSize(0), eSampleType(LTI_DATATYPE_UINT8),
741 62 : eDataType(GDT_UInt8), eColorSpace(LTI_COLORSPACE_INVALID)
742 : {
743 62 : poStream = nullptr;
744 62 : poImageReader = nullptr;
745 : #ifdef MRSID_ESDK
746 : poImageWriter = nullptr;
747 : #endif
748 62 : poLTINav = nullptr;
749 62 : poMetadata = nullptr;
750 62 : poNDPixel = nullptr;
751 62 : nBands = 0;
752 :
753 62 : poBuffer = nullptr;
754 62 : bPrevBlockRead = FALSE;
755 62 : nPrevBlockXOff = 0;
756 62 : nPrevBlockYOff = 0;
757 :
758 62 : psDefn = nullptr;
759 :
760 62 : dfCurrentMag = 1.0;
761 62 : bIsOverview = FALSE;
762 62 : poParentDS = this;
763 62 : nOverviewCount = 0;
764 62 : papoOverviewDS = nullptr;
765 :
766 62 : poDriver =
767 62 : (GDALDriver *)GDALGetDriverByName(bIsJPEG2000 ? "JP2MrSID" : "MrSID");
768 62 : }
769 :
770 : /************************************************************************/
771 : /* ~MrSIDDataset() */
772 : /************************************************************************/
773 :
774 124 : MrSIDDataset::~MrSIDDataset()
775 : {
776 62 : MrSIDDataset::FlushCache(true);
777 :
778 : #ifdef MRSID_ESDK
779 : if (poImageWriter)
780 : delete poImageWriter;
781 : #endif
782 :
783 62 : if (poBuffer)
784 5 : delete poBuffer;
785 62 : if (poMetadata)
786 12 : delete poMetadata;
787 62 : if (poLTINav)
788 62 : delete poLTINav;
789 62 : if (poImageReader && !bIsOverview)
790 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
791 : {
792 12 : poImageReader->release();
793 12 : poImageReader = nullptr;
794 : }
795 : #else
796 : delete poImageReader;
797 : #endif
798 : // points to another member, don't delete
799 62 : poStream = nullptr;
800 :
801 62 : if (psDefn)
802 12 : delete psDefn;
803 62 : MrSIDDataset::CloseDependentDatasets();
804 124 : }
805 :
806 : /************************************************************************/
807 : /* CloseDependentDatasets() */
808 : /************************************************************************/
809 :
810 64 : int MrSIDDataset::CloseDependentDatasets()
811 : {
812 64 : int bRet = GDALPamDataset::CloseDependentDatasets();
813 :
814 64 : if (papoOverviewDS)
815 : {
816 62 : for (int i = 0; i < nOverviewCount; i++)
817 50 : delete papoOverviewDS[i];
818 12 : CPLFree(papoOverviewDS);
819 12 : papoOverviewDS = nullptr;
820 12 : bRet = TRUE;
821 : }
822 64 : return bRet;
823 : }
824 :
825 : /************************************************************************/
826 : /* IRasterIO() */
827 : /************************************************************************/
828 :
829 1 : CPLErr MrSIDDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
830 : int nXSize, int nYSize, void *pData,
831 : int nBufXSize, int nBufYSize,
832 : GDALDataType eBufType, int nBandCount,
833 : BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
834 : GSpacing nLineSpace, GSpacing nBandSpace,
835 : GDALRasterIOExtraArg *psExtraArg)
836 :
837 : {
838 : /* -------------------------------------------------------------------- */
839 : /* We need various criteria to skip out to block based methods. */
840 : /* -------------------------------------------------------------------- */
841 1 : int bUseBlockedIO = bForceCachedIO;
842 :
843 1 : if (nYSize == 1 || nXSize * ((double)nYSize) < 100.0)
844 0 : bUseBlockedIO = TRUE;
845 :
846 1 : if (nBufYSize == 1 || nBufXSize * ((double)nBufYSize) < 100.0)
847 0 : bUseBlockedIO = TRUE;
848 :
849 1 : if (CPLTestBool(CPLGetConfigOption("GDAL_ONE_BIG_READ", "NO")))
850 0 : bUseBlockedIO = FALSE;
851 :
852 1 : if (bUseBlockedIO && !m_nInRasterIO)
853 : {
854 0 : ++m_nInRasterIO;
855 0 : const CPLErr eErr = GDALDataset::BlockBasedRasterIO(
856 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
857 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
858 : nBandSpace, psExtraArg);
859 0 : --m_nInRasterIO;
860 0 : return eErr;
861 : }
862 :
863 1 : CPLDebug("MrSID", "RasterIO() - using optimized dataset level IO.");
864 :
865 : /* -------------------------------------------------------------------- */
866 : /* What is our requested window relative to the base dataset. */
867 : /* We want to operate from here on as if we were operating on */
868 : /* the full res band. */
869 : /* -------------------------------------------------------------------- */
870 1 : int nZoomMag = (int)((1 / dfCurrentMag) * 1.0000001);
871 :
872 1 : nXOff *= nZoomMag;
873 1 : nYOff *= nZoomMag;
874 1 : nXSize *= nZoomMag;
875 1 : nYSize *= nZoomMag;
876 :
877 : /* -------------------------------------------------------------------- */
878 : /* We need to figure out the best zoom level to use for this */
879 : /* request. We apply a small fudge factor to make sure that */
880 : /* request just very, very slightly larger than a zoom level do */
881 : /* not force us to the next level. */
882 : /* -------------------------------------------------------------------- */
883 1 : int iOverview = 0;
884 : double dfZoomMag =
885 1 : std::min((nXSize / (double)nBufXSize), (nYSize / (double)nBufYSize));
886 :
887 5 : for (nZoomMag = 1; nZoomMag * 2 < (dfZoomMag + 0.1) &&
888 5 : iOverview < poParentDS->nOverviewCount;
889 4 : nZoomMag *= 2, iOverview++)
890 : {
891 : }
892 :
893 : /* -------------------------------------------------------------------- */
894 : /* Work out the size of the temporary buffer and allocate it. */
895 : /* The temporary buffer will generally be at a moderately */
896 : /* higher resolution than the buffer of data requested. */
897 : /* -------------------------------------------------------------------- */
898 : int nTmpPixelSize;
899 2 : LTIPixel oPixel(eColorSpace, static_cast<lt_uint16>(nBands), eSampleType);
900 :
901 : LT_STATUS eLTStatus;
902 : unsigned int maxWidth;
903 : unsigned int maxHeight;
904 :
905 : eLTStatus =
906 1 : poImageReader->getDimsAtMag(1.0 / nZoomMag, maxWidth, maxHeight);
907 :
908 1 : if (!LT_SUCCESS(eLTStatus))
909 : {
910 0 : CPLError(CE_Failure, CPLE_AppDefined,
911 : "MrSIDDataset::IRasterIO(): Failed to get zoomed image "
912 : "dimensions.\n%s",
913 : getLastStatusString(eLTStatus));
914 0 : return CE_Failure;
915 : }
916 :
917 : int maxWidthAtL0 =
918 1 : bIsOverview ? poParentDS->GetRasterXSize() : this->GetRasterXSize();
919 : int maxHeightAtL0 =
920 1 : bIsOverview ? poParentDS->GetRasterYSize() : this->GetRasterYSize();
921 :
922 1 : int sceneUlXOff = nXOff / nZoomMag;
923 1 : int sceneUlYOff = nYOff / nZoomMag;
924 1 : int sceneWidth =
925 1 : (int)(nXSize * (double)maxWidth / (double)maxWidthAtL0 + 0.99);
926 1 : int sceneHeight =
927 1 : (int)(nYSize * (double)maxHeight / (double)maxHeightAtL0 + 0.99);
928 :
929 1 : if ((sceneUlXOff + sceneWidth) > (int)maxWidth)
930 0 : sceneWidth = maxWidth - sceneUlXOff;
931 :
932 1 : if ((sceneUlYOff + sceneHeight) > (int)maxHeight)
933 0 : sceneHeight = maxHeight - sceneUlYOff;
934 :
935 2 : LTISceneBuffer oLTIBuffer(oPixel, sceneWidth, sceneHeight, nullptr);
936 :
937 1 : nTmpPixelSize = GDALGetDataTypeSizeBytes(eDataType);
938 :
939 : /* -------------------------------------------------------------------- */
940 : /* Create navigator, and move to the requested scene area. */
941 : /* -------------------------------------------------------------------- */
942 2 : LTINavigator oNav(*poImageReader);
943 :
944 1 : if (!LT_SUCCESS(oNav.setSceneAsULWH(sceneUlXOff, sceneUlYOff, sceneWidth,
945 : sceneHeight, 1.0 / nZoomMag)))
946 : {
947 0 : CPLError(CE_Failure, CPLE_AppDefined,
948 : "MrSIDDataset::IRasterIO(): Failed to set scene position.");
949 :
950 0 : return CE_Failure;
951 : }
952 :
953 1 : CPLDebug("MrSID",
954 : "Dataset:IRasterIO(%d,%d %dx%d -> %dx%d -> %dx%d, zoom=%d)", nXOff,
955 : nYOff, nXSize, nYSize, sceneWidth, sceneHeight, nBufXSize,
956 : nBufYSize, nZoomMag);
957 :
958 1 : if (!oNav.isSceneValid())
959 0 : CPLDebug("MrSID", "LTINavigator in invalid state.");
960 :
961 : /* -------------------------------------------------------------------- */
962 : /* Read into the buffer. */
963 : /* -------------------------------------------------------------------- */
964 :
965 1 : eLTStatus = poImageReader->read(oNav.getScene(), oLTIBuffer);
966 1 : if (!LT_SUCCESS(eLTStatus))
967 : {
968 0 : CPLError(CE_Failure, CPLE_AppDefined,
969 : "MrSIDRasterBand::IRasterIO(): Failed to load image.\n%s",
970 : getLastStatusString(eLTStatus));
971 0 : return CE_Failure;
972 : }
973 :
974 : /* -------------------------------------------------------------------- */
975 : /* If we are pulling the data at a matching resolution, try to */
976 : /* do a more direct copy without subsampling. */
977 : /* -------------------------------------------------------------------- */
978 : int iBufLine, iBufPixel;
979 :
980 1 : if (nBufXSize == sceneWidth && nBufYSize == sceneHeight)
981 : {
982 0 : for (int iBand = 0; iBand < nBandCount; iBand++)
983 : {
984 0 : GByte *pabySrcBand = (GByte *)oLTIBuffer.myGetTotalBandData(
985 0 : static_cast<lt_uint16>(panBandMap[iBand] - 1));
986 :
987 0 : for (int iLine = 0; iLine < nBufYSize; iLine++)
988 : {
989 0 : GDALCopyWords(
990 0 : pabySrcBand + iLine * nTmpPixelSize * sceneWidth, eDataType,
991 : nTmpPixelSize,
992 0 : ((GByte *)pData) + iLine * nLineSpace + iBand * nBandSpace,
993 : eBufType, static_cast<int>(nPixelSpace), nBufXSize);
994 : }
995 0 : }
996 : }
997 :
998 : /* -------------------------------------------------------------------- */
999 : /* Manually resample to our target buffer. */
1000 : /* -------------------------------------------------------------------- */
1001 : else
1002 : {
1003 11 : for (iBufLine = 0; iBufLine < nBufYSize; iBufLine++)
1004 : {
1005 10 : int iTmpLine =
1006 10 : (int)floor(((iBufLine + 0.5) / nBufYSize) * sceneHeight);
1007 :
1008 110 : for (iBufPixel = 0; iBufPixel < nBufXSize; iBufPixel++)
1009 : {
1010 100 : int iTmpPixel =
1011 100 : (int)floor(((iBufPixel + 0.5) / nBufXSize) * sceneWidth);
1012 :
1013 200 : for (int iBand = 0; iBand < nBandCount; iBand++)
1014 : {
1015 : GByte *pabySrc, *pabyDst;
1016 :
1017 100 : pabyDst = ((GByte *)pData) + nPixelSpace * iBufPixel +
1018 100 : nLineSpace * iBufLine + nBandSpace * iBand;
1019 :
1020 200 : pabySrc = (GByte *)oLTIBuffer.myGetTotalBandData(
1021 100 : static_cast<lt_uint16>(panBandMap[iBand] - 1));
1022 100 : pabySrc +=
1023 100 : (iTmpLine * sceneWidth + iTmpPixel) * nTmpPixelSize;
1024 :
1025 100 : if (eDataType == eBufType)
1026 100 : memcpy(pabyDst, pabySrc, nTmpPixelSize);
1027 : else
1028 0 : GDALCopyWords(pabySrc, eDataType, 0, pabyDst, eBufType,
1029 : 0, 1);
1030 : }
1031 : }
1032 : }
1033 : }
1034 :
1035 1 : return CE_None;
1036 : }
1037 :
1038 : /************************************************************************/
1039 : /* IBuildOverviews() */
1040 : /************************************************************************/
1041 :
1042 0 : CPLErr MrSIDDataset::IBuildOverviews(const char *, int, const int *, int,
1043 : const int *, GDALProgressFunc, void *,
1044 : CSLConstList)
1045 : {
1046 0 : CPLError(CE_Warning, CPLE_AppDefined,
1047 : "MrSID overviews are built-in, so building external "
1048 : "overviews is unnecessary. Ignoring.");
1049 :
1050 0 : return CE_None;
1051 : }
1052 :
1053 : /************************************************************************/
1054 : /* SerializeMetadataRec() */
1055 : /************************************************************************/
1056 :
1057 372 : static CPLString SerializeMetadataRec(const LTIMetadataRecord *poMetadataRec)
1058 : {
1059 372 : GUInt32 iNumDims = 0;
1060 372 : const GUInt32 *paiDims = nullptr;
1061 372 : const void *pData = poMetadataRec->getArrayData(iNumDims, paiDims);
1062 744 : CPLString osMetadata;
1063 372 : GUInt32 k = 0;
1064 :
1065 744 : for (GUInt32 i = 0; paiDims != nullptr && i < iNumDims; i++)
1066 : {
1067 : // stops on large binary data
1068 372 : if (poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_UINT8 &&
1069 0 : paiDims[i] > 1024)
1070 0 : return CPLString();
1071 :
1072 964 : for (GUInt32 j = 0; j < paiDims[i]; j++)
1073 : {
1074 1184 : CPLString osTemp;
1075 :
1076 592 : switch (poMetadataRec->getDataType())
1077 : {
1078 0 : case LTI_METADATA_DATATYPE_UINT8:
1079 : case LTI_METADATA_DATATYPE_SINT8:
1080 0 : osTemp.Printf("%d", ((GByte *)pData)[k++]);
1081 0 : break;
1082 110 : case LTI_METADATA_DATATYPE_UINT16:
1083 110 : osTemp.Printf("%u", ((GUInt16 *)pData)[k++]);
1084 110 : break;
1085 0 : case LTI_METADATA_DATATYPE_SINT16:
1086 0 : osTemp.Printf("%d", ((GInt16 *)pData)[k++]);
1087 0 : break;
1088 20 : case LTI_METADATA_DATATYPE_UINT32:
1089 20 : osTemp.Printf("%u", ((GUInt32 *)pData)[k++]);
1090 20 : break;
1091 30 : case LTI_METADATA_DATATYPE_SINT32:
1092 30 : osTemp.Printf("%d", ((GInt32 *)pData)[k++]);
1093 30 : break;
1094 30 : case LTI_METADATA_DATATYPE_FLOAT32:
1095 30 : osTemp.Printf("%f", ((float *)pData)[k++]);
1096 30 : break;
1097 282 : case LTI_METADATA_DATATYPE_FLOAT64:
1098 282 : osTemp.Printf("%f", ((double *)pData)[k++]);
1099 282 : break;
1100 120 : case LTI_METADATA_DATATYPE_ASCII:
1101 120 : osTemp = ((const char **)pData)[k++];
1102 120 : break;
1103 0 : default:
1104 0 : break;
1105 : }
1106 :
1107 592 : if (!osMetadata.empty())
1108 220 : osMetadata += ',';
1109 592 : osMetadata += osTemp;
1110 : }
1111 : }
1112 :
1113 372 : return osMetadata;
1114 : }
1115 :
1116 : /************************************************************************/
1117 : /* GetMetadataElement() */
1118 : /************************************************************************/
1119 :
1120 288 : int MrSIDDataset::GetMetadataElement(const char *pszKey, void *pValue,
1121 : int iLength)
1122 : {
1123 288 : if (!poMetadata->has(pszKey))
1124 168 : return FALSE;
1125 :
1126 120 : const LTIMetadataRecord *poMetadataRec = nullptr;
1127 120 : poMetadata->get(pszKey, poMetadataRec);
1128 :
1129 120 : if (poMetadataRec == nullptr || !poMetadataRec->isScalar())
1130 40 : return FALSE;
1131 :
1132 : // XXX: return FALSE if we have more than one element in metadata record
1133 : int iSize;
1134 80 : switch (poMetadataRec->getDataType())
1135 : {
1136 0 : case LTI_METADATA_DATATYPE_UINT8:
1137 : case LTI_METADATA_DATATYPE_SINT8:
1138 0 : iSize = 1;
1139 0 : break;
1140 70 : case LTI_METADATA_DATATYPE_UINT16:
1141 : case LTI_METADATA_DATATYPE_SINT16:
1142 70 : iSize = 2;
1143 70 : break;
1144 0 : case LTI_METADATA_DATATYPE_UINT32:
1145 : case LTI_METADATA_DATATYPE_SINT32:
1146 : case LTI_METADATA_DATATYPE_FLOAT32:
1147 0 : iSize = 4;
1148 0 : break;
1149 0 : case LTI_METADATA_DATATYPE_FLOAT64:
1150 0 : iSize = 8;
1151 0 : break;
1152 10 : case LTI_METADATA_DATATYPE_ASCII:
1153 10 : iSize = iLength;
1154 10 : break;
1155 0 : default:
1156 0 : iSize = 0;
1157 0 : break;
1158 : }
1159 :
1160 80 : if (poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_ASCII)
1161 : {
1162 20 : strncpy((char *)pValue,
1163 10 : ((const char **)poMetadataRec->getScalarData())[0], iSize);
1164 10 : ((char *)pValue)[iSize - 1] = '\0';
1165 : }
1166 : else
1167 70 : memcpy(pValue, poMetadataRec->getScalarData(), iSize);
1168 :
1169 80 : return TRUE;
1170 : }
1171 :
1172 : /************************************************************************/
1173 : /* GetFileList() */
1174 : /************************************************************************/
1175 :
1176 3 : char **MrSIDDataset::GetFileList()
1177 : {
1178 3 : char **papszFileList = GDALPamDataset::GetFileList();
1179 :
1180 3 : if (!osMETFilename.empty())
1181 0 : papszFileList = CSLAddString(papszFileList, osMETFilename.c_str());
1182 :
1183 3 : return papszFileList;
1184 : }
1185 :
1186 : /************************************************************************/
1187 : /* OpenZoomLevel() */
1188 : /************************************************************************/
1189 :
1190 62 : CPLErr MrSIDDataset::OpenZoomLevel(lt_int32 iZoom)
1191 : {
1192 : /* -------------------------------------------------------------------- */
1193 : /* Get image geometry. */
1194 : /* -------------------------------------------------------------------- */
1195 62 : if (iZoom != 0)
1196 : {
1197 : lt_uint32 iWidth, iHeight;
1198 50 : dfCurrentMag = LTIUtils::levelToMag(iZoom);
1199 : auto eLTStatus =
1200 50 : poImageReader->getDimsAtMag(dfCurrentMag, iWidth, iHeight);
1201 50 : if (!LT_SUCCESS(eLTStatus))
1202 : {
1203 0 : CPLDebug("MrSID", "Cannot open zoom level %d", iZoom);
1204 0 : return CE_Failure;
1205 : }
1206 50 : nRasterXSize = iWidth;
1207 50 : nRasterYSize = iHeight;
1208 : }
1209 : else
1210 : {
1211 12 : dfCurrentMag = 1.0;
1212 12 : nRasterXSize = poImageReader->getWidth();
1213 12 : nRasterYSize = poImageReader->getHeight();
1214 : }
1215 :
1216 62 : nBands = poImageReader->getNumBands();
1217 62 : nBlockXSize = nRasterXSize;
1218 62 : nBlockYSize = poImageReader->getStripHeight();
1219 :
1220 62 : CPLDebug("MrSID", "Opened zoom level %d with size %dx%d.", iZoom,
1221 : nRasterXSize, nRasterYSize);
1222 :
1223 : try
1224 : {
1225 62 : poLTINav = new LTIDLLNavigator<LTINavigator>(*poImageReader);
1226 : }
1227 0 : catch (...)
1228 : {
1229 0 : CPLError(CE_Failure, CPLE_AppDefined,
1230 : "MrSIDDataset::OpenZoomLevel(): "
1231 : "Failed to create LTINavigator object.");
1232 0 : return CE_Failure;
1233 : }
1234 :
1235 : /* -------------------------------------------------------------------- */
1236 : /* Handle sample type and color space. */
1237 : /* -------------------------------------------------------------------- */
1238 62 : eColorSpace = poImageReader->getColorSpace();
1239 62 : eSampleType = poImageReader->getDataType();
1240 62 : switch (eSampleType)
1241 : {
1242 0 : case LTI_DATATYPE_UINT16:
1243 0 : eDataType = GDT_UInt16;
1244 0 : break;
1245 0 : case LTI_DATATYPE_SINT16:
1246 0 : eDataType = GDT_Int16;
1247 0 : break;
1248 0 : case LTI_DATATYPE_UINT32:
1249 0 : eDataType = GDT_UInt32;
1250 0 : break;
1251 0 : case LTI_DATATYPE_SINT32:
1252 0 : eDataType = GDT_Int32;
1253 0 : break;
1254 0 : case LTI_DATATYPE_FLOAT32:
1255 0 : eDataType = GDT_Float32;
1256 0 : break;
1257 0 : case LTI_DATATYPE_FLOAT64:
1258 0 : eDataType = GDT_Float64;
1259 0 : break;
1260 62 : case LTI_DATATYPE_UINT8:
1261 : case LTI_DATATYPE_SINT8:
1262 : default:
1263 62 : eDataType = GDT_UInt8;
1264 62 : break;
1265 : }
1266 :
1267 : /* -------------------------------------------------------------------- */
1268 : /* Read georeferencing. */
1269 : /* -------------------------------------------------------------------- */
1270 62 : if (!poImageReader->isGeoCoordImplicit())
1271 : {
1272 62 : const LTIGeoCoord &oGeo = poImageReader->getGeoCoord();
1273 62 : oGeo.get(m_gt.xorig, m_gt.yorig, m_gt.xscale, m_gt.yscale, m_gt.xrot,
1274 62 : m_gt.yrot);
1275 :
1276 62 : m_gt.xorig = m_gt.xorig - m_gt.xscale / 2;
1277 62 : m_gt.yorig = m_gt.yorig - m_gt.yscale / 2;
1278 62 : bGeoTransformValid = TRUE;
1279 : }
1280 0 : else if (iZoom == 0)
1281 : {
1282 0 : bGeoTransformValid =
1283 0 : GDALReadWorldFile(GetDescription(), nullptr, m_gt.data()) ||
1284 0 : GDALReadWorldFile(GetDescription(), ".wld", m_gt.data());
1285 : }
1286 :
1287 : /* -------------------------------------------------------------------- */
1288 : /* Read wkt. */
1289 : /* -------------------------------------------------------------------- */
1290 : #ifdef MRSID_HAVE_GETWKT
1291 62 : if (!poImageReader->isGeoCoordImplicit())
1292 : {
1293 62 : const LTIGeoCoord &oGeo = poImageReader->getGeoCoord();
1294 :
1295 62 : if (oGeo.getWKT())
1296 : {
1297 : /* Workaround probable issue with GeoDSK 7 on 64bit Linux */
1298 114 : if (!(m_oSRS.IsEmpty() && !m_oSRS.IsLocal() &&
1299 52 : STARTS_WITH_CI(oGeo.getWKT(), "LOCAL_CS")))
1300 : {
1301 62 : m_oSRS.importFromWkt(oGeo.getWKT());
1302 : }
1303 : }
1304 : }
1305 : #endif // HAVE_MRSID_GETWKT
1306 :
1307 : /* -------------------------------------------------------------------- */
1308 : /* Special case for https://zulu.ssc.nasa.gov/mrsid/mrsid.pl */
1309 : /* where LandSat .SID are accompanied by a .met file with the */
1310 : /* projection */
1311 : /* -------------------------------------------------------------------- */
1312 62 : if (iZoom == 0 && m_oSRS.IsEmpty() &&
1313 62 : EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "sid"))
1314 : {
1315 : const std::string l_osMETFilename =
1316 0 : CPLResetExtensionSafe(GetDescription(), "met");
1317 0 : VSILFILE *fp = VSIFOpenL(l_osMETFilename.c_str(), "rb");
1318 0 : if (fp)
1319 : {
1320 0 : const char *pszLine = nullptr;
1321 0 : int nCountLine = 0;
1322 0 : int nUTMZone = 0;
1323 0 : int bWGS84 = FALSE;
1324 0 : int bUnitsMeter = FALSE;
1325 0 : while ((pszLine = CPLReadLine2L(fp, 200, nullptr)) != nullptr &&
1326 : nCountLine < 1000)
1327 : {
1328 0 : ++nCountLine;
1329 0 : if (nCountLine == 1 && strcmp(pszLine, "::MetadataFile") != 0)
1330 0 : break;
1331 0 : if (STARTS_WITH_CI(pszLine, "Projection UTM "))
1332 0 : nUTMZone = atoi(pszLine + 15);
1333 0 : else if (EQUAL(pszLine, "Datum WGS84"))
1334 0 : bWGS84 = TRUE;
1335 0 : else if (EQUAL(pszLine, "Units Meters"))
1336 0 : bUnitsMeter = TRUE;
1337 : }
1338 0 : VSIFCloseL(fp);
1339 :
1340 : /* Images in southern hemisphere have negative northings in the */
1341 : /* .sdw file. A bit weird, but anyway we must use the northern */
1342 : /* UTM SRS for consistency */
1343 0 : if (nUTMZone >= 1 && nUTMZone <= 60 && bWGS84 && bUnitsMeter)
1344 : {
1345 0 : osMETFilename = l_osMETFilename;
1346 :
1347 0 : m_oSRS.importFromEPSG(32600 + nUTMZone);
1348 0 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1349 : }
1350 : }
1351 : }
1352 :
1353 : /* -------------------------------------------------------------------- */
1354 : /* Read NoData value. */
1355 : /* -------------------------------------------------------------------- */
1356 62 : poNDPixel = poImageReader->getNoDataPixel();
1357 :
1358 : /* -------------------------------------------------------------------- */
1359 : /* Create band information objects. */
1360 : /* -------------------------------------------------------------------- */
1361 : int iBand;
1362 :
1363 124 : for (iBand = 1; iBand <= nBands; iBand++)
1364 62 : SetBand(iBand, new MrSIDRasterBand(this, iBand));
1365 :
1366 62 : return CE_None;
1367 : }
1368 :
1369 : /************************************************************************/
1370 : /* MrSIDOpen() */
1371 : /* */
1372 : /* Open method that only supports MrSID files. */
1373 : /************************************************************************/
1374 :
1375 12 : static GDALDataset *MrSIDOpen(GDALOpenInfo *poOpenInfo)
1376 : {
1377 12 : if (!MrSIDIdentify(poOpenInfo))
1378 0 : return nullptr;
1379 :
1380 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
1381 : lt_uint8 gen;
1382 : bool raster;
1383 24 : LT_STATUS eStat = MrSIDImageReaderInterface::getMrSIDGeneration(
1384 12 : poOpenInfo->pabyHeader, gen, raster);
1385 12 : if (!LT_SUCCESS(eStat) || !raster)
1386 0 : return nullptr;
1387 : #endif
1388 :
1389 12 : return MrSIDDataset::Open(poOpenInfo, FALSE);
1390 : }
1391 :
1392 : #ifdef MRSID_J2K
1393 :
1394 : /************************************************************************/
1395 : /* JP2Open() */
1396 : /* */
1397 : /* Open method that only supports JPEG2000 files. */
1398 : /************************************************************************/
1399 :
1400 : static GDALDataset *JP2Open(GDALOpenInfo *poOpenInfo)
1401 : {
1402 : if (!MrSIDJP2Identify(poOpenInfo))
1403 : return nullptr;
1404 :
1405 : return MrSIDDataset::Open(poOpenInfo, TRUE);
1406 : }
1407 :
1408 : #endif // MRSID_J2K
1409 :
1410 : /************************************************************************/
1411 : /* Open() */
1412 : /************************************************************************/
1413 :
1414 12 : GDALDataset *MrSIDDataset::Open(GDALOpenInfo *poOpenInfo, int bIsJP2)
1415 : {
1416 12 : return OpenPAM(poOpenInfo, bIsJP2);
1417 : }
1418 :
1419 12 : GDALPamDataset *MrSIDDataset::OpenPAM(GDALOpenInfo *poOpenInfo, int bIsJP2)
1420 : {
1421 12 : if (poOpenInfo->fpL)
1422 : {
1423 12 : VSIFCloseL(poOpenInfo->fpL);
1424 12 : poOpenInfo->fpL = nullptr;
1425 : }
1426 :
1427 : /* -------------------------------------------------------------------- */
1428 : /* Make sure we have hooked CSV lookup for GDAL_DATA. */
1429 : /* -------------------------------------------------------------------- */
1430 12 : LibgeotiffOneTimeInit();
1431 :
1432 : /* -------------------------------------------------------------------- */
1433 : /* Create a corresponding GDALDataset. */
1434 : /* -------------------------------------------------------------------- */
1435 : LT_STATUS eStat;
1436 :
1437 12 : MrSIDDataset *poDS = new MrSIDDataset(bIsJP2);
1438 :
1439 : // try the LTIOFileStream first, since it uses filesystem caching
1440 12 : eStat = poDS->oLTIStream.initialize(poOpenInfo->pszFilename, "rb");
1441 12 : if (LT_SUCCESS(eStat))
1442 : {
1443 12 : eStat = poDS->oLTIStream.open();
1444 12 : if (LT_SUCCESS(eStat))
1445 9 : poDS->poStream = &(poDS->oLTIStream);
1446 : }
1447 :
1448 : // fall back on VSI for non-files
1449 12 : if (!LT_SUCCESS(eStat) || !poDS->poStream)
1450 : {
1451 3 : eStat = poDS->oVSIStream.initialize(poOpenInfo->pszFilename, "rb");
1452 3 : if (!LT_SUCCESS(eStat))
1453 : {
1454 0 : CPLError(CE_Failure, CPLE_AppDefined,
1455 : "LTIVSIStream::initialize(): "
1456 : "failed to open file \"%s\".\n%s",
1457 : poOpenInfo->pszFilename, getLastStatusString(eStat));
1458 0 : delete poDS;
1459 0 : return nullptr;
1460 : }
1461 :
1462 3 : eStat = poDS->oVSIStream.open();
1463 3 : if (!LT_SUCCESS(eStat))
1464 : {
1465 0 : CPLError(CE_Failure, CPLE_AppDefined,
1466 : "LTIVSIStream::open(): "
1467 : "failed to open file \"%s\".\n%s",
1468 : poOpenInfo->pszFilename, getLastStatusString(eStat));
1469 0 : delete poDS;
1470 0 : return nullptr;
1471 : }
1472 :
1473 3 : poDS->poStream = &(poDS->oVSIStream);
1474 : }
1475 :
1476 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
1477 :
1478 : #ifdef MRSID_J2K
1479 : if (bIsJP2)
1480 : {
1481 : J2KImageReader *reader = J2KImageReader::create();
1482 : eStat = reader->initialize(*(poDS->poStream));
1483 : poDS->poImageReader = reader;
1484 : }
1485 : else
1486 : #endif /* MRSID_J2K */
1487 : {
1488 12 : MrSIDImageReader *reader = MrSIDImageReader::create();
1489 12 : eStat = reader->initialize(poDS->poStream, nullptr);
1490 12 : poDS->poImageReader = reader;
1491 : }
1492 :
1493 : #else /* LTI_SDK_MAJOR < 7 */
1494 :
1495 : #ifdef MRSID_J2K
1496 : if (bIsJP2)
1497 : {
1498 : poDS->poImageReader =
1499 : new LTIDLLReader<J2KImageReader>(*(poDS->poStream), true);
1500 : eStat = poDS->poImageReader->initialize();
1501 : }
1502 : else
1503 : #endif /* MRSID_J2K */
1504 : {
1505 : poDS->poImageReader =
1506 : new LTIDLLReader<MrSIDImageReader>(poDS->poStream, nullptr);
1507 : eStat = poDS->poImageReader->initialize();
1508 : }
1509 :
1510 : #endif /* LTI_SDK_MAJOR >= 7 */
1511 :
1512 12 : if (!LT_SUCCESS(eStat))
1513 : {
1514 0 : CPLError(CE_Failure, CPLE_AppDefined,
1515 : "LTIImageReader::initialize(): "
1516 : "failed to initialize reader from the stream \"%s\".\n%s",
1517 : poOpenInfo->pszFilename, getLastStatusString(eStat));
1518 0 : delete poDS;
1519 0 : return nullptr;
1520 : }
1521 :
1522 : /* -------------------------------------------------------------------- */
1523 : /* Read metadata. */
1524 : /* -------------------------------------------------------------------- */
1525 12 : poDS->poMetadata =
1526 12 : new LTIDLLCopy<LTIMetadataDatabase>(poDS->poImageReader->getMetadata());
1527 12 : const GUInt32 iNumRecs = poDS->poMetadata->getIndexCount();
1528 :
1529 384 : for (GUInt32 i = 0; i < iNumRecs; i++)
1530 : {
1531 372 : const LTIMetadataRecord *poMetadataRec = nullptr;
1532 372 : if (LT_SUCCESS(poDS->poMetadata->getDataByIndex(i, poMetadataRec)))
1533 : {
1534 744 : const auto osElement = SerializeMetadataRec(poMetadataRec);
1535 372 : char *pszKey = CPLStrdup(poMetadataRec->getTagName());
1536 372 : char *pszTemp = pszKey;
1537 :
1538 : // GDAL metadata keys should not contain ':' and '=' characters.
1539 : // We will replace them with '_'.
1540 11612 : do
1541 : {
1542 11984 : if (*pszTemp == ':' || *pszTemp == '=')
1543 1044 : *pszTemp = '_';
1544 11984 : } while (*++pszTemp);
1545 :
1546 372 : poDS->SetMetadataItem(pszKey, osElement.c_str());
1547 :
1548 372 : CPLFree(pszKey);
1549 : }
1550 : }
1551 :
1552 : /* -------------------------------------------------------------------- */
1553 : /* Add MrSID version. */
1554 : /* -------------------------------------------------------------------- */
1555 : #ifdef MRSID_J2K
1556 : if (!bIsJP2)
1557 : #endif
1558 : {
1559 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
1560 : lt_uint8 gen;
1561 : bool raster;
1562 12 : MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader,
1563 : gen, raster);
1564 12 : poDS->SetMetadataItem(
1565 : "VERSION",
1566 24 : CPLString().Printf("MG%d%s", gen, raster ? "" : " LiDAR"));
1567 : #else
1568 : lt_uint8 major;
1569 : lt_uint8 minor;
1570 : char letter;
1571 : MrSIDImageReader *poMrSIDImageReader =
1572 : static_cast<MrSIDImageReader *>(poDS->poImageReader);
1573 : poMrSIDImageReader->getVersion(major, minor, minor, letter);
1574 : if (major < 2)
1575 : major = 2;
1576 : poDS->SetMetadataItem("VERSION", CPLString().Printf("MG%d", major));
1577 : #endif
1578 : }
1579 :
1580 12 : poDS->GetGTIFDefn();
1581 :
1582 : /* -------------------------------------------------------------------- */
1583 : /* Get number of resolution levels (we will use them as overviews).*/
1584 : /* -------------------------------------------------------------------- */
1585 : #ifdef MRSID_J2K
1586 : if (bIsJP2)
1587 : poDS->nOverviewCount =
1588 : static_cast<J2KImageReader *>(poDS->poImageReader)->getNumLevels();
1589 : else
1590 : #endif
1591 12 : poDS->nOverviewCount =
1592 12 : static_cast<MrSIDImageReader *>(poDS->poImageReader)
1593 12 : ->getNumLevels();
1594 :
1595 12 : if (poDS->nOverviewCount > 0)
1596 : {
1597 : lt_int32 i;
1598 :
1599 12 : poDS->papoOverviewDS =
1600 12 : (MrSIDDataset **)CPLMalloc(poDS->nOverviewCount * (sizeof(void *)));
1601 :
1602 62 : for (i = 0; i < poDS->nOverviewCount; i++)
1603 : {
1604 50 : poDS->papoOverviewDS[i] = new MrSIDDataset(bIsJP2);
1605 50 : poDS->papoOverviewDS[i]->poImageReader = poDS->poImageReader;
1606 50 : poDS->papoOverviewDS[i]->bIsOverview = TRUE;
1607 50 : poDS->papoOverviewDS[i]->poParentDS = poDS;
1608 50 : if (poDS->papoOverviewDS[i]->OpenZoomLevel(i + 1) != CE_None)
1609 : {
1610 0 : delete poDS->papoOverviewDS[i];
1611 0 : poDS->nOverviewCount = i;
1612 0 : break;
1613 : }
1614 : }
1615 : }
1616 :
1617 : /* -------------------------------------------------------------------- */
1618 : /* Create object for the whole image. */
1619 : /* -------------------------------------------------------------------- */
1620 12 : poDS->SetDescription(poOpenInfo->pszFilename);
1621 12 : if (poDS->OpenZoomLevel(0) != CE_None)
1622 : {
1623 0 : delete poDS;
1624 0 : return nullptr;
1625 : }
1626 :
1627 12 : CPLDebug("MrSID", "Opened image: width %d, height %d, bands %d",
1628 : poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands);
1629 :
1630 12 : if (poDS->nBands > 1)
1631 0 : poDS->SetMetadataItem(GDALMD_INTERLEAVE, "PIXEL",
1632 0 : GDAL_MDD_IMAGE_STRUCTURE);
1633 :
1634 12 : if (bIsJP2)
1635 : {
1636 0 : poDS->LoadJP2Metadata(poOpenInfo);
1637 : }
1638 :
1639 : /* -------------------------------------------------------------------- */
1640 : /* Initialize any PAM information. */
1641 : /* -------------------------------------------------------------------- */
1642 12 : poDS->TryLoadXML();
1643 :
1644 : /* -------------------------------------------------------------------- */
1645 : /* Initialize the overview manager for mask band support. */
1646 : /* -------------------------------------------------------------------- */
1647 12 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
1648 :
1649 12 : return poDS;
1650 : }
1651 :
1652 : /************************************************************************/
1653 : /* EPSGProjMethodToCTProjMethod() */
1654 : /* */
1655 : /* Convert between the EPSG enumeration for projection methods, */
1656 : /* and the GeoTIFF CT codes. */
1657 : /* Explicitly copied from geo_normalize.c of the GeoTIFF package */
1658 : /************************************************************************/
1659 :
1660 0 : static int EPSGProjMethodToCTProjMethod(int nEPSG)
1661 :
1662 : {
1663 : /* see trf_method.csv for list of EPSG codes */
1664 :
1665 0 : switch (nEPSG)
1666 : {
1667 0 : case 9801:
1668 0 : return CT_LambertConfConic_1SP;
1669 :
1670 0 : case 9802:
1671 0 : return CT_LambertConfConic_2SP;
1672 :
1673 0 : case 9803:
1674 0 : return CT_LambertConfConic_2SP; // Belgian variant not supported.
1675 :
1676 0 : case 9804:
1677 0 : return CT_Mercator; // 1SP and 2SP not differentiated.
1678 :
1679 0 : case 9805:
1680 0 : return CT_Mercator; // 1SP and 2SP not differentiated.
1681 :
1682 0 : case 9806:
1683 0 : return CT_CassiniSoldner;
1684 :
1685 0 : case 9807:
1686 0 : return CT_TransverseMercator;
1687 :
1688 0 : case 9808:
1689 0 : return CT_TransvMercator_SouthOriented;
1690 :
1691 0 : case 9809:
1692 0 : return CT_ObliqueStereographic;
1693 :
1694 0 : case 9810:
1695 0 : return CT_PolarStereographic;
1696 :
1697 0 : case 9811:
1698 0 : return CT_NewZealandMapGrid;
1699 :
1700 0 : case 9812:
1701 0 : return CT_ObliqueMercator; // Is hotine actually different?
1702 :
1703 0 : case 9813:
1704 0 : return CT_ObliqueMercator_Laborde;
1705 :
1706 0 : case 9814:
1707 0 : return CT_ObliqueMercator_Rosenmund; // Swiss.
1708 :
1709 0 : case 9815:
1710 0 : return CT_ObliqueMercator;
1711 :
1712 0 : case 9816: /* tunesia mining grid has no counterpart */
1713 0 : return KvUserDefined;
1714 : }
1715 :
1716 0 : return KvUserDefined;
1717 : }
1718 :
1719 : /* EPSG Codes for projection parameters. Unfortunately, these bear no
1720 : relationship to the GeoTIFF codes even though the names are so similar. */
1721 :
1722 : #define EPSGNatOriginLat 8801
1723 : #define EPSGNatOriginLong 8802
1724 : #define EPSGNatOriginScaleFactor 8805
1725 : #define EPSGFalseEasting 8806
1726 : #define EPSGFalseNorthing 8807
1727 : #define EPSGProjCenterLat 8811
1728 : #define EPSGProjCenterLong 8812
1729 : #define EPSGAzimuth 8813
1730 : #define EPSGAngleRectifiedToSkewedGrid 8814
1731 : #define EPSGInitialLineScaleFactor 8815
1732 : #define EPSGProjCenterEasting 8816
1733 : #define EPSGProjCenterNorthing 8817
1734 : #define EPSGPseudoStdParallelLat 8818
1735 : #define EPSGPseudoStdParallelScaleFactor 8819
1736 : #define EPSGFalseOriginLat 8821
1737 : #define EPSGFalseOriginLong 8822
1738 : #define EPSGStdParallel1Lat 8823
1739 : #define EPSGStdParallel2Lat 8824
1740 : #define EPSGFalseOriginEasting 8826
1741 : #define EPSGFalseOriginNorthing 8827
1742 : #define EPSGSphericalOriginLat 8828
1743 : #define EPSGSphericalOriginLong 8829
1744 : #define EPSGInitialLongitude 8830
1745 : #define EPSGZoneWidth 8831
1746 :
1747 : /************************************************************************/
1748 : /* SetGTParamIds() */
1749 : /* */
1750 : /* This is hardcoded logic to set the GeoTIFF parameter */
1751 : /* identifiers for all the EPSG supported projections. As the */
1752 : /* trf_method.csv table grows with new projections, this code */
1753 : /* will need to be updated. */
1754 : /* Explicitly copied from geo_normalize.c of the GeoTIFF package. */
1755 : /************************************************************************/
1756 :
1757 0 : static int SetGTParamIds(int nCTProjection, int *panProjParamId,
1758 : int *panEPSGCodes)
1759 :
1760 : {
1761 : int anWorkingDummy[7];
1762 :
1763 0 : if (panEPSGCodes == nullptr)
1764 0 : panEPSGCodes = anWorkingDummy;
1765 0 : if (panProjParamId == nullptr)
1766 0 : panProjParamId = anWorkingDummy;
1767 :
1768 0 : memset(panEPSGCodes, 0, sizeof(int) * 7);
1769 :
1770 : /* psDefn->nParms = 7; */
1771 :
1772 0 : switch (nCTProjection)
1773 : {
1774 0 : case CT_CassiniSoldner:
1775 : case CT_NewZealandMapGrid:
1776 0 : panProjParamId[0] = ProjNatOriginLatGeoKey;
1777 0 : panProjParamId[1] = ProjNatOriginLongGeoKey;
1778 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1779 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1780 :
1781 0 : panEPSGCodes[0] = EPSGNatOriginLat;
1782 0 : panEPSGCodes[1] = EPSGNatOriginLong;
1783 0 : panEPSGCodes[5] = EPSGFalseEasting;
1784 0 : panEPSGCodes[6] = EPSGFalseNorthing;
1785 0 : return TRUE;
1786 :
1787 0 : case CT_ObliqueMercator:
1788 0 : panProjParamId[0] = ProjCenterLatGeoKey;
1789 0 : panProjParamId[1] = ProjCenterLongGeoKey;
1790 0 : panProjParamId[2] = ProjAzimuthAngleGeoKey;
1791 0 : panProjParamId[3] = ProjRectifiedGridAngleGeoKey;
1792 0 : panProjParamId[4] = ProjScaleAtCenterGeoKey;
1793 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1794 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1795 :
1796 0 : panEPSGCodes[0] = EPSGProjCenterLat;
1797 0 : panEPSGCodes[1] = EPSGProjCenterLong;
1798 0 : panEPSGCodes[2] = EPSGAzimuth;
1799 0 : panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
1800 0 : panEPSGCodes[4] = EPSGInitialLineScaleFactor;
1801 0 : panEPSGCodes[5] = EPSGProjCenterEasting;
1802 0 : panEPSGCodes[6] = EPSGProjCenterNorthing;
1803 0 : return TRUE;
1804 :
1805 0 : case CT_ObliqueMercator_Laborde:
1806 0 : panProjParamId[0] = ProjCenterLatGeoKey;
1807 0 : panProjParamId[1] = ProjCenterLongGeoKey;
1808 0 : panProjParamId[2] = ProjAzimuthAngleGeoKey;
1809 0 : panProjParamId[4] = ProjScaleAtCenterGeoKey;
1810 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1811 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1812 :
1813 0 : panEPSGCodes[0] = EPSGProjCenterLat;
1814 0 : panEPSGCodes[1] = EPSGProjCenterLong;
1815 0 : panEPSGCodes[2] = EPSGAzimuth;
1816 0 : panEPSGCodes[4] = EPSGInitialLineScaleFactor;
1817 0 : panEPSGCodes[5] = EPSGProjCenterEasting;
1818 0 : panEPSGCodes[6] = EPSGProjCenterNorthing;
1819 0 : return TRUE;
1820 :
1821 0 : case CT_LambertConfConic_1SP:
1822 : case CT_Mercator:
1823 : case CT_ObliqueStereographic:
1824 : case CT_PolarStereographic:
1825 : case CT_TransverseMercator:
1826 : case CT_TransvMercator_SouthOriented:
1827 0 : panProjParamId[0] = ProjNatOriginLatGeoKey;
1828 0 : panProjParamId[1] = ProjNatOriginLongGeoKey;
1829 0 : panProjParamId[4] = ProjScaleAtNatOriginGeoKey;
1830 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1831 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1832 :
1833 0 : panEPSGCodes[0] = EPSGNatOriginLat;
1834 0 : panEPSGCodes[1] = EPSGNatOriginLong;
1835 0 : panEPSGCodes[4] = EPSGNatOriginScaleFactor;
1836 0 : panEPSGCodes[5] = EPSGFalseEasting;
1837 0 : panEPSGCodes[6] = EPSGFalseNorthing;
1838 0 : return TRUE;
1839 :
1840 0 : case CT_LambertConfConic_2SP:
1841 0 : panProjParamId[0] = ProjFalseOriginLatGeoKey;
1842 0 : panProjParamId[1] = ProjFalseOriginLongGeoKey;
1843 0 : panProjParamId[2] = ProjStdParallel1GeoKey;
1844 0 : panProjParamId[3] = ProjStdParallel2GeoKey;
1845 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1846 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1847 :
1848 0 : panEPSGCodes[0] = EPSGFalseOriginLat;
1849 0 : panEPSGCodes[1] = EPSGFalseOriginLong;
1850 0 : panEPSGCodes[2] = EPSGStdParallel1Lat;
1851 0 : panEPSGCodes[3] = EPSGStdParallel2Lat;
1852 0 : panEPSGCodes[5] = EPSGFalseOriginEasting;
1853 0 : panEPSGCodes[6] = EPSGFalseOriginNorthing;
1854 0 : return TRUE;
1855 :
1856 0 : case CT_SwissObliqueCylindrical:
1857 0 : panProjParamId[0] = ProjCenterLatGeoKey;
1858 0 : panProjParamId[1] = ProjCenterLongGeoKey;
1859 0 : panProjParamId[5] = ProjFalseEastingGeoKey;
1860 0 : panProjParamId[6] = ProjFalseNorthingGeoKey;
1861 :
1862 : /* EPSG codes? */
1863 0 : return TRUE;
1864 :
1865 0 : default:
1866 0 : return FALSE;
1867 : }
1868 : }
1869 :
1870 : static const char *const papszDatumEquiv[] = {
1871 : "Militar_Geographische_Institut",
1872 : "Militar_Geographische_Institute",
1873 : "World_Geodetic_System_1984",
1874 : "WGS_1984",
1875 : "WGS_72_Transit_Broadcast_Ephemeris",
1876 : "WGS_1972_Transit_Broadcast_Ephemeris",
1877 : "World_Geodetic_System_1972",
1878 : "WGS_1972",
1879 : "European_Terrestrial_Reference_System_89",
1880 : "European_Reference_System_1989",
1881 : nullptr};
1882 :
1883 : /************************************************************************/
1884 : /* WKTMassageDatum() */
1885 : /* */
1886 : /* Massage an EPSG datum name into WMT format. Also transform */
1887 : /* specific exception cases into WKT versions. */
1888 : /* Explicitly copied from the gt_wkt_srs.cpp. */
1889 : /************************************************************************/
1890 :
1891 10 : static void WKTMassageDatum(char **ppszDatum)
1892 :
1893 : {
1894 : int i, j;
1895 10 : char *pszDatum = *ppszDatum;
1896 :
1897 10 : if (pszDatum[0] == '\0')
1898 0 : return;
1899 :
1900 : /* -------------------------------------------------------------------- */
1901 : /* Translate non-alphanumeric values to underscores. */
1902 : /* -------------------------------------------------------------------- */
1903 260 : for (i = 0; pszDatum[i] != '\0'; i++)
1904 : {
1905 250 : if (!(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z') &&
1906 220 : !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z') &&
1907 70 : !(pszDatum[i] >= '0' && pszDatum[i] <= '9'))
1908 : {
1909 30 : pszDatum[i] = '_';
1910 : }
1911 : }
1912 :
1913 : /* -------------------------------------------------------------------- */
1914 : /* Remove repeated and trailing underscores. */
1915 : /* -------------------------------------------------------------------- */
1916 250 : for (i = 1, j = 0; pszDatum[i] != '\0'; i++)
1917 : {
1918 240 : if (pszDatum[j] == '_' && pszDatum[i] == '_')
1919 0 : continue;
1920 :
1921 240 : pszDatum[++j] = pszDatum[i];
1922 : }
1923 10 : if (pszDatum[j] == '_')
1924 0 : pszDatum[j] = '\0';
1925 : else
1926 10 : pszDatum[j + 1] = '\0';
1927 :
1928 : /* -------------------------------------------------------------------- */
1929 : /* Search for datum equivalences. Specific massaged names get */
1930 : /* mapped to OpenGIS specified names. */
1931 : /* -------------------------------------------------------------------- */
1932 60 : for (i = 0; papszDatumEquiv[i] != nullptr; i += 2)
1933 : {
1934 50 : if (EQUAL(*ppszDatum, papszDatumEquiv[i]))
1935 : {
1936 0 : CPLFree(*ppszDatum);
1937 0 : *ppszDatum = CPLStrdup(papszDatumEquiv[i + 1]);
1938 0 : return;
1939 : }
1940 : }
1941 : }
1942 :
1943 : /************************************************************************/
1944 : /* FetchProjParams() */
1945 : /* */
1946 : /* Fetch the projection parameters for a particular projection */
1947 : /* from MrSID metadata, and fill the GTIFDefn structure out */
1948 : /* with them. */
1949 : /* Copied from geo_normalize.c of the GeoTIFF package. */
1950 : /************************************************************************/
1951 :
1952 10 : void MrSIDDataset::FetchProjParams()
1953 : {
1954 10 : double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
1955 10 : double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
1956 10 : double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
1957 :
1958 : /* -------------------------------------------------------------------- */
1959 : /* Get the false easting, and northing if available. */
1960 : /* -------------------------------------------------------------------- */
1961 10 : if (!GetMetadataElement("GEOTIFF_NUM::3082::ProjFalseEastingGeoKey",
1962 20 : &dfFalseEasting) &&
1963 10 : !GetMetadataElement("GEOTIFF_NUM::3090:ProjCenterEastingGeoKey",
1964 : &dfFalseEasting))
1965 10 : dfFalseEasting = 0.0;
1966 :
1967 10 : if (!GetMetadataElement("GEOTIFF_NUM::3083::ProjFalseNorthingGeoKey",
1968 20 : &dfFalseNorthing) &&
1969 10 : !GetMetadataElement("GEOTIFF_NUM::3091::ProjCenterNorthingGeoKey",
1970 : &dfFalseNorthing))
1971 10 : dfFalseNorthing = 0.0;
1972 :
1973 10 : switch (psDefn->CTProjection)
1974 : {
1975 : /* --------------------------------------------------------------------
1976 : */
1977 0 : case CT_Stereographic:
1978 : /* --------------------------------------------------------------------
1979 : */
1980 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
1981 0 : &dfNatOriginLong) == 0 &&
1982 0 : GetMetadataElement(
1983 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
1984 0 : &dfNatOriginLong) == 0 &&
1985 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
1986 : &dfNatOriginLong) == 0)
1987 0 : dfNatOriginLong = 0.0;
1988 :
1989 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
1990 0 : &dfNatOriginLat) == 0 &&
1991 0 : GetMetadataElement(
1992 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
1993 0 : &dfNatOriginLat) == 0 &&
1994 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
1995 : &dfNatOriginLat) == 0)
1996 0 : dfNatOriginLat = 0.0;
1997 :
1998 0 : if (GetMetadataElement(
1999 : "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2000 0 : &dfNatOriginScale) == 0)
2001 0 : dfNatOriginScale = 1.0;
2002 :
2003 : /* notdef: should transform to decimal degrees at this point */
2004 :
2005 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2006 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2007 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2008 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2009 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2010 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2011 0 : psDefn->ProjParm[5] = dfFalseEasting;
2012 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2013 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2014 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2015 :
2016 0 : psDefn->nParms = 7;
2017 0 : break;
2018 :
2019 : /* --------------------------------------------------------------------
2020 : */
2021 10 : case CT_LambertConfConic_1SP:
2022 : case CT_Mercator:
2023 : case CT_ObliqueStereographic:
2024 : case CT_TransverseMercator:
2025 : case CT_TransvMercator_SouthOriented:
2026 : /* --------------------------------------------------------------------
2027 : */
2028 10 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2029 10 : &dfNatOriginLong) == 0 &&
2030 10 : GetMetadataElement(
2031 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2032 20 : &dfNatOriginLong) == 0 &&
2033 10 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2034 : &dfNatOriginLong) == 0)
2035 10 : dfNatOriginLong = 0.0;
2036 :
2037 10 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2038 10 : &dfNatOriginLat) == 0 &&
2039 10 : GetMetadataElement(
2040 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2041 20 : &dfNatOriginLat) == 0 &&
2042 10 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2043 : &dfNatOriginLat) == 0)
2044 10 : dfNatOriginLat = 0.0;
2045 :
2046 10 : if (GetMetadataElement(
2047 : "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2048 10 : &dfNatOriginScale) == 0)
2049 10 : dfNatOriginScale = 1.0;
2050 :
2051 : /* notdef: should transform to decimal degrees at this point */
2052 :
2053 10 : psDefn->ProjParm[0] = dfNatOriginLat;
2054 10 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2055 10 : psDefn->ProjParm[1] = dfNatOriginLong;
2056 10 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2057 10 : psDefn->ProjParm[4] = dfNatOriginScale;
2058 10 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2059 10 : psDefn->ProjParm[5] = dfFalseEasting;
2060 10 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2061 10 : psDefn->ProjParm[6] = dfFalseNorthing;
2062 10 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2063 :
2064 10 : psDefn->nParms = 7;
2065 10 : break;
2066 :
2067 : /* --------------------------------------------------------------------
2068 : */
2069 0 : case CT_ObliqueMercator: /* hotine */
2070 : /* --------------------------------------------------------------------
2071 : */
2072 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2073 0 : &dfNatOriginLong) == 0 &&
2074 0 : GetMetadataElement(
2075 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2076 0 : &dfNatOriginLong) == 0 &&
2077 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2078 : &dfNatOriginLong) == 0)
2079 0 : dfNatOriginLong = 0.0;
2080 :
2081 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2082 0 : &dfNatOriginLat) == 0 &&
2083 0 : GetMetadataElement(
2084 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2085 0 : &dfNatOriginLat) == 0 &&
2086 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2087 : &dfNatOriginLat) == 0)
2088 0 : dfNatOriginLat = 0.0;
2089 :
2090 0 : if (GetMetadataElement("GEOTIFF_NUM::3094::ProjAzimuthAngleGeoKey",
2091 0 : &dfAzimuth) == 0)
2092 0 : dfAzimuth = 0.0;
2093 :
2094 0 : if (GetMetadataElement(
2095 : "GEOTIFF_NUM::3096::ProjRectifiedGridAngleGeoKey",
2096 0 : &dfRectGridAngle) == 0)
2097 0 : dfRectGridAngle = 90.0;
2098 :
2099 0 : if (GetMetadataElement(
2100 : "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2101 0 : &dfNatOriginScale) == 0 &&
2102 0 : GetMetadataElement("GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2103 : &dfNatOriginScale) == 0)
2104 0 : dfNatOriginScale = 1.0;
2105 :
2106 : /* notdef: should transform to decimal degrees at this point */
2107 :
2108 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2109 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2110 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2111 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2112 0 : psDefn->ProjParm[2] = dfAzimuth;
2113 0 : psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
2114 0 : psDefn->ProjParm[3] = dfRectGridAngle;
2115 0 : psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
2116 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2117 0 : psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
2118 0 : psDefn->ProjParm[5] = dfFalseEasting;
2119 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2120 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2121 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2122 :
2123 0 : psDefn->nParms = 7;
2124 0 : break;
2125 :
2126 : /* --------------------------------------------------------------------
2127 : */
2128 0 : case CT_CassiniSoldner:
2129 : case CT_Polyconic:
2130 : /* --------------------------------------------------------------------
2131 : */
2132 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2133 0 : &dfNatOriginLong) == 0 &&
2134 0 : GetMetadataElement(
2135 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2136 0 : &dfNatOriginLong) == 0 &&
2137 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2138 : &dfNatOriginLong) == 0)
2139 0 : dfNatOriginLong = 0.0;
2140 :
2141 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2142 0 : &dfNatOriginLat) == 0 &&
2143 0 : GetMetadataElement(
2144 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2145 0 : &dfNatOriginLat) == 0 &&
2146 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2147 : &dfNatOriginLat) == 0)
2148 0 : dfNatOriginLat = 0.0;
2149 :
2150 0 : if (GetMetadataElement(
2151 : "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2152 0 : &dfNatOriginScale) == 0 &&
2153 0 : GetMetadataElement("GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2154 : &dfNatOriginScale) == 0)
2155 0 : dfNatOriginScale = 1.0;
2156 :
2157 : /* notdef: should transform to decimal degrees at this point */
2158 :
2159 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2160 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2161 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2162 0 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2163 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2164 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2165 0 : psDefn->ProjParm[5] = dfFalseEasting;
2166 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2167 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2168 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2169 :
2170 0 : psDefn->nParms = 7;
2171 0 : break;
2172 :
2173 : /* --------------------------------------------------------------------
2174 : */
2175 0 : case CT_AzimuthalEquidistant:
2176 : case CT_MillerCylindrical:
2177 : case CT_Equirectangular:
2178 : case CT_Gnomonic:
2179 : case CT_LambertAzimEqualArea:
2180 : case CT_Orthographic:
2181 : /* --------------------------------------------------------------------
2182 : */
2183 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2184 0 : &dfNatOriginLong) == 0 &&
2185 0 : GetMetadataElement(
2186 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2187 0 : &dfNatOriginLong) == 0 &&
2188 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2189 : &dfNatOriginLong) == 0)
2190 0 : dfNatOriginLong = 0.0;
2191 :
2192 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2193 0 : &dfNatOriginLat) == 0 &&
2194 0 : GetMetadataElement(
2195 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2196 0 : &dfNatOriginLat) == 0 &&
2197 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2198 : &dfNatOriginLat) == 0)
2199 0 : dfNatOriginLat = 0.0;
2200 :
2201 : /* notdef: should transform to decimal degrees at this point */
2202 :
2203 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2204 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2205 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2206 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2207 0 : psDefn->ProjParm[5] = dfFalseEasting;
2208 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2209 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2210 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2211 :
2212 0 : psDefn->nParms = 7;
2213 0 : break;
2214 :
2215 : /* --------------------------------------------------------------------
2216 : */
2217 0 : case CT_Robinson:
2218 : case CT_Sinusoidal:
2219 : case CT_VanDerGrinten:
2220 : /* --------------------------------------------------------------------
2221 : */
2222 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2223 0 : &dfNatOriginLong) == 0 &&
2224 0 : GetMetadataElement(
2225 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2226 0 : &dfNatOriginLong) == 0 &&
2227 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2228 : &dfNatOriginLong) == 0)
2229 0 : dfNatOriginLong = 0.0;
2230 :
2231 : /* notdef: should transform to decimal degrees at this point */
2232 :
2233 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2234 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2235 0 : psDefn->ProjParm[5] = dfFalseEasting;
2236 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2237 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2238 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2239 :
2240 0 : psDefn->nParms = 7;
2241 0 : break;
2242 :
2243 : /* --------------------------------------------------------------------
2244 : */
2245 0 : case CT_PolarStereographic:
2246 : /* --------------------------------------------------------------------
2247 : */
2248 0 : if (GetMetadataElement(
2249 : "GEOTIFF_NUM::3095::ProjStraightVertPoleLongGeoKey",
2250 0 : &dfNatOriginLong) == 0 &&
2251 0 : GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2252 0 : &dfNatOriginLong) == 0 &&
2253 0 : GetMetadataElement(
2254 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2255 0 : &dfNatOriginLong) == 0 &&
2256 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2257 : &dfNatOriginLong) == 0)
2258 0 : dfNatOriginLong = 0.0;
2259 :
2260 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2261 0 : &dfNatOriginLat) == 0 &&
2262 0 : GetMetadataElement(
2263 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2264 0 : &dfNatOriginLat) == 0 &&
2265 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2266 : &dfNatOriginLat) == 0)
2267 0 : dfNatOriginLat = 0.0;
2268 :
2269 0 : if (GetMetadataElement(
2270 : "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2271 0 : &dfNatOriginScale) == 0 &&
2272 0 : GetMetadataElement("GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2273 : &dfNatOriginScale) == 0)
2274 0 : dfNatOriginScale = 1.0;
2275 :
2276 : /* notdef: should transform to decimal degrees at this point */
2277 :
2278 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2279 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2280 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2281 0 : psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
2282 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2283 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2284 0 : psDefn->ProjParm[5] = dfFalseEasting;
2285 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2286 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2287 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2288 :
2289 0 : psDefn->nParms = 7;
2290 0 : break;
2291 :
2292 : /* --------------------------------------------------------------------
2293 : */
2294 0 : case CT_LambertConfConic_2SP:
2295 : /* --------------------------------------------------------------------
2296 : */
2297 0 : if (GetMetadataElement("GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
2298 0 : &dfStdParallel1) == 0)
2299 0 : dfStdParallel1 = 0.0;
2300 :
2301 0 : if (GetMetadataElement("GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
2302 0 : &dfStdParallel2) == 0)
2303 0 : dfStdParallel1 = 0.0;
2304 :
2305 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2306 0 : &dfNatOriginLong) == 0 &&
2307 0 : GetMetadataElement(
2308 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2309 0 : &dfNatOriginLong) == 0 &&
2310 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2311 : &dfNatOriginLong) == 0)
2312 0 : dfNatOriginLong = 0.0;
2313 :
2314 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2315 0 : &dfNatOriginLat) == 0 &&
2316 0 : GetMetadataElement(
2317 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2318 0 : &dfNatOriginLat) == 0 &&
2319 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2320 : &dfNatOriginLat) == 0)
2321 0 : dfNatOriginLat = 0.0;
2322 :
2323 : /* notdef: should transform to decimal degrees at this point */
2324 :
2325 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2326 0 : psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
2327 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2328 0 : psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
2329 0 : psDefn->ProjParm[2] = dfStdParallel1;
2330 0 : psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
2331 0 : psDefn->ProjParm[3] = dfStdParallel2;
2332 0 : psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
2333 0 : psDefn->ProjParm[5] = dfFalseEasting;
2334 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2335 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2336 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2337 :
2338 0 : psDefn->nParms = 7;
2339 0 : break;
2340 :
2341 : /* --------------------------------------------------------------------
2342 : */
2343 0 : case CT_AlbersEqualArea:
2344 : case CT_EquidistantConic:
2345 : /* --------------------------------------------------------------------
2346 : */
2347 0 : if (GetMetadataElement("GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
2348 0 : &dfStdParallel1) == 0)
2349 0 : dfStdParallel1 = 0.0;
2350 :
2351 0 : if (GetMetadataElement("GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
2352 0 : &dfStdParallel2) == 0)
2353 0 : dfStdParallel1 = 0.0;
2354 :
2355 0 : if (GetMetadataElement("GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2356 0 : &dfNatOriginLong) == 0 &&
2357 0 : GetMetadataElement(
2358 : "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2359 0 : &dfNatOriginLong) == 0 &&
2360 0 : GetMetadataElement("GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2361 : &dfNatOriginLong) == 0)
2362 0 : dfNatOriginLong = 0.0;
2363 :
2364 0 : if (GetMetadataElement("GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2365 0 : &dfNatOriginLat) == 0 &&
2366 0 : GetMetadataElement(
2367 : "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2368 0 : &dfNatOriginLat) == 0 &&
2369 0 : GetMetadataElement("GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2370 : &dfNatOriginLat) == 0)
2371 0 : dfNatOriginLat = 0.0;
2372 :
2373 : /* notdef: should transform to decimal degrees at this point */
2374 :
2375 0 : psDefn->ProjParm[0] = dfStdParallel1;
2376 0 : psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
2377 0 : psDefn->ProjParm[1] = dfStdParallel2;
2378 0 : psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
2379 0 : psDefn->ProjParm[2] = dfNatOriginLat;
2380 0 : psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
2381 0 : psDefn->ProjParm[3] = dfNatOriginLong;
2382 0 : psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
2383 0 : psDefn->ProjParm[5] = dfFalseEasting;
2384 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2385 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2386 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2387 :
2388 0 : psDefn->nParms = 7;
2389 0 : break;
2390 : }
2391 10 : }
2392 :
2393 : /************************************************************************/
2394 : /* GetGTIFDefn() */
2395 : /* This function borrowed from the GTIFGetDefn() function. */
2396 : /* See geo_normalize.c from the GeoTIFF package. */
2397 : /************************************************************************/
2398 :
2399 12 : void MrSIDDataset::GetGTIFDefn()
2400 : {
2401 : double dfInvFlattening;
2402 :
2403 : /* -------------------------------------------------------------------- */
2404 : /* Make sure we have hooked CSV lookup for GDAL_DATA. */
2405 : /* -------------------------------------------------------------------- */
2406 12 : LibgeotiffOneTimeInit();
2407 :
2408 : /* -------------------------------------------------------------------- */
2409 : /* Initially we default all the information we can. */
2410 : /* -------------------------------------------------------------------- */
2411 12 : psDefn = new (GTIFDefn);
2412 12 : psDefn->Model = KvUserDefined;
2413 12 : psDefn->PCS = KvUserDefined;
2414 12 : psDefn->GCS = KvUserDefined;
2415 12 : psDefn->UOMLength = KvUserDefined;
2416 12 : psDefn->UOMLengthInMeters = 1.0;
2417 12 : psDefn->UOMAngle = KvUserDefined;
2418 12 : psDefn->UOMAngleInDegrees = 1.0;
2419 12 : psDefn->Datum = KvUserDefined;
2420 12 : psDefn->Ellipsoid = KvUserDefined;
2421 12 : psDefn->SemiMajor = 0.0;
2422 12 : psDefn->SemiMinor = 0.0;
2423 12 : psDefn->PM = KvUserDefined;
2424 12 : psDefn->PMLongToGreenwich = 0.0;
2425 :
2426 12 : psDefn->ProjCode = KvUserDefined;
2427 12 : psDefn->Projection = KvUserDefined;
2428 12 : psDefn->CTProjection = KvUserDefined;
2429 :
2430 12 : psDefn->nParms = 0;
2431 132 : for (int i = 0; i < MAX_GTIF_PROJPARMS; i++)
2432 : {
2433 120 : psDefn->ProjParm[i] = 0.0;
2434 120 : psDefn->ProjParmId[i] = 0;
2435 : }
2436 :
2437 12 : psDefn->MapSys = KvUserDefined;
2438 12 : psDefn->Zone = 0;
2439 :
2440 : /* -------------------------------------------------------------------- */
2441 : /* Try to get the overall model type. */
2442 : /* -------------------------------------------------------------------- */
2443 12 : GetMetadataElement("GEOTIFF_NUM::1024::GTModelTypeGeoKey",
2444 12 : &(psDefn->Model));
2445 :
2446 : /* -------------------------------------------------------------------- */
2447 : /* Try to get a PCS. */
2448 : /* -------------------------------------------------------------------- */
2449 36 : if (GetMetadataElement("GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey",
2450 22 : &(psDefn->PCS)) &&
2451 10 : psDefn->PCS != KvUserDefined)
2452 : {
2453 : /*
2454 : * Translate this into useful information.
2455 : */
2456 0 : GTIFGetPCSInfo(psDefn->PCS, nullptr, &(psDefn->ProjCode),
2457 0 : &(psDefn->UOMLength), &(psDefn->GCS));
2458 : }
2459 :
2460 : /* -------------------------------------------------------------------- */
2461 : /* If we have the PCS code, but didn't find it in the CSV files */
2462 : /* (likely because we can't find them) we will try some ``jiffy */
2463 : /* rules'' for UTM and state plane. */
2464 : /* -------------------------------------------------------------------- */
2465 12 : if (psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined)
2466 : {
2467 : int nMapSys, nZone;
2468 0 : int nGCS = psDefn->GCS;
2469 :
2470 0 : nMapSys = GTIFPCSToMapSys(psDefn->PCS, &nGCS, &nZone);
2471 0 : if (nMapSys != KvUserDefined)
2472 : {
2473 0 : psDefn->ProjCode = (short)GTIFMapSysToProj(nMapSys, nZone);
2474 0 : psDefn->GCS = (short)nGCS;
2475 : }
2476 : }
2477 :
2478 : /* -------------------------------------------------------------------- */
2479 : /* If the Proj_ code is specified directly, use that. */
2480 : /* -------------------------------------------------------------------- */
2481 12 : if (psDefn->ProjCode == KvUserDefined)
2482 12 : GetMetadataElement("GEOTIFF_NUM::3074::ProjectionGeoKey",
2483 12 : &(psDefn->ProjCode));
2484 :
2485 12 : if (psDefn->ProjCode != KvUserDefined)
2486 : {
2487 : /*
2488 : * We have an underlying projection transformation value. Look
2489 : * this up. For a PCS of ``WGS 84 / UTM 11'' the transformation
2490 : * would be Transverse Mercator, with a particular set of options.
2491 : * The nProjTRFCode itself would correspond to the name
2492 : * ``UTM zone 11N'', and doesn't include datum info.
2493 : */
2494 0 : GTIFGetProjTRFInfo(psDefn->ProjCode, nullptr, &(psDefn->Projection),
2495 0 : psDefn->ProjParm);
2496 :
2497 : /*
2498 : * Set the GeoTIFF identity of the parameters.
2499 : */
2500 0 : psDefn->CTProjection =
2501 0 : (short)EPSGProjMethodToCTProjMethod(psDefn->Projection);
2502 :
2503 0 : SetGTParamIds(psDefn->CTProjection, psDefn->ProjParmId, nullptr);
2504 0 : psDefn->nParms = 7;
2505 : }
2506 :
2507 : /* -------------------------------------------------------------------- */
2508 : /* Try to get a GCS. If found, it will override any implied by */
2509 : /* the PCS. */
2510 : /* -------------------------------------------------------------------- */
2511 12 : GetMetadataElement("GEOTIFF_NUM::2048::GeographicTypeGeoKey",
2512 12 : &(psDefn->GCS));
2513 :
2514 : /* -------------------------------------------------------------------- */
2515 : /* Derive the datum, and prime meridian from the GCS. */
2516 : /* -------------------------------------------------------------------- */
2517 12 : if (psDefn->GCS != KvUserDefined)
2518 : {
2519 10 : GTIFGetGCSInfo(psDefn->GCS, nullptr, &(psDefn->Datum), &(psDefn->PM),
2520 10 : &(psDefn->UOMAngle));
2521 : }
2522 :
2523 : /* -------------------------------------------------------------------- */
2524 : /* Handle the GCS angular units. GeogAngularUnitsGeoKey */
2525 : /* overrides the GCS or PCS setting. */
2526 : /* -------------------------------------------------------------------- */
2527 12 : GetMetadataElement("GEOTIFF_NUM::2054::GeogAngularUnitsGeoKey",
2528 12 : &(psDefn->UOMAngle));
2529 12 : if (psDefn->UOMAngle != KvUserDefined)
2530 : {
2531 10 : GTIFGetUOMAngleInfo(psDefn->UOMAngle, nullptr,
2532 10 : &(psDefn->UOMAngleInDegrees));
2533 : }
2534 :
2535 : /* -------------------------------------------------------------------- */
2536 : /* Check for a datum setting, and then use the datum to derive */
2537 : /* an ellipsoid. */
2538 : /* -------------------------------------------------------------------- */
2539 12 : GetMetadataElement("GEOTIFF_NUM::2050::GeogGeodeticDatumGeoKey",
2540 12 : &(psDefn->Datum));
2541 :
2542 12 : if (psDefn->Datum != KvUserDefined)
2543 : {
2544 10 : GTIFGetDatumInfo(psDefn->Datum, nullptr, &(psDefn->Ellipsoid));
2545 : }
2546 :
2547 : /* -------------------------------------------------------------------- */
2548 : /* Check for an explicit ellipsoid. Use the ellipsoid to */
2549 : /* derive the ellipsoid characteristics, if possible. */
2550 : /* -------------------------------------------------------------------- */
2551 12 : GetMetadataElement("GEOTIFF_NUM::2056::GeogEllipsoidGeoKey",
2552 12 : &(psDefn->Ellipsoid));
2553 :
2554 12 : if (psDefn->Ellipsoid != KvUserDefined)
2555 : {
2556 10 : GTIFGetEllipsoidInfo(psDefn->Ellipsoid, nullptr, &(psDefn->SemiMajor),
2557 10 : &(psDefn->SemiMinor));
2558 : }
2559 :
2560 : /* -------------------------------------------------------------------- */
2561 : /* Check for overridden ellipsoid parameters. It would be nice */
2562 : /* to warn if they conflict with provided information, but for */
2563 : /* now we just override. */
2564 : /* -------------------------------------------------------------------- */
2565 12 : GetMetadataElement("GEOTIFF_NUM::2057::GeogSemiMajorAxisGeoKey",
2566 12 : &(psDefn->SemiMajor));
2567 12 : GetMetadataElement("GEOTIFF_NUM::2058::GeogSemiMinorAxisGeoKey",
2568 12 : &(psDefn->SemiMinor));
2569 :
2570 12 : if (GetMetadataElement("GEOTIFF_NUM::2059::GeogInvFlatteningGeoKey",
2571 12 : &dfInvFlattening) == 1)
2572 : {
2573 0 : if (dfInvFlattening != 0.0)
2574 0 : psDefn->SemiMinor = OSRCalcSemiMinorFromInvFlattening(
2575 0 : psDefn->SemiMajor, dfInvFlattening);
2576 : }
2577 :
2578 : /* -------------------------------------------------------------------- */
2579 : /* Get the prime meridian info. */
2580 : /* -------------------------------------------------------------------- */
2581 12 : GetMetadataElement("GEOTIFF_NUM::2051::GeogPrimeMeridianGeoKey",
2582 12 : &(psDefn->PM));
2583 :
2584 12 : if (psDefn->PM != KvUserDefined)
2585 : {
2586 10 : GTIFGetPMInfo(psDefn->PM, nullptr, &(psDefn->PMLongToGreenwich));
2587 : }
2588 : else
2589 : {
2590 2 : GetMetadataElement("GEOTIFF_NUM::2061::GeogPrimeMeridianLongGeoKey",
2591 2 : &(psDefn->PMLongToGreenwich));
2592 :
2593 4 : psDefn->PMLongToGreenwich =
2594 2 : GTIFAngleToDD(psDefn->PMLongToGreenwich, psDefn->UOMAngle);
2595 : }
2596 :
2597 : /* -------------------------------------------------------------------- */
2598 : /* Have the projection units of measure been overridden? We */
2599 : /* should likely be doing something about angular units too, */
2600 : /* but these are very rarely not decimal degrees for actual */
2601 : /* file coordinates. */
2602 : /* -------------------------------------------------------------------- */
2603 12 : GetMetadataElement("GEOTIFF_NUM::3076::ProjLinearUnitsGeoKey",
2604 12 : &(psDefn->UOMLength));
2605 :
2606 12 : if (psDefn->UOMLength != KvUserDefined)
2607 : {
2608 10 : GTIFGetUOMLengthInfo(psDefn->UOMLength, nullptr,
2609 10 : &(psDefn->UOMLengthInMeters));
2610 : }
2611 :
2612 : /* -------------------------------------------------------------------- */
2613 : /* Handle a variety of user defined transform types. */
2614 : /* -------------------------------------------------------------------- */
2615 24 : if (GetMetadataElement("GEOTIFF_NUM::3075::ProjCoordTransGeoKey",
2616 12 : &(psDefn->CTProjection)))
2617 : {
2618 10 : FetchProjParams();
2619 : }
2620 :
2621 : /* -------------------------------------------------------------------- */
2622 : /* Try to set the zoned map system information. */
2623 : /* -------------------------------------------------------------------- */
2624 12 : psDefn->MapSys = GTIFProjToMapSys(psDefn->ProjCode, &(psDefn->Zone));
2625 :
2626 : /* -------------------------------------------------------------------- */
2627 : /* If this is UTM, and we were unable to extract the projection */
2628 : /* parameters from the CSV file, just set them directly now, */
2629 : /* since it is pretty easy, and a common case. */
2630 : /* -------------------------------------------------------------------- */
2631 12 : if ((psDefn->MapSys == MapSys_UTM_North ||
2632 12 : psDefn->MapSys == MapSys_UTM_South) &&
2633 0 : psDefn->CTProjection == KvUserDefined)
2634 : {
2635 0 : psDefn->CTProjection = CT_TransverseMercator;
2636 0 : psDefn->nParms = 7;
2637 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2638 0 : psDefn->ProjParm[0] = 0.0;
2639 :
2640 0 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2641 0 : psDefn->ProjParm[1] = psDefn->Zone * 6 - 183.0;
2642 :
2643 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2644 0 : psDefn->ProjParm[4] = 0.9996;
2645 :
2646 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2647 0 : psDefn->ProjParm[5] = 500000.0;
2648 :
2649 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2650 :
2651 0 : if (psDefn->MapSys == MapSys_UTM_North)
2652 0 : psDefn->ProjParm[6] = 0.0;
2653 : else
2654 0 : psDefn->ProjParm[6] = 10000000.0;
2655 : }
2656 :
2657 12 : char *pszProjection = GetOGISDefn(psDefn);
2658 12 : if (pszProjection)
2659 : {
2660 12 : m_oSRS.importFromWkt(pszProjection);
2661 12 : m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
2662 : }
2663 12 : CPLFree(pszProjection);
2664 12 : }
2665 :
2666 : /************************************************************************/
2667 : /* GTIFToCPLRecyleString() */
2668 : /* */
2669 : /* This changes a string from the libgeotiff heap to the GDAL */
2670 : /* heap. */
2671 : /************************************************************************/
2672 :
2673 50 : static void GTIFToCPLRecycleString(char **ppszTarget)
2674 :
2675 : {
2676 50 : if (*ppszTarget == nullptr)
2677 0 : return;
2678 :
2679 50 : char *pszTempString = CPLStrdup(*ppszTarget);
2680 50 : GTIFFreeMemory(*ppszTarget);
2681 50 : *ppszTarget = pszTempString;
2682 : }
2683 :
2684 : /************************************************************************/
2685 : /* GetOGISDefn() */
2686 : /* Copied from the gt_wkt_srs.cpp. */
2687 : /************************************************************************/
2688 :
2689 12 : char *MrSIDDataset::GetOGISDefn(GTIFDefn *psDefnIn)
2690 : {
2691 24 : OGRSpatialReference oSRS;
2692 :
2693 12 : if (psDefnIn->Model != ModelTypeProjected &&
2694 2 : psDefnIn->Model != ModelTypeGeographic)
2695 2 : return CPLStrdup("");
2696 :
2697 : /* -------------------------------------------------------------------- */
2698 : /* If this is a projected SRS we set the PROJCS keyword first */
2699 : /* to ensure that the GEOGCS will be a child. */
2700 : /* -------------------------------------------------------------------- */
2701 10 : if (psDefnIn->Model == ModelTypeProjected)
2702 : {
2703 10 : int bPCSNameSet = FALSE;
2704 :
2705 10 : if (psDefnIn->PCS != KvUserDefined)
2706 : {
2707 0 : char *pszPCSName = nullptr;
2708 :
2709 0 : if (GTIFGetPCSInfo(psDefnIn->PCS, &pszPCSName, nullptr, nullptr,
2710 0 : nullptr))
2711 0 : bPCSNameSet = TRUE;
2712 :
2713 0 : oSRS.SetNode("PROJCS", bPCSNameSet ? pszPCSName : "unnamed");
2714 0 : if (bPCSNameSet)
2715 0 : GTIFFreeMemory(pszPCSName);
2716 :
2717 0 : oSRS.SetAuthority("PROJCS", "EPSG", psDefnIn->PCS);
2718 : }
2719 : else
2720 : {
2721 : char szPCSName[200];
2722 10 : strcpy(szPCSName, "unnamed");
2723 10 : if (GetMetadataElement("GEOTIFF_NUM::1026::GTCitationGeoKey",
2724 10 : szPCSName, sizeof(szPCSName)))
2725 10 : oSRS.SetNode("PROJCS", szPCSName);
2726 : }
2727 : }
2728 :
2729 : /* ==================================================================== */
2730 : /* Setup the GeogCS */
2731 : /* ==================================================================== */
2732 10 : char *pszGeogName = nullptr;
2733 10 : char *pszDatumName = nullptr;
2734 10 : char *pszPMName = nullptr;
2735 10 : char *pszSpheroidName = nullptr;
2736 10 : char *pszAngularUnits = nullptr;
2737 : double dfInvFlattening, dfSemiMajor;
2738 : char szGCSName[200];
2739 :
2740 10 : if (GetMetadataElement("GEOTIFF_NUM::2049::GeogCitationGeoKey", szGCSName,
2741 10 : sizeof(szGCSName)))
2742 0 : pszGeogName = CPLStrdup(szGCSName);
2743 : else
2744 : {
2745 10 : GTIFGetGCSInfo(psDefnIn->GCS, &pszGeogName, nullptr, nullptr, nullptr);
2746 10 : GTIFToCPLRecycleString(&pszGeogName);
2747 : }
2748 10 : GTIFGetDatumInfo(psDefnIn->Datum, &pszDatumName, nullptr);
2749 10 : GTIFToCPLRecycleString(&pszDatumName);
2750 10 : GTIFGetPMInfo(psDefnIn->PM, &pszPMName, nullptr);
2751 10 : GTIFToCPLRecycleString(&pszPMName);
2752 10 : GTIFGetEllipsoidInfo(psDefnIn->Ellipsoid, &pszSpheroidName, nullptr,
2753 : nullptr);
2754 10 : GTIFToCPLRecycleString(&pszSpheroidName);
2755 :
2756 10 : GTIFGetUOMAngleInfo(psDefnIn->UOMAngle, &pszAngularUnits, nullptr);
2757 10 : GTIFToCPLRecycleString(&pszAngularUnits);
2758 10 : if (pszAngularUnits == nullptr)
2759 0 : pszAngularUnits = CPLStrdup("unknown");
2760 :
2761 10 : if (pszDatumName != nullptr)
2762 10 : WKTMassageDatum(&pszDatumName);
2763 :
2764 10 : dfSemiMajor = psDefnIn->SemiMajor;
2765 10 : if (psDefnIn->SemiMajor == 0.0)
2766 : {
2767 0 : CPLFree(pszSpheroidName);
2768 0 : pszSpheroidName = CPLStrdup("unretrievable - using WGS84");
2769 0 : dfSemiMajor = SRS_WGS84_SEMIMAJOR;
2770 0 : dfInvFlattening = SRS_WGS84_INVFLATTENING;
2771 : }
2772 : else
2773 : dfInvFlattening =
2774 10 : OSRCalcInvFlattening(psDefnIn->SemiMajor, psDefnIn->SemiMinor);
2775 :
2776 10 : oSRS.SetGeogCS(pszGeogName, pszDatumName, pszSpheroidName, dfSemiMajor,
2777 : dfInvFlattening, pszPMName,
2778 10 : psDefnIn->PMLongToGreenwich / psDefnIn->UOMAngleInDegrees,
2779 : pszAngularUnits,
2780 10 : psDefnIn->UOMAngleInDegrees * 0.0174532925199433);
2781 :
2782 10 : if (psDefnIn->GCS != KvUserDefined)
2783 10 : oSRS.SetAuthority("GEOGCS", "EPSG", psDefnIn->GCS);
2784 :
2785 10 : if (psDefnIn->Datum != KvUserDefined)
2786 10 : oSRS.SetAuthority("DATUM", "EPSG", psDefnIn->Datum);
2787 :
2788 10 : if (psDefnIn->Ellipsoid != KvUserDefined)
2789 10 : oSRS.SetAuthority("SPHEROID", "EPSG", psDefnIn->Ellipsoid);
2790 :
2791 10 : CPLFree(pszGeogName);
2792 10 : CPLFree(pszDatumName);
2793 10 : CPLFree(pszPMName);
2794 10 : CPLFree(pszSpheroidName);
2795 10 : CPLFree(pszAngularUnits);
2796 :
2797 : /* ==================================================================== */
2798 : /* Handle projection parameters. */
2799 : /* ==================================================================== */
2800 10 : if (psDefnIn->Model == ModelTypeProjected)
2801 : {
2802 : /* --------------------------------------------------------------------
2803 : */
2804 : /* Make a local copy of params, and convert back into the */
2805 : /* angular units of the GEOGCS and the linear units of the */
2806 : /* projection. */
2807 : /* --------------------------------------------------------------------
2808 : */
2809 : double adfParam[10];
2810 : int i;
2811 :
2812 80 : for (i = 0; i < std::min(10, psDefnIn->nParms); i++)
2813 70 : adfParam[i] = psDefnIn->ProjParm[i];
2814 40 : for (; i < 10; i++)
2815 30 : adfParam[i] = 0;
2816 :
2817 10 : adfParam[0] /= psDefnIn->UOMAngleInDegrees;
2818 10 : adfParam[1] /= psDefnIn->UOMAngleInDegrees;
2819 10 : adfParam[2] /= psDefnIn->UOMAngleInDegrees;
2820 10 : adfParam[3] /= psDefnIn->UOMAngleInDegrees;
2821 :
2822 10 : adfParam[5] /= psDefnIn->UOMLengthInMeters;
2823 10 : adfParam[6] /= psDefnIn->UOMLengthInMeters;
2824 :
2825 : /* --------------------------------------------------------------------
2826 : */
2827 : /* Translation the fundamental projection. */
2828 : /* --------------------------------------------------------------------
2829 : */
2830 10 : switch (psDefnIn->CTProjection)
2831 : {
2832 0 : case CT_TransverseMercator:
2833 0 : oSRS.SetTM(adfParam[0], adfParam[1], adfParam[4], adfParam[5],
2834 : adfParam[6]);
2835 0 : break;
2836 :
2837 0 : case CT_TransvMercator_SouthOriented:
2838 0 : oSRS.SetTMSO(adfParam[0], adfParam[1], adfParam[4], adfParam[5],
2839 : adfParam[6]);
2840 0 : break;
2841 :
2842 10 : case CT_Mercator:
2843 10 : oSRS.SetMercator(adfParam[0], adfParam[1], adfParam[4],
2844 : adfParam[5], adfParam[6]);
2845 10 : break;
2846 :
2847 0 : case CT_ObliqueStereographic:
2848 0 : oSRS.SetOS(adfParam[0], adfParam[1], adfParam[4], adfParam[5],
2849 : adfParam[6]);
2850 0 : break;
2851 :
2852 0 : case CT_Stereographic:
2853 0 : oSRS.SetOS(adfParam[0], adfParam[1], adfParam[4], adfParam[5],
2854 : adfParam[6]);
2855 0 : break;
2856 :
2857 0 : case CT_ObliqueMercator: /* hotine */
2858 0 : oSRS.SetHOM(adfParam[0], adfParam[1], adfParam[2], adfParam[3],
2859 : adfParam[4], adfParam[5], adfParam[6]);
2860 0 : break;
2861 :
2862 0 : case CT_EquidistantConic:
2863 0 : oSRS.SetEC(adfParam[0], adfParam[1], adfParam[2], adfParam[3],
2864 : adfParam[5], adfParam[6]);
2865 0 : break;
2866 :
2867 0 : case CT_CassiniSoldner:
2868 0 : oSRS.SetCS(adfParam[0], adfParam[1], adfParam[5], adfParam[6]);
2869 0 : break;
2870 :
2871 0 : case CT_Polyconic:
2872 0 : oSRS.SetPolyconic(adfParam[0], adfParam[1], adfParam[5],
2873 : adfParam[6]);
2874 0 : break;
2875 :
2876 0 : case CT_AzimuthalEquidistant:
2877 0 : oSRS.SetAE(adfParam[0], adfParam[1], adfParam[5], adfParam[6]);
2878 0 : break;
2879 :
2880 0 : case CT_MillerCylindrical:
2881 0 : oSRS.SetMC(adfParam[0], adfParam[1], adfParam[5], adfParam[6]);
2882 0 : break;
2883 :
2884 0 : case CT_Equirectangular:
2885 0 : oSRS.SetEquirectangular(adfParam[0], adfParam[1], adfParam[5],
2886 : adfParam[6]);
2887 0 : break;
2888 :
2889 0 : case CT_Gnomonic:
2890 0 : oSRS.SetGnomonic(adfParam[0], adfParam[1], adfParam[5],
2891 : adfParam[6]);
2892 0 : break;
2893 :
2894 0 : case CT_LambertAzimEqualArea:
2895 0 : oSRS.SetLAEA(adfParam[0], adfParam[1], adfParam[5],
2896 : adfParam[6]);
2897 0 : break;
2898 :
2899 0 : case CT_Orthographic:
2900 0 : oSRS.SetOrthographic(adfParam[0], adfParam[1], adfParam[5],
2901 : adfParam[6]);
2902 0 : break;
2903 :
2904 0 : case CT_Robinson:
2905 0 : oSRS.SetRobinson(adfParam[1], adfParam[5], adfParam[6]);
2906 0 : break;
2907 :
2908 0 : case CT_Sinusoidal:
2909 0 : oSRS.SetSinusoidal(adfParam[1], adfParam[5], adfParam[6]);
2910 0 : break;
2911 :
2912 0 : case CT_VanDerGrinten:
2913 0 : oSRS.SetVDG(adfParam[1], adfParam[5], adfParam[6]);
2914 0 : break;
2915 :
2916 0 : case CT_PolarStereographic:
2917 0 : oSRS.SetPS(adfParam[0], adfParam[1], adfParam[4], adfParam[5],
2918 : adfParam[6]);
2919 0 : break;
2920 :
2921 0 : case CT_LambertConfConic_2SP:
2922 0 : oSRS.SetLCC(adfParam[2], adfParam[3], adfParam[0], adfParam[1],
2923 : adfParam[5], adfParam[6]);
2924 0 : break;
2925 :
2926 0 : case CT_LambertConfConic_1SP:
2927 0 : oSRS.SetLCC1SP(adfParam[0], adfParam[1], adfParam[4],
2928 : adfParam[5], adfParam[6]);
2929 0 : break;
2930 :
2931 0 : case CT_AlbersEqualArea:
2932 0 : oSRS.SetACEA(adfParam[0], adfParam[1], adfParam[2], adfParam[3],
2933 : adfParam[5], adfParam[6]);
2934 0 : break;
2935 :
2936 0 : case CT_NewZealandMapGrid:
2937 0 : oSRS.SetNZMG(adfParam[0], adfParam[1], adfParam[5],
2938 : adfParam[6]);
2939 0 : break;
2940 : }
2941 :
2942 : /* --------------------------------------------------------------------
2943 : */
2944 : /* Set projection units. */
2945 : /* --------------------------------------------------------------------
2946 : */
2947 10 : char *pszUnitsName = nullptr;
2948 :
2949 10 : GTIFGetUOMLengthInfo(psDefnIn->UOMLength, &pszUnitsName, nullptr);
2950 :
2951 10 : if (pszUnitsName != nullptr && psDefnIn->UOMLength != KvUserDefined)
2952 : {
2953 10 : oSRS.SetLinearUnits(pszUnitsName, psDefnIn->UOMLengthInMeters);
2954 10 : oSRS.SetAuthority("PROJCS|UNIT", "EPSG", psDefnIn->UOMLength);
2955 : }
2956 : else
2957 0 : oSRS.SetLinearUnits("unknown", psDefnIn->UOMLengthInMeters);
2958 :
2959 10 : GTIFFreeMemory(pszUnitsName);
2960 : }
2961 :
2962 : /* -------------------------------------------------------------------- */
2963 : /* Return the WKT serialization of the object. */
2964 : /* -------------------------------------------------------------------- */
2965 :
2966 10 : char *pszWKT = nullptr;
2967 10 : if (oSRS.exportToWkt(&pszWKT) == OGRERR_NONE)
2968 10 : return pszWKT;
2969 : else
2970 : {
2971 0 : CPLFree(pszWKT);
2972 0 : return nullptr;
2973 : }
2974 : }
2975 :
2976 : #ifdef MRSID_ESDK
2977 :
2978 : /************************************************************************/
2979 : /* ==================================================================== */
2980 : /* MrSIDDummyImageReader */
2981 : /* */
2982 : /* This is a helper class to wrap GDAL calls in MrSID interface. */
2983 : /* ==================================================================== */
2984 : /************************************************************************/
2985 :
2986 : class MrSIDDummyImageReader : public LTIImageReader
2987 : {
2988 : public:
2989 : MrSIDDummyImageReader(GDALDataset *poSrcDS);
2990 : ~MrSIDDummyImageReader();
2991 : LT_STATUS initialize();
2992 :
2993 : lt_int64 getPhysicalFileSize(void) const
2994 : {
2995 : return 0;
2996 : };
2997 :
2998 : private:
2999 : GDALDataset *poDS;
3000 : GDALDataType eDataType;
3001 : LTIDataType eSampleType;
3002 : const LTIPixel *poPixel;
3003 :
3004 : GDALGeoTransform m_gt{};
3005 :
3006 : virtual LT_STATUS decodeStrip(LTISceneBuffer &stripBuffer,
3007 : const LTIScene &stripScene);
3008 :
3009 : virtual LT_STATUS decodeBegin(const LTIScene &)
3010 : {
3011 : return LT_STS_Success;
3012 : };
3013 :
3014 : virtual LT_STATUS decodeEnd()
3015 : {
3016 : return LT_STS_Success;
3017 : };
3018 : };
3019 :
3020 : /************************************************************************/
3021 : /* MrSIDDummyImageReader() */
3022 : /************************************************************************/
3023 :
3024 : MrSIDDummyImageReader::MrSIDDummyImageReader(GDALDataset *poSrcDS)
3025 : : LTIImageReader(), poDS(poSrcDS)
3026 : {
3027 : poPixel = nullptr;
3028 : }
3029 :
3030 : /************************************************************************/
3031 : /* ~MrSIDDummyImageReader() */
3032 : /************************************************************************/
3033 :
3034 : MrSIDDummyImageReader::~MrSIDDummyImageReader()
3035 : {
3036 : if (poPixel)
3037 : delete poPixel;
3038 : }
3039 :
3040 : /************************************************************************/
3041 : /* initialize() */
3042 : /************************************************************************/
3043 :
3044 : LT_STATUS MrSIDDummyImageReader::initialize()
3045 : {
3046 : LT_STATUS eStat = LT_STS_Uninit;
3047 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
3048 : if (!LT_SUCCESS(eStat = LTIImageReader::init()))
3049 : return eStat;
3050 : #else
3051 : if (!LT_SUCCESS(eStat = LTIImageReader::initialize()))
3052 : return eStat;
3053 : #endif
3054 :
3055 : lt_uint16 nBands = (lt_uint16)poDS->GetRasterCount();
3056 : LTIColorSpace eColorSpace = LTI_COLORSPACE_RGB;
3057 : switch (nBands)
3058 : {
3059 : case 1:
3060 : eColorSpace = LTI_COLORSPACE_GRAYSCALE;
3061 : break;
3062 : case 3:
3063 : eColorSpace = LTI_COLORSPACE_RGB;
3064 : break;
3065 : default:
3066 : eColorSpace = LTI_COLORSPACE_MULTISPECTRAL;
3067 : break;
3068 : }
3069 :
3070 : eDataType = poDS->GetRasterBand(1)->GetRasterDataType();
3071 : switch (eDataType)
3072 : {
3073 : case GDT_UInt16:
3074 : eSampleType = LTI_DATATYPE_UINT16;
3075 : break;
3076 : case GDT_Int16:
3077 : eSampleType = LTI_DATATYPE_SINT16;
3078 : break;
3079 : case GDT_UInt32:
3080 : eSampleType = LTI_DATATYPE_UINT32;
3081 : break;
3082 : case GDT_Int32:
3083 : eSampleType = LTI_DATATYPE_SINT32;
3084 : break;
3085 : case GDT_Float32:
3086 : eSampleType = LTI_DATATYPE_FLOAT32;
3087 : break;
3088 : case GDT_Float64:
3089 : eSampleType = LTI_DATATYPE_FLOAT64;
3090 : break;
3091 : case GDT_UInt8:
3092 : default:
3093 : eSampleType = LTI_DATATYPE_UINT8;
3094 : break;
3095 : }
3096 :
3097 : poPixel = new LTIDLLPixel<LTIPixel>(eColorSpace, nBands, eSampleType);
3098 : if (!LT_SUCCESS(setPixelProps(*poPixel)))
3099 : return LT_STS_Failure;
3100 :
3101 : if (!LT_SUCCESS(
3102 : setDimensions(poDS->GetRasterXSize(), poDS->GetRasterYSize())))
3103 : return LT_STS_Failure;
3104 :
3105 : if (poDS->GetGeoTransform(m_gt) == CE_None)
3106 : {
3107 : #ifdef MRSID_SDK_40
3108 : LTIGeoCoord oGeo(m_gt.xorig + m_gt.xscale / 2,
3109 : m_gt.yorig + m_gt.yscale / 2, m_gt.xscale, m_gt.yscale,
3110 : m_gt.xrot, m_gt.yrot, nullptr,
3111 : poDS->GetProjectionRef());
3112 : #else
3113 : LTIGeoCoord oGeo(m_gt.xorig + m_gt.xscale / 2,
3114 : m_gt.yorig + m_gt.yscale / 2, m_gt.xscale, m_gt.yscale,
3115 : m_gt.xrot, m_gt.yrot, poDS->GetProjectionRef());
3116 : #endif
3117 : if (!LT_SUCCESS(setGeoCoord(oGeo)))
3118 : return LT_STS_Failure;
3119 : }
3120 :
3121 : /*int bSuccess;
3122 : double dfNoDataValue = poDS->GetNoDataValue( &bSuccess );
3123 : if ( bSuccess )
3124 : {
3125 : LTIPixel oNoDataPixel( *poPixel );
3126 : lt_uint16 iBand;
3127 :
3128 : for (iBand = 0; iBand < (lt_uint16)poDS->GetRasterCount(); iBand++)
3129 : oNoDataPixel.setSampleValueFloat32( iBand, dfNoDataValue );
3130 : if ( !LT_SUCCESS(setNoDataPixel( &oNoDataPixel )) )
3131 : return LT_STS_Failure;
3132 : }*/
3133 :
3134 : setDefaultDynamicRange();
3135 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3136 : setClassicalMetadata();
3137 : #endif
3138 :
3139 : return LT_STS_Success;
3140 : }
3141 :
3142 : /************************************************************************/
3143 : /* decodeStrip() */
3144 : /************************************************************************/
3145 :
3146 : LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer &stripData,
3147 : const LTIScene &stripScene)
3148 :
3149 : {
3150 : const lt_int32 nXOff = stripScene.getUpperLeftCol();
3151 : const lt_int32 nYOff = stripScene.getUpperLeftRow();
3152 : const lt_int32 nBufXSize = stripScene.getNumCols();
3153 : const lt_int32 nBufYSize = stripScene.getNumRows();
3154 : const lt_int32 nDataBufXSize = stripData.getTotalNumCols();
3155 : const lt_int32 nDataBufYSize = stripData.getTotalNumRows();
3156 : const lt_uint16 nBands = poPixel->getNumBands();
3157 :
3158 : void *pData =
3159 : CPLMalloc(nDataBufXSize * nDataBufYSize * poPixel->getNumBytes());
3160 : if (!pData)
3161 : {
3162 : CPLError(CE_Failure, CPLE_AppDefined,
3163 : "MrSIDDummyImageReader::decodeStrip(): "
3164 : "Cannot allocate enough space for scene buffer");
3165 : return LT_STS_Failure;
3166 : }
3167 :
3168 : poDS->RasterIO(GF_Read, nXOff, nYOff, nBufXSize, nBufYSize, pData,
3169 : nBufXSize, nBufYSize, eDataType, nBands, nullptr, 0, 0, 0,
3170 : nullptr);
3171 :
3172 : stripData.importDataBSQ(pData);
3173 : CPLFree(pData);
3174 : return LT_STS_Success;
3175 : }
3176 :
3177 : /************************************************************************/
3178 : /* MrSIDCreateCopy() */
3179 : /************************************************************************/
3180 :
3181 : static GDALDataset *MrSIDCreateCopy(const char *pszFilename,
3182 : GDALDataset *poSrcDS, int bStrict,
3183 : CSLConstList papszOptions,
3184 : GDALProgressFunc pfnProgress,
3185 : void *pProgressData)
3186 :
3187 : {
3188 : const char *pszVersion = CSLFetchNameValue(papszOptions, "VERSION");
3189 : #ifdef MRSID_HAVE_MG4WRITE
3190 : int iVersion = pszVersion ? atoi(pszVersion) : 4;
3191 : #else
3192 : int iVersion = pszVersion ? atoi(pszVersion) : 3;
3193 : #endif
3194 : LT_STATUS eStat = LT_STS_Uninit;
3195 :
3196 : #ifdef DEBUG
3197 : bool bMeter = false;
3198 : #else
3199 : bool bMeter = true;
3200 : #endif
3201 :
3202 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr)
3203 : {
3204 : CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3205 : "MrSID driver ignores color table. "
3206 : "The source raster band will be considered as grey level.\n"
3207 : "Consider using color table expansion (-expand option in "
3208 : "gdal_translate)");
3209 : if (bStrict)
3210 : return nullptr;
3211 : }
3212 :
3213 : MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
3214 : if (LT_FAILURE(eStat = oProgressDelegate.setProgressStatus(0)))
3215 : {
3216 : CPLError(CE_Failure, CPLE_AppDefined,
3217 : "MrSIDProgress.setProgressStatus failed.\n%s",
3218 : getLastStatusString(eStat));
3219 : return nullptr;
3220 : }
3221 :
3222 : // Create the file.
3223 : MrSIDDummyImageReader oImageReader(poSrcDS);
3224 : if (LT_FAILURE(eStat = oImageReader.initialize()))
3225 : {
3226 : CPLError(CE_Failure, CPLE_AppDefined,
3227 : "MrSIDDummyImageReader.Initialize failed.\n%s",
3228 : getLastStatusString(eStat));
3229 : return nullptr;
3230 : }
3231 :
3232 : LTIGeoFileImageWriter *poImageWriter = nullptr;
3233 : switch (iVersion)
3234 : {
3235 : case 2:
3236 : {
3237 : // Output Mrsid Version 2 file.
3238 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3239 : LTIDLLDefault<MG2ImageWriter> *poMG2ImageWriter;
3240 : poMG2ImageWriter = new LTIDLLDefault<MG2ImageWriter>;
3241 : eStat = poMG2ImageWriter->initialize(&oImageReader);
3242 : #else
3243 : LTIDLLWriter<MG2ImageWriter> *poMG2ImageWriter;
3244 : poMG2ImageWriter = new LTIDLLWriter<MG2ImageWriter>(&oImageReader);
3245 : eStat = poMG2ImageWriter->initialize();
3246 : #endif
3247 : if (LT_FAILURE(eStat))
3248 : {
3249 : delete poMG2ImageWriter;
3250 : CPLError(CE_Failure, CPLE_AppDefined,
3251 : "MG2ImageWriter.initialize() failed.\n%s",
3252 : getLastStatusString(eStat));
3253 : return nullptr;
3254 : }
3255 :
3256 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3257 : eStat = poMG2ImageWriter->setEncodingApplication(
3258 : "MrSID Driver", GDALVersionInfo("--version"));
3259 : if (LT_FAILURE(eStat))
3260 : {
3261 : delete poMG2ImageWriter;
3262 : CPLError(CE_Failure, CPLE_AppDefined,
3263 : "MG2ImageWriter.setEncodingApplication() failed.\n%s",
3264 : getLastStatusString(eStat));
3265 : return nullptr;
3266 : }
3267 : #endif
3268 :
3269 : poMG2ImageWriter->setUsageMeterEnabled(bMeter);
3270 :
3271 : poMG2ImageWriter->params().setBlockSize(
3272 : poMG2ImageWriter->params().getBlockSize());
3273 :
3274 : // check for compression option
3275 : const char *pszValue =
3276 : CSLFetchNameValue(papszOptions, GDALMD_COMPRESSION);
3277 : if (pszValue != nullptr)
3278 : poMG2ImageWriter->params().setCompressionRatio(
3279 : (float)CPLAtof(pszValue));
3280 :
3281 : poImageWriter = poMG2ImageWriter;
3282 :
3283 : break;
3284 : }
3285 : case 3:
3286 : {
3287 : // Output Mrsid Version 3 file.
3288 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3289 : LTIDLLDefault<MG3ImageWriter> *poMG3ImageWriter;
3290 : poMG3ImageWriter = new LTIDLLDefault<MG3ImageWriter>;
3291 : eStat = poMG3ImageWriter->initialize(&oImageReader);
3292 : #else
3293 : LTIDLLWriter<MG3ImageWriter> *poMG3ImageWriter;
3294 : poMG3ImageWriter = new LTIDLLWriter<MG3ImageWriter>(&oImageReader);
3295 : eStat = poMG3ImageWriter->initialize();
3296 : #endif
3297 : if (LT_FAILURE(eStat))
3298 : {
3299 : delete poMG3ImageWriter;
3300 : CPLError(CE_Failure, CPLE_AppDefined,
3301 : "MG3ImageWriter.initialize() failed.\n%s",
3302 : getLastStatusString(eStat));
3303 : return nullptr;
3304 : }
3305 :
3306 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3307 : eStat = poMG3ImageWriter->setEncodingApplication(
3308 : "MrSID Driver", GDALVersionInfo("--version"));
3309 : if (LT_FAILURE(eStat))
3310 : {
3311 : delete poMG3ImageWriter;
3312 : CPLError(CE_Failure, CPLE_AppDefined,
3313 : "MG3ImageWriter.setEncodingApplication() failed.\n%s",
3314 : getLastStatusString(eStat));
3315 : return nullptr;
3316 : }
3317 : #endif
3318 :
3319 : // usage meter should only be disabled for debugging
3320 : poMG3ImageWriter->setUsageMeterEnabled(bMeter);
3321 :
3322 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3323 : // Set 64-bit Interface for large files.
3324 : poMG3ImageWriter->setFileStream64(true);
3325 : #endif
3326 :
3327 : // set 2 pass optimizer option
3328 : if (CSLFetchNameValue(papszOptions, "TWOPASS") != nullptr)
3329 : poMG3ImageWriter->params().setTwoPassOptimizer(true);
3330 :
3331 : // set filesize in KB
3332 : const char *pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
3333 : if (pszValue != nullptr)
3334 : poMG3ImageWriter->params().setTargetFilesize(atoi(pszValue));
3335 :
3336 : poImageWriter = poMG3ImageWriter;
3337 :
3338 : break;
3339 : }
3340 : #ifdef MRSID_HAVE_MG4WRITE
3341 : case 4:
3342 : {
3343 : // Output Mrsid Version 4 file.
3344 : LTIDLLDefault<MG4ImageWriter> *poMG4ImageWriter;
3345 : poMG4ImageWriter = new LTIDLLDefault<MG4ImageWriter>;
3346 : eStat =
3347 : poMG4ImageWriter->initialize(&oImageReader, nullptr, nullptr);
3348 : if (LT_FAILURE(eStat))
3349 : {
3350 : delete poMG4ImageWriter;
3351 : CPLError(CE_Failure, CPLE_AppDefined,
3352 : "MG3ImageWriter.initialize() failed.\n%s",
3353 : getLastStatusString(eStat));
3354 : return nullptr;
3355 : }
3356 :
3357 : eStat = poMG4ImageWriter->setEncodingApplication(
3358 : "MrSID Driver", GDALVersionInfo("--version"));
3359 : if (LT_FAILURE(eStat))
3360 : {
3361 : delete poMG4ImageWriter;
3362 : CPLError(CE_Failure, CPLE_AppDefined,
3363 : "MG3ImageWriter.setEncodingApplication() failed.\n%s",
3364 : getLastStatusString(eStat));
3365 : return nullptr;
3366 : }
3367 :
3368 : // usage meter should only be disabled for debugging
3369 : poMG4ImageWriter->setUsageMeterEnabled(bMeter);
3370 :
3371 : // set 2 pass optimizer option
3372 : if (CSLFetchNameValue(papszOptions, "TWOPASS") != nullptr)
3373 : poMG4ImageWriter->params().setTwoPassOptimizer(true);
3374 :
3375 : // set filesize in KB
3376 : const char *pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
3377 : if (pszValue != nullptr)
3378 : poMG4ImageWriter->params().setTargetFilesize(atoi(pszValue));
3379 :
3380 : poImageWriter = poMG4ImageWriter;
3381 :
3382 : break;
3383 : }
3384 : #endif /* MRSID_HAVE_MG4WRITE */
3385 : default:
3386 : CPLError(CE_Failure, CPLE_AppDefined,
3387 : "Invalid MrSID generation specified (VERSION=%s).",
3388 : pszVersion);
3389 : return nullptr;
3390 : }
3391 :
3392 : // set output filename
3393 : poImageWriter->setOutputFileSpec(pszFilename);
3394 :
3395 : // set progress delegate
3396 : poImageWriter->setProgressDelegate(&oProgressDelegate);
3397 :
3398 : // set defaults
3399 : poImageWriter->setStripHeight(poImageWriter->getStripHeight());
3400 :
3401 : // set MrSID world file
3402 : if (CSLFetchNameValue(papszOptions, "WORLDFILE") != nullptr)
3403 : poImageWriter->setWorldFileSupport(true);
3404 :
3405 : // write the scene
3406 : int nXSize = poSrcDS->GetRasterXSize();
3407 : int nYSize = poSrcDS->GetRasterYSize();
3408 : const LTIScene oScene(0, 0, nXSize, nYSize, 1.0);
3409 : if (LT_FAILURE(eStat = poImageWriter->write(oScene)))
3410 : {
3411 : delete poImageWriter;
3412 : CPLError(CE_Failure, CPLE_AppDefined,
3413 : "MG2ImageWriter.write() failed.\n%s",
3414 : getLastStatusString(eStat));
3415 : return nullptr;
3416 : }
3417 :
3418 : delete poImageWriter;
3419 : /* -------------------------------------------------------------------- */
3420 : /* Re-open dataset, and copy any auxiliary pam information. */
3421 : /* -------------------------------------------------------------------- */
3422 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
3423 : GDALPamDataset *poDS = OpenPAM(&oOpenInfo, /* bIsJP2 = */ false);
3424 :
3425 : if (poDS)
3426 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
3427 :
3428 : return poDS;
3429 : }
3430 :
3431 : #ifdef MRSID_J2K
3432 : /************************************************************************/
3433 : /* JP2CreateCopy() */
3434 : /************************************************************************/
3435 :
3436 : static GDALDataset *JP2CreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
3437 : int bStrict, CSLConstList papszOptions,
3438 : GDALProgressFunc pfnProgress,
3439 : void *pProgressData)
3440 :
3441 : {
3442 : #ifdef DEBUG
3443 : bool bMeter = false;
3444 : #else
3445 : bool bMeter = true;
3446 : #endif
3447 :
3448 : int nXSize = poSrcDS->GetRasterXSize();
3449 : int nYSize = poSrcDS->GetRasterYSize();
3450 : LT_STATUS eStat;
3451 :
3452 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != nullptr)
3453 : {
3454 : CPLError((bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3455 : "MrSID driver ignores color table. "
3456 : "The source raster band will be considered as grey level.\n"
3457 : "Consider using color table expansion (-expand option in "
3458 : "gdal_translate)");
3459 : if (bStrict)
3460 : return nullptr;
3461 : }
3462 :
3463 : MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
3464 : if (LT_FAILURE(eStat = oProgressDelegate.setProgressStatus(0)))
3465 : {
3466 : CPLError(CE_Failure, CPLE_AppDefined,
3467 : "MrSIDProgress.setProgressStatus failed.\n%s",
3468 : getLastStatusString(eStat));
3469 : return nullptr;
3470 : }
3471 :
3472 : // Create the file.
3473 : MrSIDDummyImageReader oImageReader(poSrcDS);
3474 : eStat = oImageReader.initialize();
3475 : if (eStat != LT_STS_Success)
3476 : {
3477 : CPLError(CE_Failure, CPLE_AppDefined,
3478 : "MrSIDDummyImageReader.Initialize failed.\n%s",
3479 : getLastStatusString(eStat));
3480 : return nullptr;
3481 : }
3482 :
3483 : #if !defined(MRSID_POST5)
3484 : J2KImageWriter oImageWriter(&oImageReader);
3485 : eStat = oImageWriter.initialize();
3486 : #elif !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3487 : JP2WriterManager oImageWriter(&oImageReader);
3488 : eStat = oImageWriter.initialize();
3489 : #else
3490 : JP2WriterManager oImageWriter;
3491 : eStat = oImageWriter.initialize(&oImageReader);
3492 : #endif
3493 : if (eStat != LT_STS_Success)
3494 : {
3495 : CPLError(CE_Failure, CPLE_AppDefined,
3496 : "J2KImageWriter.Initialize failed.\n%s",
3497 : getLastStatusString(eStat));
3498 : return nullptr;
3499 : }
3500 :
3501 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3502 : // Set 64-bit Interface for large files.
3503 : oImageWriter.setFileStream64(true);
3504 : #endif
3505 :
3506 : oImageWriter.setUsageMeterEnabled(bMeter);
3507 :
3508 : // set output filename
3509 : oImageWriter.setOutputFileSpec(pszFilename);
3510 :
3511 : // set progress delegate
3512 : oImageWriter.setProgressDelegate(&oProgressDelegate);
3513 :
3514 : // Set defaults
3515 : // oImageWriter.setStripHeight(oImageWriter.getStripHeight());
3516 :
3517 : // set MrSID world file
3518 : if (CSLFetchNameValue(papszOptions, "WORLDFILE") != nullptr)
3519 : oImageWriter.setWorldFileSupport(true);
3520 :
3521 : // check for compression option
3522 : const char *pszValue = CSLFetchNameValue(papszOptions, GDALMD_COMPRESSION);
3523 : if (pszValue != nullptr)
3524 : oImageWriter.params().setCompressionRatio((float)CPLAtof(pszValue));
3525 :
3526 : pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
3527 : if (pszValue != nullptr)
3528 : {
3529 : LTFileSpec xmlprofile(pszValue);
3530 : eStat = oImageWriter.params().readProfile(xmlprofile);
3531 : if (eStat != LT_STS_Success)
3532 : {
3533 : CPLError(CE_Failure, CPLE_AppDefined,
3534 : "JPCWriterParams.readProfile failed.\n%s",
3535 : getLastStatusString(eStat));
3536 : return nullptr;
3537 : }
3538 : }
3539 :
3540 : // write the scene
3541 : const LTIScene oScene(0, 0, nXSize, nYSize, 1.0);
3542 : eStat = oImageWriter.write(oScene);
3543 : if (eStat != LT_STS_Success)
3544 : {
3545 : CPLError(CE_Failure, CPLE_AppDefined,
3546 : "J2KImageWriter.write() failed.\n%s",
3547 : getLastStatusString(eStat));
3548 : return nullptr;
3549 : }
3550 :
3551 : /* -------------------------------------------------------------------- */
3552 : /* Re-open dataset, and copy any auxiliary pam information. */
3553 : /* -------------------------------------------------------------------- */
3554 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
3555 : GDALPamDataset *poDS = OpenPAM(&oOpenInfo, /* bIsJP2 = */ true);
3556 :
3557 : if (poDS)
3558 : poDS->CloneInfo(poSrcDS, GCIF_PAM_DEFAULT);
3559 :
3560 : return poDS;
3561 : }
3562 : #endif /* MRSID_J2K */
3563 : #endif /* MRSID_ESDK */
3564 :
3565 : /************************************************************************/
3566 : /* GDALRegister_MrSID() */
3567 : /************************************************************************/
3568 :
3569 2135 : void GDALRegister_MrSID()
3570 :
3571 : {
3572 2135 : if (!GDAL_CHECK_VERSION("MrSID driver"))
3573 0 : return;
3574 :
3575 : /* -------------------------------------------------------------------- */
3576 : /* MrSID driver. */
3577 : /* -------------------------------------------------------------------- */
3578 2135 : if (GDALGetDriverByName(MRSID_DRIVER_NAME) != nullptr)
3579 263 : return;
3580 :
3581 1872 : GDALDriver *poDriver = new GDALDriver();
3582 1872 : MrSIDDriverSetCommonMetadata(poDriver);
3583 : #ifdef MRSID_ESDK
3584 : poDriver->pfnCreateCopy = MrSIDCreateCopy;
3585 : #endif
3586 1872 : poDriver->pfnOpen = MrSIDOpen;
3587 :
3588 1872 : GetGDALDriverManager()->RegisterDriver(poDriver);
3589 :
3590 : /* -------------------------------------------------------------------- */
3591 : /* JP2MRSID driver. */
3592 : /* -------------------------------------------------------------------- */
3593 : #ifdef MRSID_J2K
3594 : poDriver = new GDALDriver();
3595 : JP2MrSIDDriverSetCommonMetadata(poDriver);
3596 : #ifdef MRSID_ESDK
3597 : poDriver->pfnCreateCopy = JP2CreateCopy;
3598 : #endif
3599 : poDriver->pfnOpen = JP2Open;
3600 :
3601 : GetGDALDriverManager()->RegisterDriver(poDriver);
3602 : #endif /* def MRSID_J2K */
3603 : }
3604 :
3605 : #if defined(MRSID_USE_TIFFSYMS_WORKAROUND)
3606 : extern "C"
3607 : {
3608 :
3609 : /* This is not pretty but I am not sure how else to get the plugin to build
3610 : * against the ESDK. ESDK symbol dependencies bring in __TIFFmemcpy and
3611 : * __gtiff_size, which are not exported from gdal.dll. Rather than link
3612 : * these symbols from the ESDK distribution of GDAL, or link in the entire
3613 : * gdal.lib statically, it seemed safer and smaller to bring in just the
3614 : * objects that wouldsatisfy these symbols from the enclosing GDAL build.
3615 : * However, doing so pulls in a few more dependencies. /Gy and /OPT:REF did
3616 : * not seem to help things, so I have implemented no-op versions of these
3617 : * symbols since they do not actually get called. If the MrSID ESDK ever
3618 : * comes to require the actual versions of these functions, we'll hope
3619 : * duplicate symbol errors will bring attention back to this problem.
3620 : */
3621 : void TIFFClientOpen()
3622 : {
3623 : }
3624 :
3625 : void TIFFError()
3626 : {
3627 : }
3628 :
3629 : void TIFFGetField()
3630 : {
3631 : }
3632 :
3633 : void TIFFSetField()
3634 : {
3635 : }
3636 : }
3637 : #endif
|