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