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