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