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