1 : /******************************************************************************
2 : * $Id: mrsiddataset.cpp 24375 2012-05-03 17:46:08Z 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 24375 2012-05-03 17:46:08Z 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 226 : LTIDLLPixel(LTIColorSpace colorSpace,
121 : lt_uint16 numBands,
122 226 : LTIDataType dataType) : T(colorSpace,numBands,dataType) {}
123 226 : 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 142 : LTIDLLNavigator(const LTIImage& image ) : T(image) {}
144 142 : 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 27 : LTIDLLCopy(const T& original) : T(original) {}
163 27 : 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 226 : MrSIDRasterBand::MrSIDRasterBand( MrSIDDataset *poDS, int nBand )
341 : {
342 226 : this->poDS = poDS;
343 226 : poGDS = poDS;
344 226 : this->nBand = nBand;
345 226 : this->eDataType = poDS->eDataType;
346 :
347 : /* -------------------------------------------------------------------- */
348 : /* Set the block sizes and buffer parameters. */
349 : /* -------------------------------------------------------------------- */
350 226 : nBlockXSize = poDS->nBlockXSize;
351 226 : nBlockYSize = poDS->nBlockYSize;
352 : //#ifdef notdef
353 226 : if( poDS->GetRasterXSize() > 2048 )
354 6 : nBlockXSize = 1024;
355 226 : if( poDS->GetRasterYSize() > 128 )
356 87 : nBlockYSize = 128;
357 : else
358 139 : nBlockYSize = poDS->GetRasterYSize();
359 : //#endif
360 :
361 226 : nBlockSize = nBlockXSize * nBlockYSize;
362 : poPixel = new LTIDLLPixel<LTIPixel>( poDS->eColorSpace, poDS->nBands,
363 226 : 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 226 : dfNoDataValue = 0.0;
419 226 : bNoDataSet = FALSE;
420 : }
421 :
422 226 : 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 94 : eBandInterp = GCI_GrayIndex;
465 94 : break;
466 :
467 : default:
468 6 : eBandInterp = GCI_Undefined;
469 : break;
470 : }
471 226 : }
472 :
473 : /************************************************************************/
474 : /* ~MrSIDRasterBand() */
475 : /************************************************************************/
476 :
477 226 : MrSIDRasterBand::~MrSIDRasterBand()
478 : {
479 226 : if ( poPixel )
480 226 : delete poPixel;
481 226 : }
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 142 : MrSIDDataset::MrSIDDataset(int bIsJPEG2000)
736 : {
737 142 : poStream = NULL;
738 142 : poImageReader = NULL;
739 : #ifdef MRSID_ESDK
740 : poImageWriter = NULL;
741 : #endif
742 142 : poLTINav = NULL;
743 142 : poMetadata = NULL;
744 142 : poNDPixel = NULL;
745 142 : eSampleType = LTI_DATATYPE_UINT8;
746 142 : nBands = 0;
747 142 : eDataType = GDT_Byte;
748 :
749 142 : poBuffer = NULL;
750 142 : bPrevBlockRead = FALSE;
751 142 : nPrevBlockXOff = 0;
752 142 : nPrevBlockYOff = 0;
753 :
754 142 : pszProjection = CPLStrdup( "" );
755 142 : bHasGeoTransform = FALSE;
756 142 : adfGeoTransform[0] = 0.0;
757 142 : adfGeoTransform[1] = 1.0;
758 142 : adfGeoTransform[2] = 0.0;
759 142 : adfGeoTransform[3] = 0.0;
760 142 : adfGeoTransform[4] = 0.0;
761 142 : adfGeoTransform[5] = 1.0;
762 142 : psDefn = NULL;
763 :
764 142 : dfCurrentMag = 1.0;
765 142 : bIsOverview = FALSE;
766 142 : poParentDS = this;
767 142 : nOverviewCount = 0;
768 142 : papoOverviewDS = NULL;
769 :
770 142 : poDriver = (GDALDriver*) GDALGetDriverByName( bIsJPEG2000 ? "JP2MrSID" : "MrSID" );
771 142 : }
772 :
773 : /************************************************************************/
774 : /* ~MrSIDDataset() */
775 : /************************************************************************/
776 :
777 142 : MrSIDDataset::~MrSIDDataset()
778 : {
779 142 : FlushCache();
780 :
781 : #ifdef MRSID_ESDK
782 : if ( poImageWriter )
783 : delete poImageWriter;
784 : #endif
785 :
786 142 : if ( poBuffer )
787 18 : delete poBuffer;
788 142 : if ( poMetadata )
789 27 : delete poMetadata;
790 142 : if ( poLTINav )
791 142 : delete poLTINav;
792 142 : if ( poImageReader && !bIsOverview )
793 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
794 : {
795 27 : poImageReader->release();
796 27 : poImageReader = NULL;
797 : }
798 : #else
799 : delete poImageReader;
800 : #endif
801 : // points to another member, don't delete
802 142 : poStream = NULL;
803 :
804 142 : if ( pszProjection )
805 142 : CPLFree( pszProjection );
806 142 : if ( psDefn )
807 27 : delete psDefn;
808 142 : CloseDependentDatasets();
809 142 : }
810 :
811 : /************************************************************************/
812 : /* CloseDependentDatasets() */
813 : /************************************************************************/
814 :
815 142 : int MrSIDDataset::CloseDependentDatasets()
816 : {
817 142 : int bRet = GDALPamDataset::CloseDependentDatasets();
818 :
819 142 : if ( papoOverviewDS )
820 : {
821 140 : for( int i = 0; i < nOverviewCount; i++ )
822 115 : delete papoOverviewDS[i];
823 25 : CPLFree( papoOverviewDS );
824 25 : papoOverviewDS = NULL;
825 25 : bRet = TRUE;
826 : }
827 142 : 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 5 : CPLErr MrSIDDataset::GetGeoTransform( double * padfTransform )
1052 : {
1053 5 : 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 4 : memcpy( padfTransform, adfGeoTransform, sizeof(double) * 6 );
1062 4 : 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 357 : char *MrSIDDataset::SerializeMetadataRec( const LTIMetadataRecord *poMetadataRec )
1085 : {
1086 357 : GUInt32 iNumDims = 0;
1087 357 : const GUInt32 *paiDims = NULL;
1088 357 : const void *pData = poMetadataRec->getArrayData( iNumDims, paiDims );
1089 357 : GUInt32 i, j, k = 0, iLength;
1090 357 : char *pszMetadata = CPLStrdup( "" );
1091 :
1092 714 : for ( i = 0; i < iNumDims; i++ )
1093 : {
1094 : // stops on large binary data
1095 357 : if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_UINT8
1096 0 : && paiDims[i] > 1024 )
1097 0 : return pszMetadata;
1098 :
1099 890 : for ( j = 0; j < paiDims[i]; j++ )
1100 : {
1101 533 : CPLString osTemp;
1102 :
1103 533 : 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 115 : osTemp.Printf( "%u", ((GUInt16 *)pData)[k++] );
1111 115 : 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 16 : osTemp.Printf( "%u", ((GUInt32 *)pData)[k++] );
1117 16 : break;
1118 : case LTI_METADATA_DATATYPE_SINT32:
1119 24 : osTemp.Printf( "%d", ((GInt32 *)pData)[k++] );
1120 24 : break;
1121 : case LTI_METADATA_DATATYPE_FLOAT32:
1122 24 : osTemp.Printf( "%f", ((float *)pData)[k++] );
1123 24 : break;
1124 : case LTI_METADATA_DATATYPE_FLOAT64:
1125 225 : osTemp.Printf( "%f", ((double *)pData)[k++] );
1126 225 : break;
1127 : case LTI_METADATA_DATATYPE_ASCII:
1128 129 : osTemp = ((const char **)pData)[k++];
1129 129 : break;
1130 : default:
1131 0 : osTemp = "";
1132 : break;
1133 : }
1134 :
1135 533 : iLength = strlen(pszMetadata) + strlen(osTemp) + 2;
1136 :
1137 533 : pszMetadata = (char *)CPLRealloc( pszMetadata, iLength );
1138 533 : if ( !EQUAL( pszMetadata, "" ) )
1139 176 : strncat( pszMetadata, ",", 1 );
1140 533 : strncat( pszMetadata, osTemp, iLength );
1141 : }
1142 : }
1143 :
1144 357 : return pszMetadata;
1145 : }
1146 :
1147 : /************************************************************************/
1148 : /* GetMetadataElement() */
1149 : /************************************************************************/
1150 :
1151 469 : int MrSIDDataset::GetMetadataElement( const char *pszKey, void *pValue,
1152 : int iLength )
1153 : {
1154 469 : if ( !poMetadata->has( pszKey ) )
1155 352 : return FALSE;
1156 :
1157 117 : const LTIMetadataRecord *poMetadataRec = NULL;
1158 117 : poMetadata->get( pszKey, poMetadataRec );
1159 :
1160 117 : if ( !poMetadataRec->isScalar() )
1161 32 : return FALSE;
1162 :
1163 : // XXX: return FALSE if we have more than one element in metadata record
1164 : int iSize;
1165 85 : 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 76 : iSize = 2;
1174 76 : 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 9 : iSize = iLength;
1185 9 : break;
1186 : default:
1187 0 : iSize = 0;
1188 : break;
1189 : }
1190 :
1191 85 : if ( poMetadataRec->getDataType() == LTI_METADATA_DATATYPE_ASCII )
1192 : {
1193 : strncpy( (char *)pValue,
1194 9 : ((const char**)poMetadataRec->getScalarData())[0], iSize );
1195 9 : ((char *)pValue)[iSize - 1] = '\0';
1196 : }
1197 : else
1198 76 : memcpy( pValue, poMetadataRec->getScalarData(), iSize );
1199 :
1200 85 : 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 142 : CPLErr MrSIDDataset::OpenZoomLevel( lt_int32 iZoom )
1222 : {
1223 : /* -------------------------------------------------------------------- */
1224 : /* Get image geometry. */
1225 : /* -------------------------------------------------------------------- */
1226 142 : if ( iZoom != 0 )
1227 : {
1228 : lt_uint32 iWidth, iHeight;
1229 115 : dfCurrentMag = LTIUtils::levelToMag( iZoom );
1230 115 : poImageReader->getDimsAtMag( dfCurrentMag, iWidth, iHeight );
1231 115 : nRasterXSize = iWidth;
1232 115 : nRasterYSize = iHeight;
1233 : }
1234 : else
1235 : {
1236 27 : dfCurrentMag = 1.0;
1237 27 : nRasterXSize = poImageReader->getWidth();
1238 27 : nRasterYSize = poImageReader->getHeight();
1239 : }
1240 :
1241 142 : nBands = poImageReader->getNumBands();
1242 142 : nBlockXSize = nRasterXSize;
1243 142 : nBlockYSize = poImageReader->getStripHeight();
1244 :
1245 : CPLDebug( "MrSID", "Opened zoom level %d with size %dx%d.",
1246 142 : iZoom, nRasterXSize, nRasterYSize );
1247 :
1248 : try
1249 : {
1250 142 : 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 142 : eColorSpace = poImageReader->getColorSpace();
1264 142 : eSampleType = poImageReader->getDataType();
1265 142 : 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 118 : eDataType = GDT_Byte;
1289 : break;
1290 : }
1291 :
1292 : /* -------------------------------------------------------------------- */
1293 : /* Read georeferencing. */
1294 : /* -------------------------------------------------------------------- */
1295 142 : if ( !poImageReader->isGeoCoordImplicit() )
1296 : {
1297 71 : const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
1298 : oGeo.get( adfGeoTransform[0], adfGeoTransform[3],
1299 : adfGeoTransform[1], adfGeoTransform[5],
1300 71 : adfGeoTransform[2], adfGeoTransform[4] );
1301 :
1302 71 : adfGeoTransform[0] = adfGeoTransform[0] - adfGeoTransform[1] / 2;
1303 71 : adfGeoTransform[3] = adfGeoTransform[3] - adfGeoTransform[5] / 2;
1304 71 : bHasGeoTransform = TRUE;
1305 : }
1306 71 : else if( iZoom == 0 )
1307 : {
1308 : bHasGeoTransform =
1309 13 : GDALReadWorldFile( GetDescription(), NULL,
1310 : adfGeoTransform )
1311 12 : || GDALReadWorldFile( GetDescription(), ".wld",
1312 38 : adfGeoTransform );
1313 : }
1314 :
1315 : /* -------------------------------------------------------------------- */
1316 : /* Read wkt. */
1317 : /* -------------------------------------------------------------------- */
1318 : #ifdef MRSID_HAVE_GETWKT
1319 142 : if( !poImageReader->isGeoCoordImplicit() )
1320 : {
1321 71 : const LTIGeoCoord& oGeo = poImageReader->getGeoCoord();
1322 :
1323 71 : if( oGeo.getWKT() )
1324 : {
1325 : /* Workaround probable issue with GeoDSK 7 on 64bit Linux */
1326 71 : if (!(pszProjection != NULL && !EQUALN(pszProjection, "LOCAL_CS", 8)
1327 : && EQUALN( oGeo.getWKT(), "LOCAL_CS", 8)))
1328 : {
1329 71 : CPLFree( pszProjection );
1330 71 : pszProjection = CPLStrdup( oGeo.getWKT() );
1331 : }
1332 : }
1333 : }
1334 : #endif // HAVE_MRSID_GETWKT
1335 :
1336 : /* -------------------------------------------------------------------- */
1337 : /* Special case for https://zulu.ssc.nasa.gov/mrsid/mrsid.pl */
1338 : /* where LandSat .SID are accompanied by a .met file with the */
1339 : /* projection */
1340 : /* -------------------------------------------------------------------- */
1341 153 : if (iZoom == 0 && (pszProjection == NULL || pszProjection[0] == '\0') &&
1342 11 : EQUAL(CPLGetExtension(GetDescription()), "sid"))
1343 : {
1344 0 : const char* pszMETFilename = CPLResetExtension(GetDescription(), "met");
1345 0 : VSILFILE* fp = VSIFOpenL(pszMETFilename, "rb");
1346 0 : if (fp)
1347 : {
1348 : const char* pszLine;
1349 0 : int nCountLine = 0;
1350 0 : int nUTMZone = 0;
1351 0 : int bWGS84 = FALSE;
1352 0 : int bUnitsMeter = FALSE;
1353 0 : while ( (pszLine = CPLReadLine2L(fp, 200, NULL)) != NULL &&
1354 : ++nCountLine < 1000 )
1355 : {
1356 0 : if (nCountLine == 1 && strcmp(pszLine, "::MetadataFile") != 0)
1357 0 : break;
1358 0 : if (EQUALN(pszLine, "Projection UTM ", 15))
1359 0 : nUTMZone = atoi(pszLine + 15);
1360 0 : else if (EQUAL(pszLine, "Datum WGS84"))
1361 0 : bWGS84 = TRUE;
1362 0 : else if (EQUAL(pszLine, "Units Meters"))
1363 0 : bUnitsMeter = TRUE;
1364 : }
1365 0 : VSIFCloseL(fp);
1366 :
1367 : /* Images in southern hemisphere have negative northings in the */
1368 : /* .sdw file. A bit weird, but anyway we must use the northern */
1369 : /* UTM SRS for consistency */
1370 0 : if (nUTMZone >= 1 && nUTMZone <= 60 && bWGS84 && bUnitsMeter)
1371 : {
1372 0 : osMETFilename = pszMETFilename;
1373 :
1374 0 : OGRSpatialReference oSRS;
1375 0 : oSRS.importFromEPSG(32600 + nUTMZone);
1376 0 : CPLFree(pszProjection);
1377 0 : pszProjection = NULL;
1378 0 : oSRS.exportToWkt(&pszProjection);
1379 : }
1380 : }
1381 : }
1382 :
1383 : /* -------------------------------------------------------------------- */
1384 : /* Read NoData value. */
1385 : /* -------------------------------------------------------------------- */
1386 142 : poNDPixel = poImageReader->getNoDataPixel();
1387 :
1388 : /* -------------------------------------------------------------------- */
1389 : /* Create band information objects. */
1390 : /* -------------------------------------------------------------------- */
1391 : int iBand;
1392 :
1393 736 : for( iBand = 1; iBand <= nBands; iBand++ )
1394 226 : SetBand( iBand, new MrSIDRasterBand( this, iBand ) );
1395 :
1396 142 : return CE_None;
1397 : }
1398 :
1399 : /************************************************************************/
1400 : /* MrSIDIdentify() */
1401 : /* */
1402 : /* Identify method that only supports MrSID files. */
1403 : /************************************************************************/
1404 :
1405 12626 : static int MrSIDIdentify( GDALOpenInfo * poOpenInfo )
1406 : {
1407 12626 : if( poOpenInfo->nHeaderBytes < 32 )
1408 11610 : return FALSE;
1409 :
1410 1016 : if ( !EQUALN((const char *) poOpenInfo->pabyHeader, "msid", 4) )
1411 1007 : return FALSE;
1412 :
1413 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
1414 : lt_uint8 gen;
1415 : bool raster;
1416 : LT_STATUS eStat =
1417 9 : MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
1418 9 : if (!LT_SUCCESS(eStat) || !raster)
1419 0 : return FALSE;
1420 : #endif
1421 :
1422 9 : return TRUE;
1423 : }
1424 :
1425 : /************************************************************************/
1426 : /* MrSIDOpen() */
1427 : /* */
1428 : /* Open method that only supports MrSID files. */
1429 : /************************************************************************/
1430 :
1431 2533 : static GDALDataset* MrSIDOpen( GDALOpenInfo *poOpenInfo )
1432 : {
1433 2533 : if (!MrSIDIdentify(poOpenInfo))
1434 2524 : return NULL;
1435 :
1436 9 : return MrSIDDataset::Open( poOpenInfo, FALSE );
1437 : }
1438 :
1439 :
1440 : #ifdef MRSID_J2K
1441 :
1442 : static const unsigned char jpc_header[] =
1443 : {0xff,0x4f};
1444 :
1445 : /************************************************************************/
1446 : /* JP2Identify() */
1447 : /* */
1448 : /* Identify method that only supports JPEG2000 files. */
1449 : /************************************************************************/
1450 :
1451 11978 : static int JP2Identify( GDALOpenInfo *poOpenInfo )
1452 : {
1453 11978 : if( poOpenInfo->nHeaderBytes < 32 )
1454 11486 : return FALSE;
1455 :
1456 492 : if( memcmp( poOpenInfo->pabyHeader, jpc_header, sizeof(jpc_header) ) == 0 )
1457 : {
1458 : const char *pszExtension;
1459 :
1460 9 : pszExtension = CPLGetExtension( poOpenInfo->pszFilename );
1461 :
1462 9 : if( !EQUAL(pszExtension,"jpc") && !EQUAL(pszExtension,"j2k")
1463 : && !EQUAL(pszExtension,"jp2") && !EQUAL(pszExtension,"jpx")
1464 : && !EQUAL(pszExtension,"j2c") && !EQUAL(pszExtension,"ntf"))
1465 0 : return FALSE;
1466 : }
1467 483 : else if( !EQUALN((const char *) poOpenInfo->pabyHeader + 4, "jP ", 4) )
1468 474 : return FALSE;
1469 :
1470 18 : return TRUE;
1471 : }
1472 :
1473 : /************************************************************************/
1474 : /* JP2Open() */
1475 : /* */
1476 : /* Open method that only supports JPEG2000 files. */
1477 : /************************************************************************/
1478 :
1479 1922 : static GDALDataset* JP2Open( GDALOpenInfo *poOpenInfo )
1480 : {
1481 1922 : if (!JP2Identify(poOpenInfo))
1482 1904 : return NULL;
1483 :
1484 18 : return MrSIDDataset::Open( poOpenInfo, TRUE );
1485 : }
1486 :
1487 : #endif // MRSID_J2K
1488 :
1489 : /************************************************************************/
1490 : /* Open() */
1491 : /************************************************************************/
1492 :
1493 27 : GDALDataset *MrSIDDataset::Open( GDALOpenInfo * poOpenInfo, int bIsJP2 )
1494 : {
1495 27 : if(poOpenInfo->fp)
1496 : {
1497 21 : VSIFClose( poOpenInfo->fp );
1498 21 : poOpenInfo->fp = NULL;
1499 : }
1500 :
1501 : /* -------------------------------------------------------------------- */
1502 : /* Create a corresponding GDALDataset. */
1503 : /* -------------------------------------------------------------------- */
1504 : MrSIDDataset *poDS;
1505 : LT_STATUS eStat;
1506 :
1507 27 : poDS = new MrSIDDataset(bIsJP2);
1508 :
1509 : // try the LTIOFileStream first, since it uses filesystem caching
1510 27 : eStat = poDS->oLTIStream.initialize( poOpenInfo->pszFilename, "rb" );
1511 27 : if ( LT_SUCCESS(eStat) )
1512 : {
1513 27 : eStat = poDS->oLTIStream.open();
1514 27 : if ( LT_SUCCESS(eStat) )
1515 21 : poDS->poStream = &(poDS->oLTIStream);
1516 : }
1517 :
1518 : // fall back on VSI for non-files
1519 27 : if ( !LT_SUCCESS(eStat) || !poDS->poStream )
1520 : {
1521 6 : eStat = poDS->oVSIStream.initialize( poOpenInfo->pszFilename, "rb" );
1522 6 : if ( !LT_SUCCESS(eStat) )
1523 : {
1524 : CPLError( CE_Failure, CPLE_AppDefined,
1525 : "LTIVSIStream::initialize(): "
1526 : "failed to open file \"%s\".\n%s",
1527 0 : poOpenInfo->pszFilename, getLastStatusString( eStat ) );
1528 0 : delete poDS;
1529 0 : return NULL;
1530 : }
1531 :
1532 6 : eStat = poDS->oVSIStream.open();
1533 6 : if ( !LT_SUCCESS(eStat) )
1534 : {
1535 : CPLError( CE_Failure, CPLE_AppDefined,
1536 : "LTIVSIStream::open(): "
1537 : "failed to open file \"%s\".\n%s",
1538 0 : poOpenInfo->pszFilename, getLastStatusString( eStat ) );
1539 0 : delete poDS;
1540 0 : return NULL;
1541 : }
1542 :
1543 6 : poDS->poStream = &(poDS->oVSIStream);
1544 : }
1545 :
1546 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 7
1547 :
1548 : #ifdef MRSID_J2K
1549 27 : if ( bIsJP2 )
1550 : {
1551 18 : J2KImageReader *reader = J2KImageReader::create();
1552 18 : eStat = reader->initialize( *(poDS->poStream) );
1553 18 : poDS->poImageReader = reader;
1554 : }
1555 : else
1556 : #endif /* MRSID_J2K */
1557 : {
1558 9 : MrSIDImageReader *reader = MrSIDImageReader::create();
1559 9 : eStat = reader->initialize( poDS->poStream, NULL );
1560 9 : poDS->poImageReader = reader;
1561 : }
1562 :
1563 : #else /* LTI_SDK_MAJOR < 7 */
1564 :
1565 : #ifdef MRSID_J2K
1566 : if ( bIsJP2 )
1567 : {
1568 : poDS->poImageReader =
1569 : new LTIDLLReader<J2KImageReader>( *(poDS->poStream), true );
1570 : eStat = poDS->poImageReader->initialize();
1571 : }
1572 : else
1573 : #endif /* MRSID_J2K */
1574 : {
1575 : poDS->poImageReader =
1576 : new LTIDLLReader<MrSIDImageReader>( poDS->poStream, NULL );
1577 : eStat = poDS->poImageReader->initialize();
1578 : }
1579 :
1580 : #endif /* LTI_SDK_MAJOR >= 7 */
1581 :
1582 27 : if ( !LT_SUCCESS(eStat) )
1583 : {
1584 : CPLError( CE_Failure, CPLE_AppDefined,
1585 : "LTIImageReader::initialize(): "
1586 : "failed to initialize reader from the stream \"%s\".\n%s",
1587 0 : poOpenInfo->pszFilename, getLastStatusString( eStat ) );
1588 0 : delete poDS;
1589 0 : return NULL;
1590 : }
1591 :
1592 : /* -------------------------------------------------------------------- */
1593 : /* Read metadata. */
1594 : /* -------------------------------------------------------------------- */
1595 : poDS->poMetadata = new LTIDLLCopy<LTIMetadataDatabase>(
1596 27 : poDS->poImageReader->getMetadata() );
1597 27 : const GUInt32 iNumRecs = poDS->poMetadata->getIndexCount();
1598 : GUInt32 i;
1599 :
1600 384 : for ( i = 0; i < iNumRecs; i++ )
1601 : {
1602 357 : const LTIMetadataRecord *poMetadataRec = NULL;
1603 357 : if ( LT_SUCCESS(poDS->poMetadata->getDataByIndex(i, poMetadataRec)) )
1604 : {
1605 357 : char *pszElement = poDS->SerializeMetadataRec( poMetadataRec );
1606 357 : char *pszKey = CPLStrdup( poMetadataRec->getTagName() );
1607 357 : char *pszTemp = pszKey;
1608 :
1609 : // GDAL metadata keys should not contain ':' and '=' characters.
1610 : // We will replace them with '_'.
1611 11711 : do
1612 : {
1613 11711 : if ( *pszTemp == ':' || *pszTemp == '=' )
1614 1020 : *pszTemp = '_';
1615 : }
1616 : while ( *++pszTemp );
1617 :
1618 357 : poDS->SetMetadataItem( pszKey, pszElement );
1619 :
1620 357 : CPLFree( pszElement );
1621 357 : CPLFree( pszKey );
1622 : }
1623 : }
1624 :
1625 : /* -------------------------------------------------------------------- */
1626 : /* Add MrSID version. */
1627 : /* -------------------------------------------------------------------- */
1628 : #ifdef MRSID_J2K
1629 27 : if( !bIsJP2 )
1630 : #endif
1631 : {
1632 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
1633 : lt_uint8 gen;
1634 : bool raster;
1635 9 : MrSIDImageReaderInterface::getMrSIDGeneration(poOpenInfo->pabyHeader, gen, raster);
1636 9 : poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d%s", gen, raster ? "" : " LiDAR") );
1637 : #else
1638 : lt_uint8 major;
1639 : lt_uint8 minor;
1640 : char letter;
1641 : MrSIDImageReader* poMrSIDImageReader = (MrSIDImageReader*)poDS->poImageReader;
1642 : poMrSIDImageReader->getVersion(major, minor, minor, letter);
1643 : if (major < 2)
1644 : major = 2;
1645 : poDS->SetMetadataItem( "VERSION", CPLString().Printf("MG%d", major) );
1646 : #endif
1647 : }
1648 :
1649 27 : poDS->GetGTIFDefn();
1650 :
1651 : /* -------------------------------------------------------------------- */
1652 : /* Get number of resolution levels (we will use them as overviews).*/
1653 : /* -------------------------------------------------------------------- */
1654 : #ifdef MRSID_J2K
1655 27 : if( bIsJP2 )
1656 : poDS->nOverviewCount
1657 18 : = ((J2KImageReader *) (poDS->poImageReader))->getNumLevels();
1658 : else
1659 : #endif
1660 : poDS->nOverviewCount
1661 9 : = ((MrSIDImageReader *) (poDS->poImageReader))->getNumLevels();
1662 :
1663 27 : if ( poDS->nOverviewCount > 0 )
1664 : {
1665 : lt_int32 i;
1666 :
1667 : poDS->papoOverviewDS = (MrSIDDataset **)
1668 25 : CPLMalloc( poDS->nOverviewCount * (sizeof(void*)) );
1669 :
1670 280 : for ( i = 0; i < poDS->nOverviewCount; i++ )
1671 : {
1672 115 : poDS->papoOverviewDS[i] = new MrSIDDataset(bIsJP2);
1673 115 : poDS->papoOverviewDS[i]->poImageReader = poDS->poImageReader;
1674 115 : poDS->papoOverviewDS[i]->OpenZoomLevel( i + 1 );
1675 115 : poDS->papoOverviewDS[i]->bIsOverview = TRUE;
1676 115 : poDS->papoOverviewDS[i]->poParentDS = poDS;
1677 : }
1678 : }
1679 :
1680 : /* -------------------------------------------------------------------- */
1681 : /* Create object for the whole image. */
1682 : /* -------------------------------------------------------------------- */
1683 27 : poDS->SetDescription( poOpenInfo->pszFilename );
1684 27 : poDS->OpenZoomLevel( 0 );
1685 :
1686 : CPLDebug( "MrSID",
1687 : "Opened image: width %d, height %d, bands %d",
1688 27 : poDS->nRasterXSize, poDS->nRasterYSize, poDS->nBands );
1689 :
1690 27 : if( poDS->nBands > 1 )
1691 7 : poDS->SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
1692 :
1693 27 : if (bIsJP2)
1694 : {
1695 18 : GDALJP2Metadata oJP2Geo;
1696 18 : if ( oJP2Geo.ReadAndParse( poOpenInfo->pszFilename ) )
1697 : {
1698 : /*poDS->pszProjection = CPLStrdup(oJP2Geo.pszProjection);
1699 : poDS->bGeoTransformValid = oJP2Geo.bHaveGeoTransform;
1700 : memcpy( poDS->adfGeoTransform, oJP2Geo.adfGeoTransform,
1701 : sizeof(double) * 6 );
1702 : poDS->nGCPCount = oJP2Geo.nGCPCount;
1703 : poDS->pasGCPList = oJP2Geo.pasGCPList;
1704 : oJP2Geo.pasGCPList = NULL;
1705 : oJP2Geo.nGCPCount = 0;*/
1706 : }
1707 :
1708 18 : if (oJP2Geo.pszXMPMetadata)
1709 : {
1710 : char *apszMDList[2];
1711 1 : apszMDList[0] = (char *) oJP2Geo.pszXMPMetadata;
1712 1 : apszMDList[1] = NULL;
1713 1 : poDS->SetMetadata(apszMDList, "xml:XMP");
1714 18 : }
1715 : }
1716 :
1717 : /* -------------------------------------------------------------------- */
1718 : /* Initialize any PAM information. */
1719 : /* -------------------------------------------------------------------- */
1720 27 : poDS->TryLoadXML();
1721 :
1722 : /* -------------------------------------------------------------------- */
1723 : /* Initialize the overview manager for mask band support. */
1724 : /* -------------------------------------------------------------------- */
1725 27 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
1726 :
1727 27 : return( poDS );
1728 : }
1729 :
1730 : /************************************************************************/
1731 : /* EPSGProjMethodToCTProjMethod() */
1732 : /* */
1733 : /* Convert between the EPSG enumeration for projection methods, */
1734 : /* and the GeoTIFF CT codes. */
1735 : /* Explicitly copied from geo_normalize.c of the GeoTIFF package */
1736 : /************************************************************************/
1737 :
1738 5 : static int EPSGProjMethodToCTProjMethod( int nEPSG )
1739 :
1740 : {
1741 : /* see trf_method.csv for list of EPSG codes */
1742 :
1743 5 : switch( nEPSG )
1744 : {
1745 : case 9801:
1746 0 : return( CT_LambertConfConic_1SP );
1747 :
1748 : case 9802:
1749 0 : return( CT_LambertConfConic_2SP );
1750 :
1751 : case 9803:
1752 0 : return( CT_LambertConfConic_2SP ); /* Belgian variant not supported */
1753 :
1754 : case 9804:
1755 0 : return( CT_Mercator ); /* 1SP and 2SP not differentiated */
1756 :
1757 : case 9805:
1758 0 : return( CT_Mercator ); /* 1SP and 2SP not differentiated */
1759 :
1760 : case 9806:
1761 0 : return( CT_CassiniSoldner );
1762 :
1763 : case 9807:
1764 5 : return( CT_TransverseMercator );
1765 :
1766 : case 9808:
1767 0 : return( CT_TransvMercator_SouthOriented );
1768 :
1769 : case 9809:
1770 0 : return( CT_ObliqueStereographic );
1771 :
1772 : case 9810:
1773 0 : return( CT_PolarStereographic );
1774 :
1775 : case 9811:
1776 0 : return( CT_NewZealandMapGrid );
1777 :
1778 : case 9812:
1779 0 : return( CT_ObliqueMercator ); /* is hotine actually different? */
1780 :
1781 : case 9813:
1782 0 : return( CT_ObliqueMercator_Laborde );
1783 :
1784 : case 9814:
1785 0 : return( CT_ObliqueMercator_Rosenmund ); /* swiss */
1786 :
1787 : case 9815:
1788 0 : return( CT_ObliqueMercator );
1789 :
1790 : case 9816: /* tunesia mining grid has no counterpart */
1791 0 : return( KvUserDefined );
1792 : }
1793 :
1794 0 : return( KvUserDefined );
1795 : }
1796 :
1797 : /* EPSG Codes for projection parameters. Unfortunately, these bear no
1798 : relationship to the GeoTIFF codes even though the names are so similar. */
1799 :
1800 : #define EPSGNatOriginLat 8801
1801 : #define EPSGNatOriginLong 8802
1802 : #define EPSGNatOriginScaleFactor 8805
1803 : #define EPSGFalseEasting 8806
1804 : #define EPSGFalseNorthing 8807
1805 : #define EPSGProjCenterLat 8811
1806 : #define EPSGProjCenterLong 8812
1807 : #define EPSGAzimuth 8813
1808 : #define EPSGAngleRectifiedToSkewedGrid 8814
1809 : #define EPSGInitialLineScaleFactor 8815
1810 : #define EPSGProjCenterEasting 8816
1811 : #define EPSGProjCenterNorthing 8817
1812 : #define EPSGPseudoStdParallelLat 8818
1813 : #define EPSGPseudoStdParallelScaleFactor 8819
1814 : #define EPSGFalseOriginLat 8821
1815 : #define EPSGFalseOriginLong 8822
1816 : #define EPSGStdParallel1Lat 8823
1817 : #define EPSGStdParallel2Lat 8824
1818 : #define EPSGFalseOriginEasting 8826
1819 : #define EPSGFalseOriginNorthing 8827
1820 : #define EPSGSphericalOriginLat 8828
1821 : #define EPSGSphericalOriginLong 8829
1822 : #define EPSGInitialLongitude 8830
1823 : #define EPSGZoneWidth 8831
1824 :
1825 : /************************************************************************/
1826 : /* SetGTParmIds() */
1827 : /* */
1828 : /* This is hardcoded logic to set the GeoTIFF parameter */
1829 : /* identifiers for all the EPSG supported projections. As the */
1830 : /* trf_method.csv table grows with new projections, this code */
1831 : /* will need to be updated. */
1832 : /* Explicitly copied from geo_normalize.c of the GeoTIFF package. */
1833 : /************************************************************************/
1834 :
1835 5 : static int SetGTParmIds( int nCTProjection,
1836 : int *panProjParmId,
1837 : int *panEPSGCodes )
1838 :
1839 : {
1840 : int anWorkingDummy[7];
1841 :
1842 5 : if( panEPSGCodes == NULL )
1843 5 : panEPSGCodes = anWorkingDummy;
1844 5 : if( panProjParmId == NULL )
1845 0 : panProjParmId = anWorkingDummy;
1846 :
1847 5 : memset( panEPSGCodes, 0, sizeof(int) * 7 );
1848 :
1849 : /* psDefn->nParms = 7; */
1850 :
1851 5 : switch( nCTProjection )
1852 : {
1853 : case CT_CassiniSoldner:
1854 : case CT_NewZealandMapGrid:
1855 0 : panProjParmId[0] = ProjNatOriginLatGeoKey;
1856 0 : panProjParmId[1] = ProjNatOriginLongGeoKey;
1857 0 : panProjParmId[5] = ProjFalseEastingGeoKey;
1858 0 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1859 :
1860 0 : panEPSGCodes[0] = EPSGNatOriginLat;
1861 0 : panEPSGCodes[1] = EPSGNatOriginLong;
1862 0 : panEPSGCodes[5] = EPSGFalseEasting;
1863 0 : panEPSGCodes[6] = EPSGFalseNorthing;
1864 0 : return TRUE;
1865 :
1866 : case CT_ObliqueMercator:
1867 0 : panProjParmId[0] = ProjCenterLatGeoKey;
1868 0 : panProjParmId[1] = ProjCenterLongGeoKey;
1869 0 : panProjParmId[2] = ProjAzimuthAngleGeoKey;
1870 0 : panProjParmId[3] = ProjRectifiedGridAngleGeoKey;
1871 0 : panProjParmId[4] = ProjScaleAtCenterGeoKey;
1872 0 : panProjParmId[5] = ProjFalseEastingGeoKey;
1873 0 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1874 :
1875 0 : panEPSGCodes[0] = EPSGProjCenterLat;
1876 0 : panEPSGCodes[1] = EPSGProjCenterLong;
1877 0 : panEPSGCodes[2] = EPSGAzimuth;
1878 0 : panEPSGCodes[3] = EPSGAngleRectifiedToSkewedGrid;
1879 0 : panEPSGCodes[4] = EPSGInitialLineScaleFactor;
1880 0 : panEPSGCodes[5] = EPSGProjCenterEasting;
1881 0 : panEPSGCodes[6] = EPSGProjCenterNorthing;
1882 0 : return TRUE;
1883 :
1884 : case CT_ObliqueMercator_Laborde:
1885 0 : panProjParmId[0] = ProjCenterLatGeoKey;
1886 0 : panProjParmId[1] = ProjCenterLongGeoKey;
1887 0 : panProjParmId[2] = ProjAzimuthAngleGeoKey;
1888 0 : panProjParmId[4] = ProjScaleAtCenterGeoKey;
1889 0 : panProjParmId[5] = ProjFalseEastingGeoKey;
1890 0 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1891 :
1892 0 : panEPSGCodes[0] = EPSGProjCenterLat;
1893 0 : panEPSGCodes[1] = EPSGProjCenterLong;
1894 0 : panEPSGCodes[2] = EPSGAzimuth;
1895 0 : panEPSGCodes[4] = EPSGInitialLineScaleFactor;
1896 0 : panEPSGCodes[5] = EPSGProjCenterEasting;
1897 0 : panEPSGCodes[6] = EPSGProjCenterNorthing;
1898 0 : return TRUE;
1899 :
1900 : case CT_LambertConfConic_1SP:
1901 : case CT_Mercator:
1902 : case CT_ObliqueStereographic:
1903 : case CT_PolarStereographic:
1904 : case CT_TransverseMercator:
1905 : case CT_TransvMercator_SouthOriented:
1906 5 : panProjParmId[0] = ProjNatOriginLatGeoKey;
1907 5 : panProjParmId[1] = ProjNatOriginLongGeoKey;
1908 5 : panProjParmId[4] = ProjScaleAtNatOriginGeoKey;
1909 5 : panProjParmId[5] = ProjFalseEastingGeoKey;
1910 5 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1911 :
1912 5 : panEPSGCodes[0] = EPSGNatOriginLat;
1913 5 : panEPSGCodes[1] = EPSGNatOriginLong;
1914 5 : panEPSGCodes[4] = EPSGNatOriginScaleFactor;
1915 5 : panEPSGCodes[5] = EPSGFalseEasting;
1916 5 : panEPSGCodes[6] = EPSGFalseNorthing;
1917 5 : return TRUE;
1918 :
1919 : case CT_LambertConfConic_2SP:
1920 0 : panProjParmId[0] = ProjFalseOriginLatGeoKey;
1921 0 : panProjParmId[1] = ProjFalseOriginLongGeoKey;
1922 0 : panProjParmId[2] = ProjStdParallel1GeoKey;
1923 0 : panProjParmId[3] = ProjStdParallel2GeoKey;
1924 0 : panProjParmId[5] = ProjFalseEastingGeoKey;
1925 0 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1926 :
1927 0 : panEPSGCodes[0] = EPSGFalseOriginLat;
1928 0 : panEPSGCodes[1] = EPSGFalseOriginLong;
1929 0 : panEPSGCodes[2] = EPSGStdParallel1Lat;
1930 0 : panEPSGCodes[3] = EPSGStdParallel2Lat;
1931 0 : panEPSGCodes[5] = EPSGFalseOriginEasting;
1932 0 : panEPSGCodes[6] = EPSGFalseOriginNorthing;
1933 0 : return TRUE;
1934 :
1935 : case CT_SwissObliqueCylindrical:
1936 0 : panProjParmId[0] = ProjCenterLatGeoKey;
1937 0 : panProjParmId[1] = ProjCenterLongGeoKey;
1938 0 : panProjParmId[5] = ProjFalseEastingGeoKey;
1939 0 : panProjParmId[6] = ProjFalseNorthingGeoKey;
1940 :
1941 : /* EPSG codes? */
1942 0 : return TRUE;
1943 :
1944 : default:
1945 0 : return( FALSE );
1946 : }
1947 : }
1948 :
1949 : static const char *papszDatumEquiv[] =
1950 : {
1951 : "Militar_Geographische_Institut",
1952 : "Militar_Geographische_Institute",
1953 : "World_Geodetic_System_1984",
1954 : "WGS_1984",
1955 : "WGS_72_Transit_Broadcast_Ephemeris",
1956 : "WGS_1972_Transit_Broadcast_Ephemeris",
1957 : "World_Geodetic_System_1972",
1958 : "WGS_1972",
1959 : "European_Terrestrial_Reference_System_89",
1960 : "European_Reference_System_1989",
1961 : NULL
1962 : };
1963 :
1964 : /************************************************************************/
1965 : /* WKTMassageDatum() */
1966 : /* */
1967 : /* Massage an EPSG datum name into WMT format. Also transform */
1968 : /* specific exception cases into WKT versions. */
1969 : /* Explicitly copied from the gt_wkt_srs.cpp. */
1970 : /************************************************************************/
1971 :
1972 15 : static void WKTMassageDatum( char ** ppszDatum )
1973 :
1974 : {
1975 : int i, j;
1976 15 : char *pszDatum = *ppszDatum;
1977 :
1978 15 : if (pszDatum[0] == '\0')
1979 0 : return;
1980 :
1981 : /* -------------------------------------------------------------------- */
1982 : /* Translate non-alphanumeric values to underscores. */
1983 : /* -------------------------------------------------------------------- */
1984 392 : for( i = 0; pszDatum[i] != '\0'; i++ )
1985 : {
1986 1101 : if( !(pszDatum[i] >= 'A' && pszDatum[i] <= 'Z')
1987 559 : && !(pszDatum[i] >= 'a' && pszDatum[i] <= 'z')
1988 165 : && !(pszDatum[i] >= '0' && pszDatum[i] <= '9') )
1989 : {
1990 45 : pszDatum[i] = '_';
1991 : }
1992 : }
1993 :
1994 : /* -------------------------------------------------------------------- */
1995 : /* Remove repeated and trailing underscores. */
1996 : /* -------------------------------------------------------------------- */
1997 377 : for( i = 1, j = 0; pszDatum[i] != '\0'; i++ )
1998 : {
1999 362 : if( pszDatum[j] == '_' && pszDatum[i] == '_' )
2000 0 : continue;
2001 :
2002 362 : pszDatum[++j] = pszDatum[i];
2003 : }
2004 15 : if( pszDatum[j] == '_' )
2005 0 : pszDatum[j] = '\0';
2006 : else
2007 15 : pszDatum[j+1] = '\0';
2008 :
2009 : /* -------------------------------------------------------------------- */
2010 : /* Search for datum equivelences. Specific massaged names get */
2011 : /* mapped to OpenGIS specified names. */
2012 : /* -------------------------------------------------------------------- */
2013 82 : for( i = 0; papszDatumEquiv[i] != NULL; i += 2 )
2014 : {
2015 69 : if( EQUAL(*ppszDatum,papszDatumEquiv[i]) )
2016 : {
2017 2 : CPLFree( *ppszDatum );
2018 2 : *ppszDatum = CPLStrdup( papszDatumEquiv[i+1] );
2019 2 : return;
2020 : }
2021 : }
2022 : }
2023 :
2024 : /************************************************************************/
2025 : /* FetchProjParms() */
2026 : /* */
2027 : /* Fetch the projection parameters for a particular projection */
2028 : /* from MrSID metadata, and fill the GTIFDefn structure out */
2029 : /* with them. */
2030 : /* Copied from geo_normalize.c of the GeoTIFF package. */
2031 : /************************************************************************/
2032 :
2033 8 : void MrSIDDataset::FetchProjParms()
2034 : {
2035 8 : double dfNatOriginLong = 0.0, dfNatOriginLat = 0.0, dfRectGridAngle = 0.0;
2036 8 : double dfFalseEasting = 0.0, dfFalseNorthing = 0.0, dfNatOriginScale = 1.0;
2037 8 : double dfStdParallel1 = 0.0, dfStdParallel2 = 0.0, dfAzimuth = 0.0;
2038 :
2039 : /* -------------------------------------------------------------------- */
2040 : /* Get the false easting, and northing if available. */
2041 : /* -------------------------------------------------------------------- */
2042 8 : if( !GetMetadataElement( "GEOTIFF_NUM::3082::ProjFalseEastingGeoKey",
2043 : &dfFalseEasting )
2044 : && !GetMetadataElement( "GEOTIFF_NUM::3090:ProjCenterEastingGeoKey",
2045 : &dfFalseEasting ) )
2046 8 : dfFalseEasting = 0.0;
2047 :
2048 8 : if( !GetMetadataElement( "GEOTIFF_NUM::3083::ProjFalseNorthingGeoKey",
2049 : &dfFalseNorthing )
2050 : && !GetMetadataElement( "GEOTIFF_NUM::3091::ProjCenterNorthingGeoKey",
2051 : &dfFalseNorthing ) )
2052 8 : dfFalseNorthing = 0.0;
2053 :
2054 8 : switch( psDefn->CTProjection )
2055 : {
2056 : /* -------------------------------------------------------------------- */
2057 : case CT_Stereographic:
2058 : /* -------------------------------------------------------------------- */
2059 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2060 : &dfNatOriginLong ) == 0
2061 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2062 : &dfNatOriginLong ) == 0
2063 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2064 : &dfNatOriginLong ) == 0 )
2065 0 : dfNatOriginLong = 0.0;
2066 :
2067 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2068 : &dfNatOriginLat ) == 0
2069 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2070 : &dfNatOriginLat ) == 0
2071 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2072 : &dfNatOriginLat ) == 0 )
2073 0 : dfNatOriginLat = 0.0;
2074 :
2075 0 : if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2076 : &dfNatOriginScale ) == 0 )
2077 0 : dfNatOriginScale = 1.0;
2078 :
2079 : /* notdef: should transform to decimal degrees at this point */
2080 :
2081 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2082 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2083 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2084 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2085 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2086 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2087 0 : psDefn->ProjParm[5] = dfFalseEasting;
2088 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2089 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2090 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2091 :
2092 0 : psDefn->nParms = 7;
2093 0 : break;
2094 :
2095 : /* -------------------------------------------------------------------- */
2096 : case CT_LambertConfConic_1SP:
2097 : case CT_Mercator:
2098 : case CT_ObliqueStereographic:
2099 : case CT_TransverseMercator:
2100 : case CT_TransvMercator_SouthOriented:
2101 : /* -------------------------------------------------------------------- */
2102 8 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2103 : &dfNatOriginLong ) == 0
2104 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2105 : &dfNatOriginLong ) == 0
2106 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2107 : &dfNatOriginLong ) == 0 )
2108 8 : dfNatOriginLong = 0.0;
2109 :
2110 8 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2111 : &dfNatOriginLat ) == 0
2112 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2113 : &dfNatOriginLat ) == 0
2114 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2115 : &dfNatOriginLat ) == 0 )
2116 8 : dfNatOriginLat = 0.0;
2117 :
2118 8 : if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2119 : &dfNatOriginScale ) == 0 )
2120 8 : dfNatOriginScale = 1.0;
2121 :
2122 : /* notdef: should transform to decimal degrees at this point */
2123 :
2124 8 : psDefn->ProjParm[0] = dfNatOriginLat;
2125 8 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2126 8 : psDefn->ProjParm[1] = dfNatOriginLong;
2127 8 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2128 8 : psDefn->ProjParm[4] = dfNatOriginScale;
2129 8 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2130 8 : psDefn->ProjParm[5] = dfFalseEasting;
2131 8 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2132 8 : psDefn->ProjParm[6] = dfFalseNorthing;
2133 8 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2134 :
2135 8 : psDefn->nParms = 7;
2136 8 : break;
2137 :
2138 : /* -------------------------------------------------------------------- */
2139 : case CT_ObliqueMercator: /* hotine */
2140 : /* -------------------------------------------------------------------- */
2141 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2142 : &dfNatOriginLong ) == 0
2143 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2144 : &dfNatOriginLong ) == 0
2145 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2146 : &dfNatOriginLong ) == 0 )
2147 0 : dfNatOriginLong = 0.0;
2148 :
2149 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2150 : &dfNatOriginLat ) == 0
2151 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2152 : &dfNatOriginLat ) == 0
2153 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2154 : &dfNatOriginLat ) == 0 )
2155 0 : dfNatOriginLat = 0.0;
2156 :
2157 0 : if( GetMetadataElement( "GEOTIFF_NUM::3094::ProjAzimuthAngleGeoKey",
2158 : &dfAzimuth ) == 0 )
2159 0 : dfAzimuth = 0.0;
2160 :
2161 0 : if( GetMetadataElement( "GEOTIFF_NUM::3096::ProjRectifiedGridAngleGeoKey",
2162 : &dfRectGridAngle ) == 0 )
2163 0 : dfRectGridAngle = 90.0;
2164 :
2165 0 : if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2166 : &dfNatOriginScale ) == 0
2167 : && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2168 : &dfNatOriginScale ) == 0 )
2169 0 : dfNatOriginScale = 1.0;
2170 :
2171 : /* notdef: should transform to decimal degrees at this point */
2172 :
2173 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2174 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2175 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2176 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2177 0 : psDefn->ProjParm[2] = dfAzimuth;
2178 0 : psDefn->ProjParmId[2] = ProjAzimuthAngleGeoKey;
2179 0 : psDefn->ProjParm[3] = dfRectGridAngle;
2180 0 : psDefn->ProjParmId[3] = ProjRectifiedGridAngleGeoKey;
2181 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2182 0 : psDefn->ProjParmId[4] = ProjScaleAtCenterGeoKey;
2183 0 : psDefn->ProjParm[5] = dfFalseEasting;
2184 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2185 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2186 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2187 :
2188 0 : psDefn->nParms = 7;
2189 0 : break;
2190 :
2191 : /* -------------------------------------------------------------------- */
2192 : case CT_CassiniSoldner:
2193 : case CT_Polyconic:
2194 : /* -------------------------------------------------------------------- */
2195 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2196 : &dfNatOriginLong ) == 0
2197 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2198 : &dfNatOriginLong ) == 0
2199 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2200 : &dfNatOriginLong ) == 0 )
2201 0 : dfNatOriginLong = 0.0;
2202 :
2203 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2204 : &dfNatOriginLat ) == 0
2205 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2206 : &dfNatOriginLat ) == 0
2207 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2208 : &dfNatOriginLat ) == 0 )
2209 0 : dfNatOriginLat = 0.0;
2210 :
2211 :
2212 0 : if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2213 : &dfNatOriginScale ) == 0
2214 : && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2215 : &dfNatOriginScale ) == 0 )
2216 0 : dfNatOriginScale = 1.0;
2217 :
2218 : /* notdef: should transform to decimal degrees at this point */
2219 :
2220 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2221 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2222 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2223 0 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2224 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2225 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2226 0 : psDefn->ProjParm[5] = dfFalseEasting;
2227 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2228 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2229 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2230 :
2231 0 : psDefn->nParms = 7;
2232 0 : break;
2233 :
2234 : /* -------------------------------------------------------------------- */
2235 : case CT_AzimuthalEquidistant:
2236 : case CT_MillerCylindrical:
2237 : case CT_Equirectangular:
2238 : case CT_Gnomonic:
2239 : case CT_LambertAzimEqualArea:
2240 : case CT_Orthographic:
2241 : /* -------------------------------------------------------------------- */
2242 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2243 : &dfNatOriginLong ) == 0
2244 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2245 : &dfNatOriginLong ) == 0
2246 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2247 : &dfNatOriginLong ) == 0 )
2248 0 : dfNatOriginLong = 0.0;
2249 :
2250 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2251 : &dfNatOriginLat ) == 0
2252 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2253 : &dfNatOriginLat ) == 0
2254 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2255 : &dfNatOriginLat ) == 0 )
2256 0 : dfNatOriginLat = 0.0;
2257 :
2258 : /* notdef: should transform to decimal degrees at this point */
2259 :
2260 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2261 0 : psDefn->ProjParmId[0] = ProjCenterLatGeoKey;
2262 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2263 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2264 0 : psDefn->ProjParm[5] = dfFalseEasting;
2265 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2266 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2267 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2268 :
2269 0 : psDefn->nParms = 7;
2270 0 : break;
2271 :
2272 : /* -------------------------------------------------------------------- */
2273 : case CT_Robinson:
2274 : case CT_Sinusoidal:
2275 : case CT_VanDerGrinten:
2276 : /* -------------------------------------------------------------------- */
2277 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2278 : &dfNatOriginLong ) == 0
2279 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2280 : &dfNatOriginLong ) == 0
2281 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2282 : &dfNatOriginLong ) == 0 )
2283 0 : dfNatOriginLong = 0.0;
2284 :
2285 : /* notdef: should transform to decimal degrees at this point */
2286 :
2287 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2288 0 : psDefn->ProjParmId[1] = ProjCenterLongGeoKey;
2289 0 : psDefn->ProjParm[5] = dfFalseEasting;
2290 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2291 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2292 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2293 :
2294 0 : psDefn->nParms = 7;
2295 0 : break;
2296 :
2297 : /* -------------------------------------------------------------------- */
2298 : case CT_PolarStereographic:
2299 : /* -------------------------------------------------------------------- */
2300 0 : if( GetMetadataElement( "GEOTIFF_NUM::3095::ProjStraightVertPoleLongGeoKey",
2301 : &dfNatOriginLong ) == 0
2302 : && GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2303 : &dfNatOriginLong ) == 0
2304 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2305 : &dfNatOriginLong ) == 0
2306 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2307 : &dfNatOriginLong ) == 0 )
2308 0 : dfNatOriginLong = 0.0;
2309 :
2310 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2311 : &dfNatOriginLat ) == 0
2312 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2313 : &dfNatOriginLat ) == 0
2314 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2315 : &dfNatOriginLat ) == 0 )
2316 0 : dfNatOriginLat = 0.0;
2317 :
2318 0 : if( GetMetadataElement( "GEOTIFF_NUM::3092::ProjScaleAtNatOriginGeoKey",
2319 : &dfNatOriginScale ) == 0
2320 : && GetMetadataElement( "GEOTIFF_NUM::3093::ProjScaleAtCenterGeoKey",
2321 : &dfNatOriginScale ) == 0 )
2322 0 : dfNatOriginScale = 1.0;
2323 :
2324 : /* notdef: should transform to decimal degrees at this point */
2325 :
2326 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2327 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;;
2328 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2329 0 : psDefn->ProjParmId[1] = ProjStraightVertPoleLongGeoKey;
2330 0 : psDefn->ProjParm[4] = dfNatOriginScale;
2331 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2332 0 : psDefn->ProjParm[5] = dfFalseEasting;
2333 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2334 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2335 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2336 :
2337 0 : psDefn->nParms = 7;
2338 0 : break;
2339 :
2340 : /* -------------------------------------------------------------------- */
2341 : case CT_LambertConfConic_2SP:
2342 : /* -------------------------------------------------------------------- */
2343 0 : if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
2344 : &dfStdParallel1 ) == 0 )
2345 0 : dfStdParallel1 = 0.0;
2346 :
2347 0 : if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
2348 : &dfStdParallel2 ) == 0 )
2349 0 : dfStdParallel1 = 0.0;
2350 :
2351 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2352 : &dfNatOriginLong ) == 0
2353 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2354 : &dfNatOriginLong ) == 0
2355 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2356 : &dfNatOriginLong ) == 0 )
2357 0 : dfNatOriginLong = 0.0;
2358 :
2359 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2360 : &dfNatOriginLat ) == 0
2361 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2362 : &dfNatOriginLat ) == 0
2363 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2364 : &dfNatOriginLat ) == 0 )
2365 0 : dfNatOriginLat = 0.0;
2366 :
2367 : /* notdef: should transform to decimal degrees at this point */
2368 :
2369 0 : psDefn->ProjParm[0] = dfNatOriginLat;
2370 0 : psDefn->ProjParmId[0] = ProjFalseOriginLatGeoKey;
2371 0 : psDefn->ProjParm[1] = dfNatOriginLong;
2372 0 : psDefn->ProjParmId[1] = ProjFalseOriginLongGeoKey;
2373 0 : psDefn->ProjParm[2] = dfStdParallel1;
2374 0 : psDefn->ProjParmId[2] = ProjStdParallel1GeoKey;
2375 0 : psDefn->ProjParm[3] = dfStdParallel2;
2376 0 : psDefn->ProjParmId[3] = ProjStdParallel2GeoKey;
2377 0 : psDefn->ProjParm[5] = dfFalseEasting;
2378 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2379 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2380 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2381 :
2382 0 : psDefn->nParms = 7;
2383 0 : break;
2384 :
2385 : /* -------------------------------------------------------------------- */
2386 : case CT_AlbersEqualArea:
2387 : case CT_EquidistantConic:
2388 : /* -------------------------------------------------------------------- */
2389 0 : if( GetMetadataElement( "GEOTIFF_NUM::3078::ProjStdParallel1GeoKey",
2390 : &dfStdParallel1 ) == 0 )
2391 0 : dfStdParallel1 = 0.0;
2392 :
2393 0 : if( GetMetadataElement( "GEOTIFF_NUM::3079::ProjStdParallel2GeoKey",
2394 : &dfStdParallel2 ) == 0 )
2395 0 : dfStdParallel1 = 0.0;
2396 :
2397 0 : if( GetMetadataElement( "GEOTIFF_NUM::3080::ProjNatOriginLongGeoKey",
2398 : &dfNatOriginLong ) == 0
2399 : && GetMetadataElement( "GEOTIFF_NUM::3084::ProjFalseOriginLongGeoKey",
2400 : &dfNatOriginLong ) == 0
2401 : && GetMetadataElement( "GEOTIFF_NUM::3088::ProjCenterLongGeoKey",
2402 : &dfNatOriginLong ) == 0 )
2403 0 : dfNatOriginLong = 0.0;
2404 :
2405 0 : if( GetMetadataElement( "GEOTIFF_NUM::3081::ProjNatOriginLatGeoKey",
2406 : &dfNatOriginLat ) == 0
2407 : && GetMetadataElement( "GEOTIFF_NUM::3085::ProjFalseOriginLatGeoKey",
2408 : &dfNatOriginLat ) == 0
2409 : && GetMetadataElement( "GEOTIFF_NUM::3089::ProjCenterLatGeoKey",
2410 : &dfNatOriginLat ) == 0 )
2411 0 : dfNatOriginLat = 0.0;
2412 :
2413 : /* notdef: should transform to decimal degrees at this point */
2414 :
2415 0 : psDefn->ProjParm[0] = dfStdParallel1;
2416 0 : psDefn->ProjParmId[0] = ProjStdParallel1GeoKey;
2417 0 : psDefn->ProjParm[1] = dfStdParallel2;
2418 0 : psDefn->ProjParmId[1] = ProjStdParallel2GeoKey;
2419 0 : psDefn->ProjParm[2] = dfNatOriginLat;
2420 0 : psDefn->ProjParmId[2] = ProjNatOriginLatGeoKey;
2421 0 : psDefn->ProjParm[3] = dfNatOriginLong;
2422 0 : psDefn->ProjParmId[3] = ProjNatOriginLongGeoKey;
2423 0 : psDefn->ProjParm[5] = dfFalseEasting;
2424 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2425 0 : psDefn->ProjParm[6] = dfFalseNorthing;
2426 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2427 :
2428 0 : psDefn->nParms = 7;
2429 : break;
2430 : }
2431 8 : }
2432 :
2433 : /************************************************************************/
2434 : /* GetGTIFDefn() */
2435 : /* This function borrowed from the GTIFGetDefn() function. */
2436 : /* See geo_normalize.c from the GeoTIFF package. */
2437 : /************************************************************************/
2438 :
2439 27 : void MrSIDDataset::GetGTIFDefn()
2440 : {
2441 : double dfInvFlattening;
2442 :
2443 : /* -------------------------------------------------------------------- */
2444 : /* Initially we default all the information we can. */
2445 : /* -------------------------------------------------------------------- */
2446 27 : psDefn = new( GTIFDefn );
2447 27 : psDefn->Model = KvUserDefined;
2448 27 : psDefn->PCS = KvUserDefined;
2449 27 : psDefn->GCS = KvUserDefined;
2450 27 : psDefn->UOMLength = KvUserDefined;
2451 27 : psDefn->UOMLengthInMeters = 1.0;
2452 27 : psDefn->UOMAngle = KvUserDefined;
2453 27 : psDefn->UOMAngleInDegrees = 1.0;
2454 27 : psDefn->Datum = KvUserDefined;
2455 27 : psDefn->Ellipsoid = KvUserDefined;
2456 27 : psDefn->SemiMajor = 0.0;
2457 27 : psDefn->SemiMinor = 0.0;
2458 27 : psDefn->PM = KvUserDefined;
2459 27 : psDefn->PMLongToGreenwich = 0.0;
2460 :
2461 27 : psDefn->ProjCode = KvUserDefined;
2462 27 : psDefn->Projection = KvUserDefined;
2463 27 : psDefn->CTProjection = KvUserDefined;
2464 :
2465 27 : psDefn->nParms = 0;
2466 297 : for( int i = 0; i < MAX_GTIF_PROJPARMS; i++ )
2467 : {
2468 270 : psDefn->ProjParm[i] = 0.0;
2469 270 : psDefn->ProjParmId[i] = 0;
2470 : }
2471 :
2472 27 : psDefn->MapSys = KvUserDefined;
2473 27 : psDefn->Zone = 0;
2474 :
2475 : /* -------------------------------------------------------------------- */
2476 : /* Try to get the overall model type. */
2477 : /* -------------------------------------------------------------------- */
2478 : GetMetadataElement( "GEOTIFF_NUM::1024::GTModelTypeGeoKey",
2479 27 : &(psDefn->Model) );
2480 :
2481 : /* -------------------------------------------------------------------- */
2482 : /* Try to get a PCS. */
2483 : /* -------------------------------------------------------------------- */
2484 27 : if( GetMetadataElement( "GEOTIFF_NUM::3072::ProjectedCSTypeGeoKey",
2485 : &(psDefn->PCS) )
2486 : && psDefn->PCS != KvUserDefined )
2487 : {
2488 : /*
2489 : * Translate this into useful information.
2490 : */
2491 : GTIFGetPCSInfo( psDefn->PCS, NULL, &(psDefn->ProjCode),
2492 5 : &(psDefn->UOMLength), &(psDefn->GCS) );
2493 : }
2494 :
2495 : /* -------------------------------------------------------------------- */
2496 : /* If we have the PCS code, but didn't find it in the CSV files */
2497 : /* (likely because we can't find them) we will try some ``jiffy */
2498 : /* rules'' for UTM and state plane. */
2499 : /* -------------------------------------------------------------------- */
2500 27 : if( psDefn->PCS != KvUserDefined && psDefn->ProjCode == KvUserDefined )
2501 : {
2502 : int nMapSys, nZone;
2503 0 : int nGCS = psDefn->GCS;
2504 :
2505 0 : nMapSys = GTIFPCSToMapSys( psDefn->PCS, &nGCS, &nZone );
2506 0 : if( nMapSys != KvUserDefined )
2507 : {
2508 0 : psDefn->ProjCode = (short) GTIFMapSysToProj( nMapSys, nZone );
2509 0 : psDefn->GCS = (short) nGCS;
2510 : }
2511 : }
2512 :
2513 : /* -------------------------------------------------------------------- */
2514 : /* If the Proj_ code is specified directly, use that. */
2515 : /* -------------------------------------------------------------------- */
2516 27 : if( psDefn->ProjCode == KvUserDefined )
2517 : GetMetadataElement( "GEOTIFF_NUM::3074::ProjectionGeoKey",
2518 22 : &(psDefn->ProjCode) );
2519 :
2520 27 : if( psDefn->ProjCode != KvUserDefined )
2521 : {
2522 : /*
2523 : * We have an underlying projection transformation value. Look
2524 : * this up. For a PCS of ``WGS 84 / UTM 11'' the transformation
2525 : * would be Transverse Mercator, with a particular set of options.
2526 : * The nProjTRFCode itself would correspond to the name
2527 : * ``UTM zone 11N'', and doesn't include datum info.
2528 : */
2529 : GTIFGetProjTRFInfo( psDefn->ProjCode, NULL, &(psDefn->Projection),
2530 5 : psDefn->ProjParm );
2531 :
2532 : /*
2533 : * Set the GeoTIFF identity of the parameters.
2534 : */
2535 : psDefn->CTProjection = (short)
2536 5 : EPSGProjMethodToCTProjMethod( psDefn->Projection );
2537 :
2538 5 : SetGTParmIds( psDefn->CTProjection, psDefn->ProjParmId, NULL);
2539 5 : psDefn->nParms = 7;
2540 : }
2541 :
2542 : /* -------------------------------------------------------------------- */
2543 : /* Try to get a GCS. If found, it will override any implied by */
2544 : /* the PCS. */
2545 : /* -------------------------------------------------------------------- */
2546 : GetMetadataElement( "GEOTIFF_NUM::2048::GeographicTypeGeoKey",
2547 27 : &(psDefn->GCS) );
2548 :
2549 : /* -------------------------------------------------------------------- */
2550 : /* Derive the datum, and prime meridian from the GCS. */
2551 : /* -------------------------------------------------------------------- */
2552 27 : if( psDefn->GCS != KvUserDefined )
2553 : {
2554 : GTIFGetGCSInfo( psDefn->GCS, NULL, &(psDefn->Datum), &(psDefn->PM),
2555 15 : &(psDefn->UOMAngle) );
2556 : }
2557 :
2558 : /* -------------------------------------------------------------------- */
2559 : /* Handle the GCS angular units. GeogAngularUnitsGeoKey */
2560 : /* overrides the GCS or PCS setting. */
2561 : /* -------------------------------------------------------------------- */
2562 : GetMetadataElement( "GEOTIFF_NUM::2054::GeogAngularUnitsGeoKey",
2563 27 : &(psDefn->UOMAngle) );
2564 27 : if( psDefn->UOMAngle != KvUserDefined )
2565 : {
2566 : GTIFGetUOMAngleInfo( psDefn->UOMAngle, NULL,
2567 15 : &(psDefn->UOMAngleInDegrees) );
2568 : }
2569 :
2570 : /* -------------------------------------------------------------------- */
2571 : /* Check for a datum setting, and then use the datum to derive */
2572 : /* an ellipsoid. */
2573 : /* -------------------------------------------------------------------- */
2574 : GetMetadataElement( "GEOTIFF_NUM::2050::GeogGeodeticDatumGeoKey",
2575 27 : &(psDefn->Datum) );
2576 :
2577 27 : if( psDefn->Datum != KvUserDefined )
2578 : {
2579 15 : GTIFGetDatumInfo( psDefn->Datum, NULL, &(psDefn->Ellipsoid) );
2580 : }
2581 :
2582 : /* -------------------------------------------------------------------- */
2583 : /* Check for an explicit ellipsoid. Use the ellipsoid to */
2584 : /* derive the ellipsoid characteristics, if possible. */
2585 : /* -------------------------------------------------------------------- */
2586 : GetMetadataElement( "GEOTIFF_NUM::2056::GeogEllipsoidGeoKey",
2587 27 : &(psDefn->Ellipsoid) );
2588 :
2589 27 : if( psDefn->Ellipsoid != KvUserDefined )
2590 : {
2591 : GTIFGetEllipsoidInfo( psDefn->Ellipsoid, NULL,
2592 15 : &(psDefn->SemiMajor), &(psDefn->SemiMinor) );
2593 : }
2594 :
2595 : /* -------------------------------------------------------------------- */
2596 : /* Check for overridden ellipsoid parameters. It would be nice */
2597 : /* to warn if they conflict with provided information, but for */
2598 : /* now we just override. */
2599 : /* -------------------------------------------------------------------- */
2600 : GetMetadataElement( "GEOTIFF_NUM::2057::GeogSemiMajorAxisGeoKey",
2601 27 : &(psDefn->SemiMajor) );
2602 : GetMetadataElement( "GEOTIFF_NUM::2058::GeogSemiMinorAxisGeoKey",
2603 27 : &(psDefn->SemiMinor) );
2604 :
2605 27 : if( GetMetadataElement( "GEOTIFF_NUM::2059::GeogInvFlatteningGeoKey",
2606 : &dfInvFlattening ) == 1 )
2607 : {
2608 0 : if( dfInvFlattening != 0.0 )
2609 : psDefn->SemiMinor =
2610 0 : psDefn->SemiMajor * (1 - 1.0/dfInvFlattening);
2611 : }
2612 :
2613 : /* -------------------------------------------------------------------- */
2614 : /* Get the prime meridian info. */
2615 : /* -------------------------------------------------------------------- */
2616 : GetMetadataElement( "GEOTIFF_NUM::2051::GeogPrimeMeridianGeoKey",
2617 27 : &(psDefn->PM) );
2618 :
2619 27 : if( psDefn->PM != KvUserDefined )
2620 : {
2621 15 : GTIFGetPMInfo( psDefn->PM, NULL, &(psDefn->PMLongToGreenwich) );
2622 : }
2623 : else
2624 : {
2625 : GetMetadataElement( "GEOTIFF_NUM::2061::GeogPrimeMeridianLongGeoKey",
2626 12 : &(psDefn->PMLongToGreenwich) );
2627 :
2628 : psDefn->PMLongToGreenwich =
2629 : GTIFAngleToDD( psDefn->PMLongToGreenwich,
2630 12 : psDefn->UOMAngle );
2631 : }
2632 :
2633 : /* -------------------------------------------------------------------- */
2634 : /* Have the projection units of measure been overridden? We */
2635 : /* should likely be doing something about angular units too, */
2636 : /* but these are very rarely not decimal degrees for actual */
2637 : /* file coordinates. */
2638 : /* -------------------------------------------------------------------- */
2639 : GetMetadataElement( "GEOTIFF_NUM::3076::ProjLinearUnitsGeoKey",
2640 27 : &(psDefn->UOMLength) );
2641 :
2642 27 : if( psDefn->UOMLength != KvUserDefined )
2643 : {
2644 : GTIFGetUOMLengthInfo( psDefn->UOMLength, NULL,
2645 13 : &(psDefn->UOMLengthInMeters) );
2646 : }
2647 :
2648 : /* -------------------------------------------------------------------- */
2649 : /* Handle a variety of user defined transform types. */
2650 : /* -------------------------------------------------------------------- */
2651 27 : if( GetMetadataElement( "GEOTIFF_NUM::3075::ProjCoordTransGeoKey",
2652 : &(psDefn->CTProjection) ) )
2653 : {
2654 8 : FetchProjParms();
2655 : }
2656 :
2657 : /* -------------------------------------------------------------------- */
2658 : /* Try to set the zoned map system information. */
2659 : /* -------------------------------------------------------------------- */
2660 27 : psDefn->MapSys = GTIFProjToMapSys( psDefn->ProjCode, &(psDefn->Zone) );
2661 :
2662 : /* -------------------------------------------------------------------- */
2663 : /* If this is UTM, and we were unable to extract the projection */
2664 : /* parameters from the CSV file, just set them directly now, */
2665 : /* since it's pretty easy, and a common case. */
2666 : /* -------------------------------------------------------------------- */
2667 27 : if( (psDefn->MapSys == MapSys_UTM_North
2668 : || psDefn->MapSys == MapSys_UTM_South)
2669 : && psDefn->CTProjection == KvUserDefined )
2670 : {
2671 0 : psDefn->CTProjection = CT_TransverseMercator;
2672 0 : psDefn->nParms = 7;
2673 0 : psDefn->ProjParmId[0] = ProjNatOriginLatGeoKey;
2674 0 : psDefn->ProjParm[0] = 0.0;
2675 :
2676 0 : psDefn->ProjParmId[1] = ProjNatOriginLongGeoKey;
2677 0 : psDefn->ProjParm[1] = psDefn->Zone*6 - 183.0;
2678 :
2679 0 : psDefn->ProjParmId[4] = ProjScaleAtNatOriginGeoKey;
2680 0 : psDefn->ProjParm[4] = 0.9996;
2681 :
2682 0 : psDefn->ProjParmId[5] = ProjFalseEastingGeoKey;
2683 0 : psDefn->ProjParm[5] = 500000.0;
2684 :
2685 0 : psDefn->ProjParmId[6] = ProjFalseNorthingGeoKey;
2686 :
2687 0 : if( psDefn->MapSys == MapSys_UTM_North )
2688 0 : psDefn->ProjParm[6] = 0.0;
2689 : else
2690 0 : psDefn->ProjParm[6] = 10000000.0;
2691 : }
2692 :
2693 27 : if ( pszProjection )
2694 27 : CPLFree( pszProjection );
2695 27 : pszProjection = GetOGISDefn( psDefn );
2696 27 : }
2697 :
2698 :
2699 : /************************************************************************/
2700 : /* GTIFToCPLRecyleString() */
2701 : /* */
2702 : /* This changes a string from the libgeotiff heap to the GDAL */
2703 : /* heap. */
2704 : /************************************************************************/
2705 :
2706 74 : static void GTIFToCPLRecycleString( char **ppszTarget )
2707 :
2708 : {
2709 74 : if( *ppszTarget == NULL )
2710 0 : return;
2711 :
2712 74 : char *pszTempString = CPLStrdup(*ppszTarget);
2713 74 : GTIFFreeMemory( *ppszTarget );
2714 74 : *ppszTarget = pszTempString;
2715 : }
2716 :
2717 : /************************************************************************/
2718 : /* GetOGISDefn() */
2719 : /* Copied from the gt_wkt_srs.cpp. */
2720 : /************************************************************************/
2721 :
2722 27 : char *MrSIDDataset::GetOGISDefn( GTIFDefn *psDefn )
2723 : {
2724 27 : OGRSpatialReference oSRS;
2725 :
2726 27 : if( psDefn->Model != ModelTypeProjected
2727 : && psDefn->Model != ModelTypeGeographic )
2728 12 : return CPLStrdup("");
2729 :
2730 : /* -------------------------------------------------------------------- */
2731 : /* If this is a projected SRS we set the PROJCS keyword first */
2732 : /* to ensure that the GEOGCS will be a child. */
2733 : /* -------------------------------------------------------------------- */
2734 15 : if( psDefn->Model == ModelTypeProjected )
2735 : {
2736 : char *pszPCSName;
2737 13 : int bPCSNameSet = FALSE;
2738 :
2739 13 : if( psDefn->PCS != KvUserDefined )
2740 : {
2741 :
2742 5 : if( GTIFGetPCSInfo( psDefn->PCS, &pszPCSName, NULL, NULL, NULL ) )
2743 5 : bPCSNameSet = TRUE;
2744 :
2745 5 : oSRS.SetNode( "PROJCS", bPCSNameSet ? pszPCSName : "unnamed" );
2746 5 : if( bPCSNameSet )
2747 5 : GTIFFreeMemory( pszPCSName );
2748 :
2749 5 : oSRS.SetAuthority( "PROJCS", "EPSG", psDefn->PCS );
2750 : }
2751 : else
2752 : {
2753 : char szPCSName[200];
2754 8 : strcpy( szPCSName, "unnamed" );
2755 8 : if ( GetMetadataElement( "GEOTIFF_NUM::1026::GTCitationGeoKey",
2756 : szPCSName, sizeof(szPCSName) ) )
2757 8 : oSRS.SetNode( "PROJCS", szPCSName );
2758 : }
2759 : }
2760 :
2761 : /* ==================================================================== */
2762 : /* Setup the GeogCS */
2763 : /* ==================================================================== */
2764 15 : char *pszGeogName = NULL;
2765 15 : char *pszDatumName = NULL;
2766 15 : char *pszPMName = NULL;
2767 15 : char *pszSpheroidName = NULL;
2768 15 : char *pszAngularUnits = NULL;
2769 : double dfInvFlattening, dfSemiMajor;
2770 : char szGCSName[200];
2771 :
2772 15 : if( GetMetadataElement( "GEOTIFF_NUM::2049::GeogCitationGeoKey",
2773 : szGCSName, sizeof(szGCSName) ) )
2774 1 : pszGeogName = CPLStrdup(szGCSName);
2775 : else
2776 : {
2777 14 : GTIFGetGCSInfo( psDefn->GCS, &pszGeogName, NULL, NULL, NULL );
2778 14 : GTIFToCPLRecycleString(&pszGeogName);
2779 : }
2780 15 : GTIFGetDatumInfo( psDefn->Datum, &pszDatumName, NULL );
2781 15 : GTIFToCPLRecycleString(&pszDatumName);
2782 15 : GTIFGetPMInfo( psDefn->PM, &pszPMName, NULL );
2783 15 : GTIFToCPLRecycleString(&pszPMName);
2784 15 : GTIFGetEllipsoidInfo( psDefn->Ellipsoid, &pszSpheroidName, NULL, NULL );
2785 15 : GTIFToCPLRecycleString(&pszSpheroidName);
2786 :
2787 15 : GTIFGetUOMAngleInfo( psDefn->UOMAngle, &pszAngularUnits, NULL );
2788 15 : GTIFToCPLRecycleString(&pszAngularUnits);
2789 15 : if( pszAngularUnits == NULL )
2790 0 : pszAngularUnits = CPLStrdup("unknown");
2791 :
2792 15 : if( pszDatumName != NULL )
2793 15 : WKTMassageDatum( &pszDatumName );
2794 :
2795 15 : dfSemiMajor = psDefn->SemiMajor;
2796 15 : if( psDefn->SemiMajor == 0.0 )
2797 : {
2798 0 : pszSpheroidName = CPLStrdup("unretrievable - using WGS84");
2799 0 : dfSemiMajor = SRS_WGS84_SEMIMAJOR;
2800 0 : dfInvFlattening = SRS_WGS84_INVFLATTENING;
2801 : }
2802 30 : else if( (psDefn->SemiMinor / psDefn->SemiMajor) < 0.99999999999999999
2803 : || (psDefn->SemiMinor / psDefn->SemiMajor) > 1.00000000000000001 )
2804 15 : dfInvFlattening = -1.0 / (psDefn->SemiMinor/psDefn->SemiMajor - 1.0);
2805 : else
2806 0 : dfInvFlattening = 0.0; /* special flag for infinity */
2807 :
2808 : oSRS.SetGeogCS( pszGeogName, pszDatumName,
2809 : pszSpheroidName, dfSemiMajor, dfInvFlattening,
2810 : pszPMName,
2811 : psDefn->PMLongToGreenwich / psDefn->UOMAngleInDegrees,
2812 : pszAngularUnits,
2813 15 : psDefn->UOMAngleInDegrees * 0.0174532925199433 );
2814 :
2815 15 : if( psDefn->GCS != KvUserDefined )
2816 15 : oSRS.SetAuthority( "GEOGCS", "EPSG", psDefn->GCS );
2817 :
2818 15 : if( psDefn->Datum != KvUserDefined )
2819 15 : oSRS.SetAuthority( "DATUM", "EPSG", psDefn->Datum );
2820 :
2821 15 : if( psDefn->Ellipsoid != KvUserDefined )
2822 15 : oSRS.SetAuthority( "SPHEROID", "EPSG", psDefn->Ellipsoid );
2823 :
2824 15 : CPLFree( pszGeogName );
2825 15 : CPLFree( pszDatumName );
2826 15 : CPLFree( pszPMName );
2827 15 : CPLFree( pszSpheroidName );
2828 15 : CPLFree( pszAngularUnits );
2829 :
2830 : /* ==================================================================== */
2831 : /* Handle projection parameters. */
2832 : /* ==================================================================== */
2833 15 : if( psDefn->Model == ModelTypeProjected )
2834 : {
2835 : /* -------------------------------------------------------------------- */
2836 : /* Make a local copy of parms, and convert back into the */
2837 : /* angular units of the GEOGCS and the linear units of the */
2838 : /* projection. */
2839 : /* -------------------------------------------------------------------- */
2840 : double adfParm[10];
2841 : int i;
2842 :
2843 104 : for( i = 0; i < MIN(10,psDefn->nParms); i++ )
2844 91 : adfParm[i] = psDefn->ProjParm[i];
2845 :
2846 13 : adfParm[0] /= psDefn->UOMAngleInDegrees;
2847 13 : adfParm[1] /= psDefn->UOMAngleInDegrees;
2848 13 : adfParm[2] /= psDefn->UOMAngleInDegrees;
2849 13 : adfParm[3] /= psDefn->UOMAngleInDegrees;
2850 :
2851 13 : adfParm[5] /= psDefn->UOMLengthInMeters;
2852 13 : adfParm[6] /= psDefn->UOMLengthInMeters;
2853 :
2854 : /* -------------------------------------------------------------------- */
2855 : /* Translation the fundamental projection. */
2856 : /* -------------------------------------------------------------------- */
2857 13 : switch( psDefn->CTProjection )
2858 : {
2859 : case CT_TransverseMercator:
2860 : oSRS.SetTM( adfParm[0], adfParm[1],
2861 : adfParm[4],
2862 5 : adfParm[5], adfParm[6] );
2863 5 : break;
2864 :
2865 : case CT_TransvMercator_SouthOriented:
2866 : oSRS.SetTMSO( adfParm[0], adfParm[1],
2867 : adfParm[4],
2868 0 : adfParm[5], adfParm[6] );
2869 0 : break;
2870 :
2871 : case CT_Mercator:
2872 : oSRS.SetMercator( adfParm[0], adfParm[1],
2873 : adfParm[4],
2874 8 : adfParm[5], adfParm[6] );
2875 8 : break;
2876 :
2877 : case CT_ObliqueStereographic:
2878 : oSRS.SetOS( adfParm[0], adfParm[1],
2879 : adfParm[4],
2880 0 : adfParm[5], adfParm[6] );
2881 0 : break;
2882 :
2883 : case CT_Stereographic:
2884 : oSRS.SetOS( adfParm[0], adfParm[1],
2885 : adfParm[4],
2886 0 : adfParm[5], adfParm[6] );
2887 0 : break;
2888 :
2889 : case CT_ObliqueMercator: /* hotine */
2890 : oSRS.SetHOM( adfParm[0], adfParm[1],
2891 : adfParm[2], adfParm[3],
2892 : adfParm[4],
2893 0 : adfParm[5], adfParm[6] );
2894 0 : break;
2895 :
2896 : case CT_EquidistantConic:
2897 : oSRS.SetEC( adfParm[0], adfParm[1],
2898 : adfParm[2], adfParm[3],
2899 0 : adfParm[5], adfParm[6] );
2900 0 : break;
2901 :
2902 : case CT_CassiniSoldner:
2903 : oSRS.SetCS( adfParm[0], adfParm[1],
2904 0 : adfParm[5], adfParm[6] );
2905 0 : break;
2906 :
2907 : case CT_Polyconic:
2908 : oSRS.SetPolyconic( adfParm[0], adfParm[1],
2909 0 : adfParm[5], adfParm[6] );
2910 0 : break;
2911 :
2912 : case CT_AzimuthalEquidistant:
2913 : oSRS.SetAE( adfParm[0], adfParm[1],
2914 0 : adfParm[5], adfParm[6] );
2915 0 : break;
2916 :
2917 : case CT_MillerCylindrical:
2918 : oSRS.SetMC( adfParm[0], adfParm[1],
2919 0 : adfParm[5], adfParm[6] );
2920 0 : break;
2921 :
2922 : case CT_Equirectangular:
2923 : oSRS.SetEquirectangular( adfParm[0], adfParm[1],
2924 0 : adfParm[5], adfParm[6] );
2925 0 : break;
2926 :
2927 : case CT_Gnomonic:
2928 : oSRS.SetGnomonic( adfParm[0], adfParm[1],
2929 0 : adfParm[5], adfParm[6] );
2930 0 : break;
2931 :
2932 : case CT_LambertAzimEqualArea:
2933 : oSRS.SetLAEA( adfParm[0], adfParm[1],
2934 0 : adfParm[5], adfParm[6] );
2935 0 : break;
2936 :
2937 : case CT_Orthographic:
2938 : oSRS.SetOrthographic( adfParm[0], adfParm[1],
2939 0 : adfParm[5], adfParm[6] );
2940 0 : break;
2941 :
2942 : case CT_Robinson:
2943 : oSRS.SetRobinson( adfParm[1],
2944 0 : adfParm[5], adfParm[6] );
2945 0 : break;
2946 :
2947 : case CT_Sinusoidal:
2948 : oSRS.SetSinusoidal( adfParm[1],
2949 0 : adfParm[5], adfParm[6] );
2950 0 : break;
2951 :
2952 : case CT_VanDerGrinten:
2953 : oSRS.SetVDG( adfParm[1],
2954 0 : adfParm[5], adfParm[6] );
2955 0 : break;
2956 :
2957 : case CT_PolarStereographic:
2958 : oSRS.SetPS( adfParm[0], adfParm[1],
2959 : adfParm[4],
2960 0 : adfParm[5], adfParm[6] );
2961 0 : break;
2962 :
2963 : case CT_LambertConfConic_2SP:
2964 : oSRS.SetLCC( adfParm[2], adfParm[3],
2965 : adfParm[0], adfParm[1],
2966 0 : adfParm[5], adfParm[6] );
2967 0 : break;
2968 :
2969 : case CT_LambertConfConic_1SP:
2970 : oSRS.SetLCC1SP( adfParm[0], adfParm[1],
2971 : adfParm[4],
2972 0 : adfParm[5], adfParm[6] );
2973 0 : break;
2974 :
2975 : case CT_AlbersEqualArea:
2976 : oSRS.SetACEA( adfParm[0], adfParm[1],
2977 : adfParm[2], adfParm[3],
2978 0 : adfParm[5], adfParm[6] );
2979 0 : break;
2980 :
2981 : case CT_NewZealandMapGrid:
2982 : oSRS.SetNZMG( adfParm[0], adfParm[1],
2983 0 : adfParm[5], adfParm[6] );
2984 : break;
2985 : }
2986 :
2987 : /* -------------------------------------------------------------------- */
2988 : /* Set projection units. */
2989 : /* -------------------------------------------------------------------- */
2990 13 : char *pszUnitsName = NULL;
2991 :
2992 13 : GTIFGetUOMLengthInfo( psDefn->UOMLength, &pszUnitsName, NULL );
2993 :
2994 26 : if( pszUnitsName != NULL && psDefn->UOMLength != KvUserDefined )
2995 : {
2996 13 : oSRS.SetLinearUnits( pszUnitsName, psDefn->UOMLengthInMeters );
2997 13 : oSRS.SetAuthority( "PROJCS|UNIT", "EPSG", psDefn->UOMLength );
2998 : }
2999 : else
3000 0 : oSRS.SetLinearUnits( "unknown", psDefn->UOMLengthInMeters );
3001 :
3002 13 : GTIFFreeMemory( pszUnitsName );
3003 : }
3004 :
3005 : /* -------------------------------------------------------------------- */
3006 : /* Return the WKT serialization of the object. */
3007 : /* -------------------------------------------------------------------- */
3008 : char *pszWKT;
3009 :
3010 15 : oSRS.FixupOrdering();
3011 :
3012 15 : if( oSRS.exportToWkt( &pszWKT ) == OGRERR_NONE )
3013 15 : return pszWKT;
3014 : else
3015 0 : return NULL;
3016 : }
3017 :
3018 : #ifdef MRSID_ESDK
3019 :
3020 : /************************************************************************/
3021 : /* ==================================================================== */
3022 : /* MrSIDDummyImageReader */
3023 : /* */
3024 : /* This is a helper class to wrap GDAL calls in MrSID interface. */
3025 : /* ==================================================================== */
3026 : /************************************************************************/
3027 :
3028 : class MrSIDDummyImageReader : public LTIImageReader
3029 : {
3030 : public:
3031 :
3032 : MrSIDDummyImageReader( GDALDataset *poSrcDS );
3033 : ~MrSIDDummyImageReader();
3034 : LT_STATUS initialize();
3035 : lt_int64 getPhysicalFileSize(void) const { return 0; };
3036 :
3037 : private:
3038 : GDALDataset *poDS;
3039 : GDALDataType eDataType;
3040 : LTIDataType eSampleType;
3041 : const LTIPixel *poPixel;
3042 :
3043 : double adfGeoTransform[6];
3044 :
3045 : virtual LT_STATUS decodeStrip( LTISceneBuffer& stripBuffer,
3046 : const LTIScene& stripScene );
3047 : virtual LT_STATUS decodeBegin( const LTIScene& )
3048 : { return LT_STS_Success; };
3049 : virtual LT_STATUS decodeEnd() { return LT_STS_Success; };
3050 : };
3051 :
3052 : /************************************************************************/
3053 : /* MrSIDDummyImageReader() */
3054 : /************************************************************************/
3055 :
3056 : MrSIDDummyImageReader::MrSIDDummyImageReader( GDALDataset *poSrcDS ) :
3057 : LTIImageReader(), poDS(poSrcDS)
3058 : {
3059 : poPixel = NULL;
3060 : }
3061 :
3062 : /************************************************************************/
3063 : /* ~MrSIDDummyImageReader() */
3064 : /************************************************************************/
3065 :
3066 : MrSIDDummyImageReader::~MrSIDDummyImageReader()
3067 : {
3068 : if ( poPixel )
3069 : delete poPixel;
3070 : }
3071 :
3072 : /************************************************************************/
3073 : /* initialize() */
3074 : /************************************************************************/
3075 :
3076 : LT_STATUS MrSIDDummyImageReader::initialize()
3077 : {
3078 : LT_STATUS eStat = LT_STS_Uninit;
3079 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 6
3080 : if ( !LT_SUCCESS(eStat = LTIImageReader::init()) )
3081 : return eStat;
3082 : #else
3083 : if ( !LT_SUCCESS(eStat = LTIImageReader::initialize()) )
3084 : return eStat;
3085 : #endif
3086 :
3087 : lt_uint16 nBands = (lt_uint16)poDS->GetRasterCount();
3088 : LTIColorSpace eColorSpace = LTI_COLORSPACE_RGB;
3089 : switch ( nBands )
3090 : {
3091 : case 1:
3092 : eColorSpace = LTI_COLORSPACE_GRAYSCALE;
3093 : break;
3094 : case 3:
3095 : eColorSpace = LTI_COLORSPACE_RGB;
3096 : break;
3097 : default:
3098 : eColorSpace = LTI_COLORSPACE_MULTISPECTRAL;
3099 : break;
3100 : }
3101 :
3102 : eDataType = poDS->GetRasterBand(1)->GetRasterDataType();
3103 : switch ( eDataType )
3104 : {
3105 : case GDT_UInt16:
3106 : eSampleType = LTI_DATATYPE_UINT16;
3107 : break;
3108 : case GDT_Int16:
3109 : eSampleType = LTI_DATATYPE_SINT16;
3110 : break;
3111 : case GDT_UInt32:
3112 : eSampleType = LTI_DATATYPE_UINT32;
3113 : break;
3114 : case GDT_Int32:
3115 : eSampleType = LTI_DATATYPE_SINT32;
3116 : break;
3117 : case GDT_Float32:
3118 : eSampleType = LTI_DATATYPE_FLOAT32;
3119 : break;
3120 : case GDT_Float64:
3121 : eSampleType = LTI_DATATYPE_FLOAT64;
3122 : break;
3123 : case GDT_Byte:
3124 : default:
3125 : eSampleType = LTI_DATATYPE_UINT8;
3126 : break;
3127 : }
3128 :
3129 : poPixel = new LTIDLLPixel<LTIPixel>( eColorSpace, nBands, eSampleType );
3130 : if ( !LT_SUCCESS(setPixelProps(*poPixel)) )
3131 : return LT_STS_Failure;
3132 :
3133 : if ( !LT_SUCCESS(setDimensions(poDS->GetRasterXSize(),
3134 : poDS->GetRasterYSize())) )
3135 : return LT_STS_Failure;
3136 :
3137 : if ( poDS->GetGeoTransform( adfGeoTransform ) == CE_None )
3138 : {
3139 : #ifdef MRSID_SDK_40
3140 : LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
3141 : adfGeoTransform[3] + adfGeoTransform[5] / 2,
3142 : adfGeoTransform[1], adfGeoTransform[5],
3143 : adfGeoTransform[2], adfGeoTransform[4], NULL,
3144 : poDS->GetProjectionRef() );
3145 : #else
3146 : LTIGeoCoord oGeo( adfGeoTransform[0] + adfGeoTransform[1] / 2,
3147 : adfGeoTransform[3] + adfGeoTransform[5] / 2,
3148 : adfGeoTransform[1], adfGeoTransform[5],
3149 : adfGeoTransform[2], adfGeoTransform[4],
3150 : poDS->GetProjectionRef() );
3151 : #endif
3152 : if ( !LT_SUCCESS(setGeoCoord( oGeo )) )
3153 : return LT_STS_Failure;
3154 : }
3155 :
3156 : /*int bSuccess;
3157 : double dfNoDataValue = poDS->GetNoDataValue( &bSuccess );
3158 : if ( bSuccess )
3159 : {
3160 : LTIPixel oNoDataPixel( *poPixel );
3161 : lt_uint16 iBand;
3162 :
3163 : for (iBand = 0; iBand < (lt_uint16)poDS->GetRasterCount(); iBand++)
3164 : oNoDataPixel.setSampleValueFloat32( iBand, dfNoDataValue );
3165 : if ( !LT_SUCCESS(setNoDataPixel( &oNoDataPixel )) )
3166 : return LT_STS_Failure;
3167 : }*/
3168 :
3169 : setDefaultDynamicRange();
3170 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3171 : setClassicalMetadata();
3172 : #endif
3173 :
3174 : return LT_STS_Success;
3175 : }
3176 :
3177 : /************************************************************************/
3178 : /* decodeStrip() */
3179 : /************************************************************************/
3180 :
3181 : LT_STATUS MrSIDDummyImageReader::decodeStrip(LTISceneBuffer& stripData,
3182 : const LTIScene& stripScene)
3183 :
3184 : {
3185 : const lt_int32 nXOff = stripScene.getUpperLeftCol();
3186 : const lt_int32 nYOff = stripScene.getUpperLeftRow();
3187 : const lt_int32 nBufXSize = stripScene.getNumCols();
3188 : const lt_int32 nBufYSize = stripScene.getNumRows();
3189 : const lt_int32 nDataBufXSize = stripData.getTotalNumCols();
3190 : const lt_int32 nDataBufYSize = stripData.getTotalNumRows();
3191 : const lt_uint16 nBands = poPixel->getNumBands();
3192 :
3193 : void *pData = CPLMalloc(nDataBufXSize * nDataBufYSize * poPixel->getNumBytes());
3194 : if ( !pData )
3195 : {
3196 : CPLError( CE_Failure, CPLE_AppDefined,
3197 : "MrSIDDummyImageReader::decodeStrip(): "
3198 : "Cannot allocate enough space for scene buffer" );
3199 : return LT_STS_Failure;
3200 : }
3201 :
3202 : poDS->RasterIO( GF_Read, nXOff, nYOff, nBufXSize, nBufYSize,
3203 : pData, nBufXSize, nBufYSize, eDataType, nBands, NULL,
3204 : 0, 0, 0 );
3205 :
3206 : stripData.importDataBSQ( pData );
3207 : CPLFree( pData );
3208 : return LT_STS_Success;
3209 : }
3210 :
3211 : /************************************************************************/
3212 : /* FlushCache() */
3213 : /************************************************************************/
3214 :
3215 : void MrSIDDataset::FlushCache()
3216 :
3217 : {
3218 : GDALDataset::FlushCache();
3219 : }
3220 :
3221 : /************************************************************************/
3222 : /* MrSIDCreateCopy() */
3223 : /************************************************************************/
3224 :
3225 : static GDALDataset *
3226 : MrSIDCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
3227 : int bStrict, char ** papszOptions,
3228 : GDALProgressFunc pfnProgress, void * pProgressData )
3229 :
3230 : {
3231 : const char* pszVersion = CSLFetchNameValue(papszOptions, "VERSION");
3232 : #ifdef MRSID_HAVE_MG4WRITE
3233 : int iVersion = pszVersion ? atoi(pszVersion) : 4;
3234 : #else
3235 : int iVersion = pszVersion ? atoi(pszVersion) : 3;
3236 : #endif
3237 : LT_STATUS eStat = LT_STS_Uninit;
3238 :
3239 : #ifdef DEBUG
3240 : bool bMeter = false;
3241 : #else
3242 : bool bMeter = true;
3243 : #endif
3244 :
3245 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
3246 : {
3247 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3248 : "MrSID driver ignores color table. "
3249 : "The source raster band will be considered as grey level.\n"
3250 : "Consider using color table expansion (-expand option in gdal_translate)\n");
3251 : if (bStrict)
3252 : return NULL;
3253 : }
3254 :
3255 : MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
3256 : if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
3257 : {
3258 : CPLError( CE_Failure, CPLE_AppDefined,
3259 : "MrSIDProgress.setProgressStatus failed.\n%s",
3260 : getLastStatusString( eStat ) );
3261 : return NULL;
3262 : }
3263 :
3264 : // Create the file.
3265 : MrSIDDummyImageReader oImageReader( poSrcDS );
3266 : if( LT_FAILURE( eStat = oImageReader.initialize() ) )
3267 : {
3268 : CPLError( CE_Failure, CPLE_AppDefined,
3269 : "MrSIDDummyImageReader.Initialize failed.\n%s",
3270 : getLastStatusString( eStat ) );
3271 : return NULL;
3272 : }
3273 :
3274 : LTIGeoFileImageWriter *poImageWriter = NULL;
3275 : switch (iVersion)
3276 : {
3277 : case 2: {
3278 : // Output Mrsid Version 2 file.
3279 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3280 : LTIDLLDefault<MG2ImageWriter> *poMG2ImageWriter;
3281 : poMG2ImageWriter = new LTIDLLDefault<MG2ImageWriter>;
3282 : eStat = poMG2ImageWriter->initialize(&oImageReader);
3283 : #else
3284 : LTIDLLWriter<MG2ImageWriter> *poMG2ImageWriter;
3285 : poMG2ImageWriter = new LTIDLLWriter<MG2ImageWriter>(&oImageReader);
3286 : eStat = poMG2ImageWriter->initialize();
3287 : #endif
3288 : if( LT_FAILURE( eStat ) )
3289 : {
3290 : delete poMG2ImageWriter;
3291 : CPLError( CE_Failure, CPLE_AppDefined,
3292 : "MG2ImageWriter.initialize() failed.\n%s",
3293 : getLastStatusString( eStat ) );
3294 : return NULL;
3295 : }
3296 :
3297 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3298 : eStat = poMG2ImageWriter->setEncodingApplication("MrSID Driver",
3299 : GDALVersionInfo("--version"));
3300 : if( LT_FAILURE( eStat ) )
3301 : {
3302 : delete poMG2ImageWriter;
3303 : CPLError( CE_Failure, CPLE_AppDefined,
3304 : "MG2ImageWriter.setEncodingApplication() failed.\n%s",
3305 : getLastStatusString( eStat ) );
3306 : return NULL;
3307 : }
3308 : #endif
3309 :
3310 : poMG2ImageWriter->setUsageMeterEnabled(bMeter);
3311 :
3312 : poMG2ImageWriter->params().setBlockSize(poMG2ImageWriter->params().getBlockSize());
3313 :
3314 : // check for compression option
3315 : const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
3316 : if( pszValue != NULL )
3317 : poMG2ImageWriter->params().setCompressionRatio( (float)atof(pszValue) );
3318 :
3319 : poImageWriter = poMG2ImageWriter;
3320 :
3321 : break; }
3322 : case 3: {
3323 : // Output Mrsid Version 3 file.
3324 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3325 : LTIDLLDefault<MG3ImageWriter> *poMG3ImageWriter;
3326 : poMG3ImageWriter = new LTIDLLDefault<MG3ImageWriter>;
3327 : eStat = poMG3ImageWriter->initialize(&oImageReader);
3328 : #else
3329 : LTIDLLWriter<MG3ImageWriter> *poMG3ImageWriter;
3330 : poMG3ImageWriter = new LTIDLLWriter<MG3ImageWriter>(&oImageReader);
3331 : eStat = poMG3ImageWriter->initialize();
3332 : #endif
3333 : if( LT_FAILURE( eStat ) )
3334 : {
3335 : delete poMG3ImageWriter;
3336 : CPLError( CE_Failure, CPLE_AppDefined,
3337 : "MG3ImageWriter.initialize() failed.\n%s",
3338 : getLastStatusString( eStat ) );
3339 : return NULL;
3340 : }
3341 :
3342 : #if defined(LTI_SDK_MAJOR) && LTI_SDK_MAJOR >= 8
3343 : eStat = poMG3ImageWriter->setEncodingApplication("MrSID Driver",
3344 : GDALVersionInfo("--version"));
3345 : if( LT_FAILURE( eStat ) )
3346 : {
3347 : delete poMG3ImageWriter;
3348 : CPLError( CE_Failure, CPLE_AppDefined,
3349 : "MG3ImageWriter.setEncodingApplication() failed.\n%s",
3350 : getLastStatusString( eStat ) );
3351 : return NULL;
3352 : }
3353 : #endif
3354 :
3355 : // usage meter should only be disabled for debugging
3356 : poMG3ImageWriter->setUsageMeterEnabled(bMeter);
3357 :
3358 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3359 : // Set 64-bit Interface for large files.
3360 : poMG3ImageWriter->setFileStream64(true);
3361 : #endif
3362 :
3363 : // set 2 pass optimizer option
3364 : if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
3365 : poMG3ImageWriter->params().setTwoPassOptimizer( true );
3366 :
3367 : // set filesize in KB
3368 : const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
3369 : if( pszValue != NULL )
3370 : poMG3ImageWriter->params().setTargetFilesize( atoi(pszValue) );
3371 :
3372 : poImageWriter = poMG3ImageWriter;
3373 :
3374 : break; }
3375 : #ifdef MRSID_HAVE_MG4WRITE
3376 : case 4: {
3377 : // Output Mrsid Version 4 file.
3378 : LTIDLLDefault<MG4ImageWriter> *poMG4ImageWriter;
3379 : poMG4ImageWriter = new LTIDLLDefault<MG4ImageWriter>;
3380 : eStat = poMG4ImageWriter->initialize(&oImageReader, NULL, NULL);
3381 : if( LT_FAILURE( eStat ) )
3382 : {
3383 : delete poMG4ImageWriter;
3384 : CPLError( CE_Failure, CPLE_AppDefined,
3385 : "MG3ImageWriter.initialize() failed.\n%s",
3386 : getLastStatusString( eStat ) );
3387 : return NULL;
3388 : }
3389 :
3390 : eStat = poMG4ImageWriter->setEncodingApplication("MrSID Driver",
3391 : GDALVersionInfo("--version"));
3392 : if( LT_FAILURE( eStat ) )
3393 : {
3394 : delete poMG4ImageWriter;
3395 : CPLError( CE_Failure, CPLE_AppDefined,
3396 : "MG3ImageWriter.setEncodingApplication() failed.\n%s",
3397 : getLastStatusString( eStat ) );
3398 : return NULL;
3399 : }
3400 :
3401 : // usage meter should only be disabled for debugging
3402 : poMG4ImageWriter->setUsageMeterEnabled(bMeter);
3403 :
3404 : // set 2 pass optimizer option
3405 : if( CSLFetchNameValue(papszOptions, "TWOPASS") != NULL )
3406 : poMG4ImageWriter->params().setTwoPassOptimizer( true );
3407 :
3408 : // set filesize in KB
3409 : const char* pszValue = CSLFetchNameValue(papszOptions, "FILESIZE");
3410 : if( pszValue != NULL )
3411 : poMG4ImageWriter->params().setTargetFilesize( atoi(pszValue) );
3412 :
3413 : poImageWriter = poMG4ImageWriter;
3414 :
3415 : break; }
3416 : #endif /* MRSID_HAVE_MG4WRITE */
3417 : default:
3418 : CPLError( CE_Failure, CPLE_AppDefined,
3419 : "Invalid MrSID generation specified (VERSION=%s).",
3420 : pszVersion );
3421 : return NULL;
3422 : }
3423 :
3424 : // set output filename
3425 : poImageWriter->setOutputFileSpec( pszFilename );
3426 :
3427 : // set progress delegate
3428 : poImageWriter->setProgressDelegate(&oProgressDelegate);
3429 :
3430 : // set defaults
3431 : poImageWriter->setStripHeight(poImageWriter->getStripHeight());
3432 :
3433 : // set MrSID world file
3434 : if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
3435 : poImageWriter->setWorldFileSupport( true );
3436 :
3437 : // write the scene
3438 : int nXSize = poSrcDS->GetRasterXSize();
3439 : int nYSize = poSrcDS->GetRasterYSize();
3440 : const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
3441 : if( LT_FAILURE( eStat = poImageWriter->write( oScene ) ) )
3442 : {
3443 : delete poImageWriter;
3444 : CPLError( CE_Failure, CPLE_AppDefined,
3445 : "MG2ImageWriter.write() failed.\n%s",
3446 : getLastStatusString( eStat ) );
3447 : return NULL;
3448 : }
3449 :
3450 : delete poImageWriter;
3451 : /* -------------------------------------------------------------------- */
3452 : /* Re-open dataset, and copy any auxilary pam information. */
3453 : /* -------------------------------------------------------------------- */
3454 : GDALPamDataset *poDS = (GDALPamDataset *)
3455 : GDALOpen( pszFilename, GA_ReadOnly );
3456 :
3457 : if( poDS )
3458 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
3459 :
3460 : return poDS;
3461 : }
3462 :
3463 : #ifdef MRSID_J2K
3464 : /************************************************************************/
3465 : /* JP2CreateCopy() */
3466 : /************************************************************************/
3467 :
3468 : static GDALDataset *
3469 : JP2CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
3470 : int bStrict, char ** papszOptions,
3471 : GDALProgressFunc pfnProgress, void * pProgressData )
3472 :
3473 : {
3474 : #ifdef DEBUG
3475 : bool bMeter = false;
3476 : #else
3477 : bool bMeter = true;
3478 : #endif
3479 :
3480 : int nXSize = poSrcDS->GetRasterXSize();
3481 : int nYSize = poSrcDS->GetRasterYSize();
3482 : LT_STATUS eStat;
3483 :
3484 : if (poSrcDS->GetRasterBand(1)->GetColorTable() != NULL)
3485 : {
3486 : CPLError( (bStrict) ? CE_Failure : CE_Warning, CPLE_NotSupported,
3487 : "MrSID driver ignores color table. "
3488 : "The source raster band will be considered as grey level.\n"
3489 : "Consider using color table expansion (-expand option in gdal_translate)\n");
3490 : if (bStrict)
3491 : return NULL;
3492 : }
3493 :
3494 : MrSIDProgress oProgressDelegate(pfnProgress, pProgressData);
3495 : if( LT_FAILURE( eStat = oProgressDelegate.setProgressStatus(0) ) )
3496 : {
3497 : CPLError( CE_Failure, CPLE_AppDefined,
3498 : "MrSIDProgress.setProgressStatus failed.\n%s",
3499 : getLastStatusString( eStat ) );
3500 : return NULL;
3501 : }
3502 :
3503 : // Create the file.
3504 : MrSIDDummyImageReader oImageReader( poSrcDS );
3505 : eStat = oImageReader.initialize();
3506 : if( eStat != LT_STS_Success )
3507 : {
3508 : CPLError( CE_Failure, CPLE_AppDefined,
3509 : "MrSIDDummyImageReader.Initialize failed.\n%s",
3510 : getLastStatusString( eStat ) );
3511 : return NULL;
3512 : }
3513 :
3514 : #if !defined(MRSID_POST5)
3515 : J2KImageWriter oImageWriter(&oImageReader);
3516 : eStat = oImageWriter.initialize();
3517 : #elif !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3518 : JP2WriterManager oImageWriter(&oImageReader);
3519 : eStat = oImageWriter.initialize();
3520 : #else
3521 : JP2WriterManager oImageWriter;
3522 : eStat = oImageWriter.initialize(&oImageReader);
3523 : #endif
3524 : if( eStat != LT_STS_Success )
3525 : {
3526 : CPLError( CE_Failure, CPLE_AppDefined,
3527 : "J2KImageWriter.Initialize failed.\n%s",
3528 : getLastStatusString( eStat ) );
3529 : return NULL;
3530 : }
3531 :
3532 : #if !defined(LTI_SDK_MAJOR) || LTI_SDK_MAJOR < 8
3533 : // Set 64-bit Interface for large files.
3534 : oImageWriter.setFileStream64(true);
3535 : #endif
3536 :
3537 : oImageWriter.setUsageMeterEnabled(bMeter);
3538 :
3539 : // set output filename
3540 : oImageWriter.setOutputFileSpec( pszFilename );
3541 :
3542 : // set progress delegate
3543 : oImageWriter.setProgressDelegate(&oProgressDelegate);
3544 :
3545 : // Set defaults
3546 : //oImageWriter.setStripHeight(oImageWriter.getStripHeight());
3547 :
3548 : // set MrSID world file
3549 : if( CSLFetchNameValue(papszOptions, "WORLDFILE") != NULL )
3550 : oImageWriter.setWorldFileSupport( true );
3551 :
3552 : // check for compression option
3553 : const char* pszValue = CSLFetchNameValue(papszOptions, "COMPRESSION");
3554 : if( pszValue != NULL )
3555 : oImageWriter.params().setCompressionRatio( (float)atof(pszValue) );
3556 :
3557 : pszValue = CSLFetchNameValue(papszOptions, "XMLPROFILE");
3558 : if( pszValue != NULL )
3559 : {
3560 : LTFileSpec xmlprofile(pszValue);
3561 : eStat = oImageWriter.params().readProfile(xmlprofile);
3562 : if( eStat != LT_STS_Success )
3563 : {
3564 : CPLError( CE_Failure, CPLE_AppDefined,
3565 : "JPCWriterParams.readProfile failed.\n%s",
3566 : getLastStatusString( eStat ) );
3567 : return NULL;
3568 : }
3569 : }
3570 :
3571 : // write the scene
3572 : const LTIScene oScene( 0, 0, nXSize, nYSize, 1.0 );
3573 : eStat = oImageWriter.write( oScene );
3574 : if( eStat != LT_STS_Success )
3575 : {
3576 : CPLError( CE_Failure, CPLE_AppDefined,
3577 : "J2KImageWriter.write() failed.\n%s",
3578 : getLastStatusString( eStat ) );
3579 : return NULL;
3580 : }
3581 :
3582 : /* -------------------------------------------------------------------- */
3583 : /* Re-open dataset, and copy any auxilary pam information. */
3584 : /* -------------------------------------------------------------------- */
3585 : GDALOpenInfo oOpenInfo(pszFilename, GA_ReadOnly);
3586 : GDALPamDataset *poDS = (GDALPamDataset*) JP2Open(&oOpenInfo);
3587 :
3588 : if( poDS )
3589 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
3590 :
3591 : return poDS;
3592 : }
3593 : #endif /* MRSID_J2K */
3594 : #endif /* MRSID_ESDK */
3595 :
3596 : /************************************************************************/
3597 : /* GDALRegister_MrSID() */
3598 : /************************************************************************/
3599 :
3600 582 : void GDALRegister_MrSID()
3601 :
3602 : {
3603 : GDALDriver *poDriver;
3604 :
3605 582 : if (! GDAL_CHECK_VERSION("MrSID driver"))
3606 0 : return;
3607 :
3608 : /* -------------------------------------------------------------------- */
3609 : /* MrSID driver. */
3610 : /* -------------------------------------------------------------------- */
3611 582 : if( GDALGetDriverByName( "MrSID" ) == NULL )
3612 : {
3613 561 : poDriver = new GDALDriver();
3614 :
3615 561 : poDriver->SetDescription( "MrSID" );
3616 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
3617 561 : "Multi-resolution Seamless Image Database (MrSID)" );
3618 561 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_mrsid.html" );
3619 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "sid" );
3620 :
3621 : #ifdef MRSID_ESDK
3622 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
3623 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64" );
3624 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
3625 : "<CreationOptionList>"
3626 : // Version 2 Options
3627 : " <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
3628 : // Version 3 Options
3629 : " <Option name='TWOPASS' type='int' description='Use twopass optimizer algorithm'/>"
3630 : " <Option name='FILESIZE' type='int' description='Set target file size (0 implies lossless compression)'/>"
3631 : // Version 2 and 3 Option
3632 : " <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
3633 : // Version Type
3634 : " <Option name='VERSION' type='int' description='Valid versions are 2 and 3, default = 3'/>"
3635 : "</CreationOptionList>" );
3636 :
3637 : poDriver->pfnCreateCopy = MrSIDCreateCopy;
3638 :
3639 : #else
3640 : /* In read-only mode, we support VirtualIO. I don't think this is the case */
3641 : /* for MrSIDCreateCopy() */
3642 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
3643 : #endif
3644 561 : poDriver->pfnIdentify = MrSIDIdentify;
3645 561 : poDriver->pfnOpen = MrSIDOpen;
3646 :
3647 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
3648 : }
3649 :
3650 : /* -------------------------------------------------------------------- */
3651 : /* JP2MRSID driver. */
3652 : /* -------------------------------------------------------------------- */
3653 : #ifdef MRSID_J2K
3654 582 : if( GDALGetDriverByName( "JP2MrSID" ) == NULL )
3655 : {
3656 561 : poDriver = new GDALDriver();
3657 :
3658 561 : poDriver->SetDescription( "JP2MrSID" );
3659 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
3660 561 : "MrSID JPEG2000" );
3661 561 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_jp2mrsid.html" );
3662 561 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "jp2" );
3663 :
3664 : #ifdef MRSID_ESDK
3665 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
3666 : "Byte Int16 UInt16" );
3667 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
3668 : "<CreationOptionList>"
3669 : " <Option name='COMPRESSION' type='double' description='Set compression ratio (0.0 default is meant to be lossless)'/>"
3670 : " <Option name='WORLDFILE' type='boolean' description='Write out world file'/>"
3671 : " <Option name='XMLPROFILE' type='string' description='Use named xml profile file'/>"
3672 : "</CreationOptionList>" );
3673 :
3674 : poDriver->pfnCreateCopy = JP2CreateCopy;
3675 : #else
3676 : /* In read-only mode, we support VirtualIO. I don't think this is the case */
3677 : /* for JP2CreateCopy() */
3678 561 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
3679 : #endif
3680 561 : poDriver->pfnIdentify = JP2Identify;
3681 561 : poDriver->pfnOpen = JP2Open;
3682 :
3683 561 : GetGDALDriverManager()->RegisterDriver( poDriver );
3684 : }
3685 : #endif /* def MRSID_J2K */
3686 : }
3687 :
3688 : #if defined(MRSID_USE_TIFFSYMS_WORKAROUND)
3689 : extern "C" {
3690 :
3691 : /* This is not pretty but I am not sure how else to get the plugin to build
3692 : * against the ESDK. ESDK symbol dependencies bring in __TIFFmemcpy and
3693 : * __gtiff_size, which are not exported from gdal.dll. Rather than link these
3694 : * symbols from the ESDK distribution of GDAL, or link in the entire gdal.lib
3695 : * statically, it seemed safer and smaller to bring in just the objects that
3696 : * wouldsatisfy these symbols from the enclosing GDAL build. However, doing
3697 : * so pulls in a few more dependencies. /Gy and /OPT:REF did not seem to help
3698 : * things, so I have implemented no-op versions of these symbols since they
3699 : * do not actually get called. If the MrSID ESDK ever comes to require the
3700 : * actual versions of these functions, we'll hope duplicate symbol errors will
3701 : * bring attention back to this problem.
3702 : */
3703 : void TIFFClientOpen() {}
3704 : void TIFFError() {}
3705 : void TIFFGetField() {}
3706 : void TIFFSetField() {}
3707 :
3708 : }
3709 : #endif
3710 :
|