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