1 : /******************************************************************************
2 : * $Id: geotiff.cpp 23561 2011-12-13 05:47:58Z warmerdam $
3 : *
4 : * Project: GeoTIFF Driver
5 : * Purpose: GDAL GeoTIFF support.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : /* If we use sunpro compiler on linux. Weird idea indeed ! */
31 : #if defined(__SUNPRO_CC) && defined(__linux__)
32 : #define _GNU_SOURCE
33 : #elif defined(__GNUC__) && !defined(_GNU_SOURCE)
34 : /* Required to use RTLD_DEFAULT of dlfcn.h */
35 : #define _GNU_SOURCE
36 : #endif
37 :
38 : #include "gdal_pam.h"
39 : #define CPL_SERV_H_INCLUDED
40 :
41 : #include "xtiffio.h"
42 : #include "geovalues.h"
43 : #include "cpl_string.h"
44 : #include "cpl_csv.h"
45 : #include "cpl_minixml.h"
46 : #include "gt_overview.h"
47 : #include "ogr_spatialref.h"
48 : #include "tif_float.h"
49 : #include "gtiff.h"
50 : #include "gdal_csv.h"
51 : #include "gt_wkt_srs.h"
52 : #include "tifvsi.h"
53 : #include "cpl_multiproc.h"
54 :
55 : CPL_CVSID("$Id: geotiff.cpp 23561 2011-12-13 05:47:58Z warmerdam $");
56 :
57 : /************************************************************************/
58 : /* ==================================================================== */
59 : /* GDALOverviewDS */
60 : /* ==================================================================== */
61 : /************************************************************************/
62 :
63 : /* GDALOverviewDS is not specific to GTiff and could probably be moved */
64 : /* in gcore. It is currently used to generate a fake */
65 : /* dataset from the overview levels of the source dataset that is taken */
66 : /* by CreateCopy() */
67 :
68 : #include "gdal_proxy.h"
69 :
70 : class GDALOverviewBand;
71 :
72 : class GDALOverviewDS : public GDALDataset
73 : {
74 : private:
75 :
76 : friend class GDALOverviewBand;
77 :
78 : GDALDataset* poDS;
79 : GDALDataset* poOvrDS;
80 : int nOvrLevel;
81 :
82 : public:
83 : GDALOverviewDS(GDALDataset* poDS, int nOvrLevel);
84 : virtual ~GDALOverviewDS();
85 :
86 : virtual char **GetMetadata( const char * pszDomain = "" );
87 : virtual const char *GetMetadataItem( const char * pszName,
88 : const char * pszDomain = "" );
89 : };
90 :
91 : class GDALOverviewBand : public GDALProxyRasterBand
92 : {
93 : protected:
94 : GDALRasterBand* poUnderlyingBand;
95 : virtual GDALRasterBand* RefUnderlyingRasterBand();
96 :
97 : public:
98 : GDALOverviewBand(GDALOverviewDS* poDS, int nBand);
99 : virtual ~GDALOverviewBand();
100 : };
101 :
102 12 : GDALOverviewDS::GDALOverviewDS(GDALDataset* poDS, int nOvrLevel)
103 : {
104 12 : this->poDS = poDS;
105 12 : this->nOvrLevel = nOvrLevel;
106 12 : eAccess = poDS->GetAccess();
107 12 : nRasterXSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize();
108 12 : nRasterYSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize();
109 12 : poOvrDS = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetDataset();
110 12 : nBands = poDS->GetRasterCount();
111 : int i;
112 26 : for(i=0;i<nBands;i++)
113 14 : SetBand(i+1, new GDALOverviewBand(this, i+1));
114 12 : }
115 :
116 12 : GDALOverviewDS::~GDALOverviewDS()
117 : {
118 12 : FlushCache();
119 12 : }
120 :
121 0 : char **GDALOverviewDS::GetMetadata( const char * pszDomain )
122 : {
123 0 : if (poOvrDS != NULL)
124 0 : return poOvrDS->GetMetadata(pszDomain);
125 :
126 0 : return poDS->GetMetadata(pszDomain);
127 : }
128 :
129 30 : const char *GDALOverviewDS::GetMetadataItem( const char * pszName, const char * pszDomain )
130 : {
131 30 : if (poOvrDS != NULL)
132 30 : return poOvrDS->GetMetadataItem(pszName, pszDomain);
133 :
134 0 : return poDS->GetMetadataItem(pszName, pszDomain);
135 : }
136 :
137 14 : GDALOverviewBand::GDALOverviewBand(GDALOverviewDS* poDS, int nBand)
138 : {
139 14 : this->poDS = poDS;
140 14 : this->nBand = nBand;
141 14 : poUnderlyingBand = poDS->poDS->GetRasterBand(nBand)->GetOverview(poDS->nOvrLevel);
142 14 : nRasterXSize = poDS->nRasterXSize;
143 14 : nRasterYSize = poDS->nRasterYSize;
144 14 : eDataType = poUnderlyingBand->GetRasterDataType();
145 14 : poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
146 14 : }
147 :
148 14 : GDALOverviewBand::~GDALOverviewBand()
149 : {
150 14 : FlushCache();
151 14 : }
152 :
153 50 : GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
154 : {
155 50 : return poUnderlyingBand;
156 : }
157 :
158 : /************************************************************************/
159 : /* IsPowerOfTwo() */
160 : /************************************************************************/
161 :
162 158 : static int IsPowerOfTwo(unsigned int i)
163 : {
164 158 : int nBitSet = 0;
165 1584 : while(i != 0)
166 : {
167 1268 : if ((i & 1))
168 158 : nBitSet ++;
169 1268 : i >>= 1;
170 : }
171 158 : return nBitSet == 1;
172 : }
173 :
174 : /************************************************************************/
175 : /* GTIFFGetOverviewBlockSize() */
176 : /************************************************************************/
177 :
178 158 : void GTIFFGetOverviewBlockSize(int* pnBlockXSize, int* pnBlockYSize)
179 : {
180 : static int bHasWarned = FALSE;
181 158 : const char* pszVal = CPLGetConfigOption("GDAL_TIFF_OVR_BLOCKSIZE", "128");
182 158 : int nOvrBlockSize = atoi(pszVal);
183 158 : if (nOvrBlockSize < 64 || nOvrBlockSize > 4096 ||
184 : !IsPowerOfTwo(nOvrBlockSize))
185 : {
186 0 : if (!bHasWarned)
187 : {
188 : CPLError(CE_Warning, CPLE_NotSupported,
189 : "Wrong value for GDAL_TIFF_OVR_BLOCKSIZE : %s. "
190 : "Should be a power of 2 between 64 and 4096. Defaulting to 128",
191 0 : pszVal);
192 0 : bHasWarned = TRUE;
193 : }
194 0 : nOvrBlockSize = 128;
195 : }
196 :
197 158 : *pnBlockXSize = nOvrBlockSize;
198 158 : *pnBlockYSize = nOvrBlockSize;
199 158 : }
200 :
201 : enum
202 : {
203 : ENDIANNESS_NATIVE,
204 : ENDIANNESS_LITTLE,
205 : ENDIANNESS_BIG
206 : };
207 :
208 : /************************************************************************/
209 : /* ==================================================================== */
210 : /* GTiffDataset */
211 : /* ==================================================================== */
212 : /************************************************************************/
213 :
214 : class GTiffRasterBand;
215 : class GTiffRGBABand;
216 : class GTiffBitmapBand;
217 :
218 : class GTiffDataset : public GDALPamDataset
219 : {
220 : friend class GTiffRasterBand;
221 : friend class GTiffSplitBand;
222 : friend class GTiffRGBABand;
223 : friend class GTiffBitmapBand;
224 : friend class GTiffSplitBitmapBand;
225 : friend class GTiffOddBitsBand;
226 :
227 : friend void GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality);
228 :
229 : TIFF *hTIFF;
230 : GTiffDataset **ppoActiveDSRef;
231 : GTiffDataset *poActiveDS; /* only used in actual base */
232 :
233 : int bScanDeferred;
234 : void ScanDirectories();
235 :
236 : toff_t nDirOffset;
237 : int bBase;
238 : int bCloseTIFFHandle; /* usefull for closing TIFF handle opened by GTIFF_DIR: */
239 :
240 : uint16 nPlanarConfig;
241 : uint16 nSamplesPerPixel;
242 : uint16 nBitsPerSample;
243 : uint32 nRowsPerStrip;
244 : uint16 nPhotometric;
245 : uint16 nSampleFormat;
246 : uint16 nCompression;
247 :
248 : int nBlocksPerBand;
249 :
250 : uint32 nBlockXSize;
251 : uint32 nBlockYSize;
252 :
253 : int nLoadedBlock; /* or tile */
254 : int bLoadedBlockDirty;
255 : GByte *pabyBlockBuf;
256 :
257 : CPLErr LoadBlockBuf( int nBlockId, int bReadFromDisk = TRUE );
258 : CPLErr FlushBlockBuf();
259 : int bWriteErrorInFlushBlockBuf;
260 :
261 : char *pszProjection;
262 : int bLookedForProjection;
263 :
264 : void LookForProjection();
265 : #ifdef ESRI_BUILD
266 : void AdjustLinearUnit( short UOMLength );
267 : #endif
268 :
269 : double adfGeoTransform[6];
270 : int bGeoTransformValid;
271 :
272 : int bTreatAsRGBA;
273 : int bCrystalized;
274 :
275 : void Crystalize();
276 :
277 : GDALColorTable *poColorTable;
278 :
279 : void WriteGeoTIFFInfo();
280 : int SetDirectory( toff_t nDirOffset = 0 );
281 :
282 : int nOverviewCount;
283 : GTiffDataset **papoOverviewDS;
284 :
285 : int nGCPCount;
286 : GDAL_GCP *pasGCPList;
287 :
288 : int IsBlockAvailable( int nBlockId );
289 :
290 : int bGeoTIFFInfoChanged;
291 : int bNoDataSet;
292 : double dfNoDataValue;
293 :
294 : int bMetadataChanged;
295 :
296 : int bNeedsRewrite;
297 :
298 : void ApplyPamInfo();
299 : void PushMetadataToPam();
300 :
301 : GDALMultiDomainMetadata oGTiffMDMD;
302 :
303 : CPLString osProfile;
304 : char **papszCreationOptions;
305 :
306 : int bLoadingOtherBands;
307 :
308 : static void WriteRPCTag( TIFF *, char ** );
309 : void ReadRPCTag();
310 :
311 : void* pabyTempWriteBuffer;
312 : int nTempWriteBufferSize;
313 : int WriteEncodedTile(uint32 tile, GByte* pabyData, int bPreserveDataBuffer);
314 : int WriteEncodedStrip(uint32 strip, GByte* pabyData, int bPreserveDataBuffer);
315 :
316 : GTiffDataset* poMaskDS;
317 : GTiffDataset* poBaseDS;
318 :
319 : CPLString osFilename;
320 :
321 : int bFillEmptyTiles;
322 : void FillEmptyTiles(void);
323 :
324 : void FlushDirectory();
325 : CPLErr CleanOverviews();
326 :
327 : /* Used for the all-in-on-strip case */
328 : int nLastLineRead;
329 : int nLastBandRead;
330 : int bTreatAsSplit;
331 : int bTreatAsSplitBitmap;
332 :
333 : int bClipWarn;
334 :
335 : CPLString osRPBFile;
336 : int FindRPBFile();
337 : CPLString osRPCFile;
338 : int FindRPCFile();
339 : CPLString osIMDFile;
340 : int FindIMDFile();
341 : int bHasSearchedRPC;
342 : void LoadRPCRPB();
343 : int bHasSearchedIMD;
344 : void LoadIMD();
345 :
346 : int bHasWarnedDisableAggressiveBandCaching;
347 :
348 : int bDontReloadFirstBlock; /* Hack for libtiff 3.X and #3633 */
349 :
350 : int nZLevel;
351 : int nLZMAPreset;
352 : int nJpegQuality;
353 :
354 : int bPromoteTo8Bits;
355 :
356 : int bDebugDontWriteBlocks;
357 :
358 : CPLErr RegisterNewOverviewDataset(toff_t nOverviewOffset);
359 : CPLErr CreateOverviewsFromSrcOverviews(GDALDataset* poSrcDS);
360 : CPLErr CreateInternalMaskOverviews(int nOvrBlockXSize,
361 : int nOvrBlockYSize);
362 :
363 : int bIsFinalized;
364 : int Finalize();
365 :
366 : int bIgnoreReadErrors;
367 :
368 : CPLString osWldFilename;
369 :
370 : int bDirectIO;
371 :
372 : protected:
373 : virtual int CloseDependentDatasets();
374 :
375 : public:
376 : GTiffDataset();
377 : ~GTiffDataset();
378 :
379 : virtual const char *GetProjectionRef(void);
380 : virtual CPLErr SetProjection( const char * );
381 : virtual CPLErr GetGeoTransform( double * );
382 : virtual CPLErr SetGeoTransform( double * );
383 :
384 : virtual int GetGCPCount();
385 : virtual const char *GetGCPProjection();
386 : virtual const GDAL_GCP *GetGCPs();
387 : CPLErr SetGCPs( int, const GDAL_GCP *, const char * );
388 :
389 : virtual char **GetFileList(void);
390 :
391 : virtual CPLErr IBuildOverviews( const char *, int, int *, int, int *,
392 : GDALProgressFunc, void * );
393 :
394 : CPLErr OpenOffset( TIFF *, GTiffDataset **ppoActiveDSRef,
395 : toff_t nDirOffset, int bBaseIn, GDALAccess,
396 : int bAllowRGBAInterface = TRUE, int bReadGeoTransform = FALSE,
397 : char** papszSiblingFiles = NULL);
398 :
399 : static GDALDataset *OpenDir( GDALOpenInfo * );
400 : static GDALDataset *Open( GDALOpenInfo * );
401 : static int Identify( GDALOpenInfo * );
402 : static GDALDataset *Create( const char * pszFilename,
403 : int nXSize, int nYSize, int nBands,
404 : GDALDataType eType, char ** papszParmList );
405 : static GDALDataset *CreateCopy( const char * pszFilename,
406 : GDALDataset *poSrcDS,
407 : int bStrict, char ** papszOptions,
408 : GDALProgressFunc pfnProgress,
409 : void * pProgressData );
410 : virtual void FlushCache( void );
411 :
412 : virtual CPLErr SetMetadata( char **, const char * = "" );
413 : virtual char **GetMetadata( const char * pszDomain = "" );
414 : virtual CPLErr SetMetadataItem( const char*, const char*,
415 : const char* = "" );
416 : virtual const char *GetMetadataItem( const char * pszName,
417 : const char * pszDomain = "" );
418 : virtual void *GetInternalHandle( const char * );
419 :
420 : virtual CPLErr CreateMaskBand( int nFlags );
421 :
422 : // only needed by createcopy and close code.
423 : static int WriteMetadata( GDALDataset *, TIFF *, int, const char *,
424 : const char *, char **, int bExcludeRPBandIMGFileWriting = FALSE );
425 : static void WriteNoDataValue( TIFF *, double );
426 :
427 : static TIFF * CreateLL( const char * pszFilename,
428 : int nXSize, int nYSize, int nBands,
429 : GDALDataType eType,
430 : double dfExtraSpaceForOverviews,
431 : char **papszParmList );
432 :
433 : CPLErr WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data, int bPreserveDataBuffer);
434 : };
435 :
436 : /************************************************************************/
437 : /* GTIFFSetJpegQuality() */
438 : /* Called by GTIFFBuildOverviews() to set the jpeg quality on the IFD */
439 : /* of the .ovr file */
440 : /************************************************************************/
441 :
442 4 : void GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality)
443 : {
444 4 : CPLAssert(EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
445 :
446 4 : GTiffDataset* poDS = (GTiffDataset*)hGTIFFDS;
447 4 : poDS->nJpegQuality = nJpegQuality;
448 :
449 4 : poDS->ScanDirectories();
450 :
451 : int i;
452 7 : for(i=0;i<poDS->nOverviewCount;i++)
453 3 : poDS->papoOverviewDS[i]->nJpegQuality = nJpegQuality;
454 4 : }
455 :
456 : /************************************************************************/
457 : /* ==================================================================== */
458 : /* GTiffRasterBand */
459 : /* ==================================================================== */
460 : /************************************************************************/
461 :
462 : class GTiffRasterBand : public GDALPamRasterBand
463 399730 : {
464 : friend class GTiffDataset;
465 :
466 : GDALColorInterp eBandInterp;
467 :
468 : int bHaveOffsetScale;
469 : double dfOffset;
470 : double dfScale;
471 : CPLString osUnitType;
472 :
473 : CPLErr DirectIO( GDALRWFlag eRWFlag,
474 : int nXOff, int nYOff, int nXSize, int nYSize,
475 : void * pData, int nBufXSize, int nBufYSize,
476 : GDALDataType eBufType,
477 : int nPixelSpace, int nLineSpace );
478 :
479 : protected:
480 : GTiffDataset *poGDS;
481 : GDALMultiDomainMetadata oGTiffMDMD;
482 :
483 : int bNoDataSet;
484 : double dfNoDataValue;
485 :
486 : void NullBlock( void *pData );
487 : CPLErr FillCacheForOtherBands( int nBlockXOff, int nBlockYOff );
488 :
489 : public:
490 : GTiffRasterBand( GTiffDataset *, int );
491 :
492 : virtual CPLErr IReadBlock( int, int, void * );
493 : virtual CPLErr IWriteBlock( int, int, void * );
494 :
495 : virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
496 : int nXOff, int nYOff, int nXSize, int nYSize,
497 : void * pData, int nBufXSize, int nBufYSize,
498 : GDALDataType eBufType,
499 : int nPixelSpace, int nLineSpace );
500 :
501 : virtual GDALColorInterp GetColorInterpretation();
502 : virtual GDALColorTable *GetColorTable();
503 : virtual CPLErr SetColorTable( GDALColorTable * );
504 : virtual double GetNoDataValue( int * );
505 : virtual CPLErr SetNoDataValue( double );
506 :
507 : virtual double GetOffset( int *pbSuccess = NULL );
508 : virtual CPLErr SetOffset( double dfNewValue );
509 : virtual double GetScale( int *pbSuccess = NULL );
510 : virtual CPLErr SetScale( double dfNewValue );
511 : virtual const char* GetUnitType();
512 : virtual CPLErr SetUnitType( const char *pszNewValue );
513 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
514 :
515 : virtual CPLErr SetMetadata( char **, const char * = "" );
516 : virtual char **GetMetadata( const char * pszDomain = "" );
517 : virtual CPLErr SetMetadataItem( const char*, const char*,
518 : const char* = "" );
519 : virtual const char *GetMetadataItem( const char * pszName,
520 : const char * pszDomain = "" );
521 : virtual int GetOverviewCount();
522 : virtual GDALRasterBand *GetOverview( int );
523 :
524 : virtual GDALRasterBand *GetMaskBand();
525 : virtual int GetMaskFlags();
526 : virtual CPLErr CreateMaskBand( int nFlags );
527 : };
528 :
529 : /************************************************************************/
530 : /* GTiffRasterBand() */
531 : /************************************************************************/
532 :
533 399730 : GTiffRasterBand::GTiffRasterBand( GTiffDataset *poDS, int nBand )
534 :
535 : {
536 399730 : poGDS = poDS;
537 :
538 399730 : this->poDS = poDS;
539 399730 : this->nBand = nBand;
540 :
541 399730 : bHaveOffsetScale = FALSE;
542 399730 : dfOffset = 0.0;
543 399730 : dfScale = 1.0;
544 :
545 : /* -------------------------------------------------------------------- */
546 : /* Get the GDAL data type. */
547 : /* -------------------------------------------------------------------- */
548 399730 : uint16 nSampleFormat = poDS->nSampleFormat;
549 :
550 399730 : eDataType = GDT_Unknown;
551 :
552 399730 : if( poDS->nBitsPerSample <= 8 )
553 : {
554 397004 : eDataType = GDT_Byte;
555 397004 : if( nSampleFormat == SAMPLEFORMAT_INT )
556 9 : SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
557 :
558 : }
559 2726 : else if( poDS->nBitsPerSample <= 16 )
560 : {
561 643 : if( nSampleFormat == SAMPLEFORMAT_INT )
562 271 : eDataType = GDT_Int16;
563 : else
564 372 : eDataType = GDT_UInt16;
565 : }
566 2083 : else if( poDS->nBitsPerSample == 32 )
567 : {
568 1149 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
569 190 : eDataType = GDT_CInt16;
570 959 : else if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
571 498 : eDataType = GDT_Float32;
572 461 : else if( nSampleFormat == SAMPLEFORMAT_INT )
573 231 : eDataType = GDT_Int32;
574 : else
575 230 : eDataType = GDT_UInt32;
576 : }
577 934 : else if( poDS->nBitsPerSample == 64 )
578 : {
579 661 : if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
580 269 : eDataType = GDT_Float64;
581 392 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
582 203 : eDataType = GDT_CFloat32;
583 189 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
584 189 : eDataType = GDT_CInt32;
585 : }
586 273 : else if( poDS->nBitsPerSample == 128 )
587 : {
588 205 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
589 205 : eDataType = GDT_CFloat64;
590 : }
591 :
592 : /* -------------------------------------------------------------------- */
593 : /* Try to work out band color interpretation. */
594 : /* -------------------------------------------------------------------- */
595 399730 : int bLookForExtraSamples = FALSE;
596 :
597 399818 : if( poDS->poColorTable != NULL && nBand == 1 )
598 88 : eBandInterp = GCI_PaletteIndex;
599 399642 : else if( poDS->nPhotometric == PHOTOMETRIC_RGB
600 : || (poDS->nPhotometric == PHOTOMETRIC_YCBCR
601 : && poDS->nCompression == COMPRESSION_JPEG
602 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
603 : "YES") )) )
604 : {
605 1575 : if( nBand == 1 )
606 495 : eBandInterp = GCI_RedBand;
607 1080 : else if( nBand == 2 )
608 495 : eBandInterp = GCI_GreenBand;
609 585 : else if( nBand == 3 )
610 495 : eBandInterp = GCI_BlueBand;
611 : else
612 90 : bLookForExtraSamples = TRUE;
613 : }
614 398067 : else if( poDS->nPhotometric == PHOTOMETRIC_YCBCR )
615 : {
616 4 : if( nBand == 1 )
617 1 : eBandInterp = GCI_YCbCr_YBand;
618 3 : else if( nBand == 2 )
619 1 : eBandInterp = GCI_YCbCr_CbBand;
620 2 : else if( nBand == 3 )
621 1 : eBandInterp = GCI_YCbCr_CrBand;
622 : else
623 1 : bLookForExtraSamples = TRUE;
624 : }
625 398063 : else if( poDS->nPhotometric == PHOTOMETRIC_SEPARATED )
626 : {
627 40 : if( nBand == 1 )
628 10 : eBandInterp = GCI_CyanBand;
629 30 : else if( nBand == 2 )
630 10 : eBandInterp = GCI_MagentaBand;
631 20 : else if( nBand == 3 )
632 10 : eBandInterp = GCI_YellowBand;
633 10 : else if( nBand == 4 )
634 10 : eBandInterp = GCI_BlackBand;
635 : else
636 0 : bLookForExtraSamples = TRUE;
637 : }
638 402339 : else if( poDS->nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1 )
639 4316 : eBandInterp = GCI_GrayIndex;
640 : else
641 393707 : bLookForExtraSamples = TRUE;
642 :
643 399730 : if( bLookForExtraSamples )
644 : {
645 : uint16 *v;
646 393798 : uint16 count = 0;
647 :
648 393798 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v ) )
649 : {
650 : int nBaseSamples;
651 393628 : nBaseSamples = poDS->nSamplesPerPixel - count;
652 :
653 1180887 : if( nBand > nBaseSamples
654 393628 : && (v[nBand-nBaseSamples-1] == EXTRASAMPLE_ASSOCALPHA
655 393544 : || v[nBand-nBaseSamples-1] == EXTRASAMPLE_UNASSALPHA) )
656 87 : eBandInterp = GCI_AlphaBand;
657 : else
658 393541 : eBandInterp = GCI_Undefined;
659 : }
660 : else
661 170 : eBandInterp = GCI_Undefined;
662 : }
663 :
664 : /* -------------------------------------------------------------------- */
665 : /* Establish block size for strip or tiles. */
666 : /* -------------------------------------------------------------------- */
667 399730 : nBlockXSize = poDS->nBlockXSize;
668 399730 : nBlockYSize = poDS->nBlockYSize;
669 :
670 399730 : bNoDataSet = FALSE;
671 399730 : dfNoDataValue = -9999.0;
672 399730 : }
673 :
674 : /************************************************************************/
675 : /* DirectIO() */
676 : /************************************************************************/
677 :
678 : /* Reads directly bytes from the file using ReadMultiRange(), and by-pass */
679 : /* block reading. Restricted to simple TIFF configurations (single-band, un-tiled, */
680 : /* uncompressed data, standard data types). Particularly usefull to extract */
681 : /* sub-windows of data on a large /vsicurl dataset). */
682 :
683 1 : CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
684 : int nXOff, int nYOff, int nXSize, int nYSize,
685 : void * pData, int nBufXSize, int nBufYSize,
686 : GDALDataType eBufType,
687 : int nPixelSpace, int nLineSpace )
688 : {
689 1 : if( !(eRWFlag == GF_Read && poGDS->nBands == 1 &&
690 : poGDS->nCompression == COMPRESSION_NONE &&
691 : (poGDS->nBitsPerSample == 8 || (poGDS->nBitsPerSample == 16) ||
692 : poGDS->nBitsPerSample == 32 || poGDS->nBitsPerSample == 64) &&
693 : poGDS->nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
694 : !TIFFIsTiled( poGDS->hTIFF )) )
695 : {
696 0 : return CE_Failure;
697 : }
698 :
699 : /* ==================================================================== */
700 : /* Do we have overviews that would be appropriate to satisfy */
701 : /* this request? */
702 : /* ==================================================================== */
703 2 : if( (nBufXSize < nXSize || nBufYSize < nYSize)
704 1 : && GetOverviewCount() > 0 && eRWFlag == GF_Read )
705 : {
706 : int nOverview;
707 :
708 : nOverview =
709 : GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
710 0 : nBufXSize, nBufYSize);
711 0 : if (nOverview >= 0)
712 : {
713 0 : GDALRasterBand* poOverviewBand = GetOverview(nOverview);
714 0 : if (poOverviewBand == NULL)
715 0 : return CE_Failure;
716 :
717 : return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
718 : pData, nBufXSize, nBufYSize, eBufType,
719 0 : nPixelSpace, nLineSpace );
720 : }
721 : }
722 :
723 : /* Make sure that TIFFTAG_STRIPOFFSETS is up-to-date */
724 1 : if (poGDS->GetAccess() == GA_Update)
725 0 : poGDS->FlushCache();
726 :
727 : /* Get strip offsets */
728 1 : toff_t *panTIFFOffsets = NULL;
729 1 : if ( !TIFFGetField( poGDS->hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets ) ||
730 : panTIFFOffsets == NULL )
731 : {
732 0 : return CE_Failure;
733 : }
734 :
735 : int iLine;
736 1 : int nReqXSize = nXSize; /* sub-sampling or over-sampling can only be done at last stage */
737 1 : int nReqYSize = MIN(nBufYSize, nYSize); /* we can do sub-sampling at the extraction stage */
738 1 : void** ppData = (void**) VSIMalloc(nReqYSize * sizeof(void*));
739 : vsi_l_offset* panOffsets = (vsi_l_offset*)
740 1 : VSIMalloc(nReqYSize * sizeof(vsi_l_offset));
741 1 : size_t* panSizes = (size_t*) VSIMalloc(nReqYSize * sizeof(size_t));
742 1 : int eDTSize = GDALGetDataTypeSize(eDataType) / 8;
743 1 : void* pTmpBuffer = NULL;
744 1 : CPLErr eErr = CE_None;
745 :
746 1 : if (ppData == NULL || panOffsets == NULL || panSizes == NULL)
747 0 : eErr = CE_Failure;
748 1 : else if (nXSize != nBufXSize || nYSize != nBufYSize ||
749 : eBufType != eDataType ||
750 : nPixelSpace != GDALGetDataTypeSize(eBufType) / 8)
751 : {
752 : /* We need a temporary buffer for over-sampling/sub-sampling */
753 : /* and/or data type conversion */
754 1 : pTmpBuffer = VSIMalloc(nReqXSize * nReqYSize * eDTSize);
755 1 : if (pTmpBuffer == NULL)
756 0 : eErr = CE_Failure;
757 : }
758 :
759 : /* Prepare data extraction */
760 129 : for(iLine=0;eErr == CE_None && iLine<nReqYSize;iLine++)
761 : {
762 128 : if (pTmpBuffer == NULL)
763 0 : ppData[iLine] = ((GByte*)pData) + iLine * nLineSpace;
764 : else
765 128 : ppData[iLine] = ((GByte*)pTmpBuffer) + iLine * nReqXSize * eDTSize;
766 : int nSrcLine;
767 128 : if (nBufYSize < nYSize) /* Sub-sampling in y */
768 128 : nSrcLine = nYOff + (int)((iLine + 0.5) * nYSize / nBufYSize);
769 : else
770 0 : nSrcLine = nYOff + iLine;
771 128 : panOffsets[iLine] = panTIFFOffsets[nSrcLine / nBlockYSize];
772 128 : if (panOffsets[iLine] == 0) /* We don't support sparse files */
773 0 : eErr = CE_Failure;
774 :
775 128 : panOffsets[iLine] += (nXOff + (nSrcLine % nBlockYSize) * nBlockXSize) * eDTSize;
776 128 : panSizes[iLine] = nReqXSize * eDTSize;
777 : }
778 :
779 : /* Extract data from the file */
780 1 : if (eErr == CE_None)
781 : {
782 1 : VSILFILE* fp = (VSILFILE*) TIFFClientdata( poGDS->hTIFF );
783 1 : int nRet = VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
784 1 : if (nRet != 0)
785 0 : eErr = CE_Failure;
786 : }
787 :
788 : /* Byte-swap if necessary */
789 1 : if (eErr == CE_None && TIFFIsByteSwapped(poGDS->hTIFF))
790 : {
791 0 : for(iLine=0;iLine<nReqYSize;iLine++)
792 : {
793 0 : GDALSwapWords( ppData[iLine], eDTSize, nReqXSize, eDTSize);
794 : }
795 : }
796 :
797 : /* Over-sampling/sub-sampling and/or data type conversion */
798 1 : if (eErr == CE_None && pTmpBuffer != NULL)
799 : {
800 129 : for(int iY=0;iY<nBufYSize;iY++)
801 : {
802 : int iSrcY = (nBufYSize <= nYSize) ? iY :
803 128 : (int)((iY + 0.5) * nYSize / nBufYSize);
804 128 : if (nBufXSize == nXSize)
805 : {
806 : GDALCopyWords( ppData[iSrcY], eDataType, eDTSize,
807 : ((GByte*)pData) + iY * nLineSpace,
808 : eBufType, nPixelSpace,
809 0 : nReqXSize);
810 : }
811 : else
812 : {
813 16512 : for(int iX=0;iX<nBufXSize;iX++)
814 : {
815 : int iSrcX = (nBufXSize == nXSize) ? iX :
816 16384 : (int)((iX+0.5) * nXSize / nBufXSize);
817 16384 : GDALCopyWords( ((GByte*)ppData[iSrcY]) + iSrcX * eDTSize,
818 : eDataType, 0,
819 : ((GByte*)pData) + iX * nPixelSpace + iY * nLineSpace,
820 32768 : eBufType, 0, 1);
821 : }
822 : }
823 : }
824 : }
825 :
826 : /* Cleanup */
827 1 : CPLFree(pTmpBuffer);
828 1 : CPLFree(ppData);
829 1 : CPLFree(panOffsets);
830 1 : CPLFree(panSizes);
831 :
832 1 : return eErr;
833 : }
834 :
835 : /************************************************************************/
836 : /* IRasterIO() */
837 : /************************************************************************/
838 :
839 709511 : CPLErr GTiffRasterBand::IRasterIO( GDALRWFlag eRWFlag,
840 : int nXOff, int nYOff, int nXSize, int nYSize,
841 : void * pData, int nBufXSize, int nBufYSize,
842 : GDALDataType eBufType,
843 : int nPixelSpace, int nLineSpace )
844 : {
845 : CPLErr eErr;
846 :
847 : //CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)",
848 : // nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
849 :
850 709511 : if (poGDS->bDirectIO)
851 : {
852 : eErr = DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
853 : pData, nBufXSize, nBufYSize, eBufType,
854 1 : nPixelSpace, nLineSpace);
855 :
856 1 : if (eErr == CE_None)
857 1 : return eErr;
858 : }
859 :
860 709510 : if (poGDS->nBands != 1 &&
861 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
862 : eRWFlag == GF_Read &&
863 : nXSize == nBufXSize && nYSize == nBufYSize)
864 : {
865 160239 : int nBlockX1 = nXOff / nBlockXSize;
866 160239 : int nBlockY1 = nYOff / nBlockYSize;
867 160239 : int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
868 160239 : int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
869 160239 : int nXBlocks = nBlockX2 - nBlockX1 + 1;
870 160239 : int nYBlocks = nBlockY2 - nBlockY1 + 1;
871 : GIntBig nRequiredMem = (GIntBig)poGDS->nBands * nXBlocks * nYBlocks *
872 : nBlockXSize * nBlockYSize *
873 160239 : (GDALGetDataTypeSize(eDataType) / 8);
874 160239 : if (nRequiredMem > GDALGetCacheMax64())
875 : {
876 21 : if (!poGDS->bHasWarnedDisableAggressiveBandCaching)
877 : {
878 : CPLDebug("GTiff", "Disable aggressive band caching. Cache not big enough. "
879 1 : "At least " CPL_FRMT_GIB " bytes necessary", nRequiredMem);
880 1 : poGDS->bHasWarnedDisableAggressiveBandCaching = TRUE;
881 : }
882 21 : poGDS->bLoadingOtherBands = TRUE;
883 : }
884 : }
885 :
886 : eErr = GDALPamRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
887 : pData, nBufXSize, nBufYSize, eBufType,
888 709510 : nPixelSpace, nLineSpace);
889 :
890 709510 : poGDS->bLoadingOtherBands = FALSE;
891 :
892 709510 : return eErr;
893 : }
894 :
895 : /************************************************************************/
896 : /* IReadBlock() */
897 : /************************************************************************/
898 :
899 97000 : CPLErr GTiffRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
900 : void * pImage )
901 :
902 : {
903 : int nBlockBufSize, nBlockId, nBlockIdBand0;
904 97000 : CPLErr eErr = CE_None;
905 :
906 97000 : if (!poGDS->SetDirectory())
907 0 : return CE_Failure;
908 :
909 97000 : if( TIFFIsTiled(poGDS->hTIFF) )
910 13487 : nBlockBufSize = TIFFTileSize( poGDS->hTIFF );
911 : else
912 : {
913 83513 : CPLAssert( nBlockXOff == 0 );
914 83513 : nBlockBufSize = TIFFStripSize( poGDS->hTIFF );
915 : }
916 :
917 97000 : CPLAssert(nBlocksPerRow != 0);
918 97000 : nBlockIdBand0 = nBlockXOff + nBlockYOff * nBlocksPerRow;
919 97000 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
920 1142 : nBlockId = nBlockIdBand0 + (nBand-1) * poGDS->nBlocksPerBand;
921 : else
922 95858 : nBlockId = nBlockIdBand0;
923 :
924 : /* -------------------------------------------------------------------- */
925 : /* The bottom most partial tiles and strips are sometimes only */
926 : /* partially encoded. This code reduces the requested data so */
927 : /* an error won't be reported in this case. (#1179) */
928 : /* -------------------------------------------------------------------- */
929 97000 : int nBlockReqSize = nBlockBufSize;
930 :
931 97000 : if( (nBlockYOff+1) * nBlockYSize > nRasterYSize )
932 : {
933 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
934 1515 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
935 : }
936 :
937 : /* -------------------------------------------------------------------- */
938 : /* Handle the case of a strip or tile that doesn't exist yet. */
939 : /* Just set to zeros and return. */
940 : /* -------------------------------------------------------------------- */
941 97000 : if( !poGDS->IsBlockAvailable(nBlockId) )
942 : {
943 12658 : NullBlock( pImage );
944 12658 : return CE_None;
945 : }
946 :
947 : /* -------------------------------------------------------------------- */
948 : /* Handle simple case (separate, onesampleperpixel) */
949 : /* -------------------------------------------------------------------- */
950 84342 : if( poGDS->nBands == 1
951 : || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
952 : {
953 12728 : if( nBlockReqSize < nBlockBufSize )
954 418 : memset( pImage, 0, nBlockBufSize );
955 :
956 12728 : if( TIFFIsTiled( poGDS->hTIFF ) )
957 : {
958 8563 : if( TIFFReadEncodedTile( poGDS->hTIFF, nBlockId, pImage,
959 : nBlockReqSize ) == -1
960 : && !poGDS->bIgnoreReadErrors )
961 : {
962 1 : memset( pImage, 0, nBlockBufSize );
963 : CPLError( CE_Failure, CPLE_AppDefined,
964 1 : "TIFFReadEncodedTile() failed.\n" );
965 :
966 1 : eErr = CE_Failure;
967 : }
968 : }
969 : else
970 : {
971 4165 : if( TIFFReadEncodedStrip( poGDS->hTIFF, nBlockId, pImage,
972 : nBlockReqSize ) == -1
973 : && !poGDS->bIgnoreReadErrors )
974 : {
975 1 : memset( pImage, 0, nBlockBufSize );
976 : CPLError( CE_Failure, CPLE_AppDefined,
977 1 : "TIFFReadEncodedStrip() failed.\n" );
978 :
979 1 : eErr = CE_Failure;
980 : }
981 : }
982 :
983 12728 : return eErr;
984 : }
985 :
986 : /* -------------------------------------------------------------------- */
987 : /* Load desired block */
988 : /* -------------------------------------------------------------------- */
989 71614 : eErr = poGDS->LoadBlockBuf( nBlockId );
990 71614 : if( eErr != CE_None )
991 : {
992 : memset( pImage, 0,
993 : nBlockXSize * nBlockYSize
994 0 : * (GDALGetDataTypeSize(eDataType) / 8) );
995 0 : return eErr;
996 : }
997 :
998 : /* -------------------------------------------------------------------- */
999 : /* Special case for YCbCr subsampled data. */
1000 : /* -------------------------------------------------------------------- */
1001 : #ifdef notdef
1002 : if( (eBandInterp == GCI_YCbCr_YBand
1003 : || eBandInterp == GCI_YCbCr_CbBand
1004 : || eBandInterp == GCI_YCbCr_CrBand)
1005 : && poGDS->nBitsPerSample == 8 )
1006 : {
1007 : uint16 hs, vs;
1008 : int iX, iY;
1009 :
1010 : TIFFGetFieldDefaulted( poGDS->hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
1011 : &hs, &vs);
1012 :
1013 : for( iY = 0; iY < nBlockYSize; iY++ )
1014 : {
1015 : for( iX = 0; iX < nBlockXSize; iX++ )
1016 : {
1017 : int iBlock = (iY / vs) * (nBlockXSize/hs) + (iX / hs);
1018 : GByte *pabySrcBlock = poGDS->pabyBlockBuf +
1019 : (vs * hs + 2) * iBlock;
1020 :
1021 : if( eBandInterp == GCI_YCbCr_YBand )
1022 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1023 : pabySrcBlock[(iX % hs) + (iY % vs) * hs];
1024 : else if( eBandInterp == GCI_YCbCr_CbBand )
1025 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1026 : pabySrcBlock[vs * hs + 0];
1027 : else if( eBandInterp == GCI_YCbCr_CrBand )
1028 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1029 : pabySrcBlock[vs * hs + 1];
1030 : }
1031 : }
1032 :
1033 : return CE_None;
1034 : }
1035 : #endif
1036 :
1037 : /* -------------------------------------------------------------------- */
1038 : /* Handle simple case of eight bit data, and pixel interleaving. */
1039 : /* -------------------------------------------------------------------- */
1040 71614 : if( poGDS->nBitsPerSample == 8 )
1041 : {
1042 : int i, nBlockPixels;
1043 : GByte *pabyImage;
1044 71520 : GByte *pabyImageDest = (GByte*)pImage;
1045 71520 : int nBands = poGDS->nBands;
1046 :
1047 71520 : pabyImage = poGDS->pabyBlockBuf + nBand - 1;
1048 :
1049 71520 : nBlockPixels = nBlockXSize * nBlockYSize;
1050 :
1051 : /* ==================================================================== */
1052 : /* Optimization for high number of words to transfer and some */
1053 : /* typical band numbers : we unroll the loop. */
1054 : /* ==================================================================== */
1055 : #define COPY_TO_DST_BUFFER(nBands) \
1056 : if (nBlockPixels > 100) \
1057 : { \
1058 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
1059 : { \
1060 : pabyImageDest[0] = pabyImage[0*nBands]; \
1061 : pabyImageDest[1] = pabyImage[1*nBands]; \
1062 : pabyImageDest[2] = pabyImage[2*nBands]; \
1063 : pabyImageDest[3] = pabyImage[3*nBands]; \
1064 : pabyImageDest[4] = pabyImage[4*nBands]; \
1065 : pabyImageDest[5] = pabyImage[5*nBands]; \
1066 : pabyImageDest[6] = pabyImage[6*nBands]; \
1067 : pabyImageDest[7] = pabyImage[7*nBands]; \
1068 : pabyImageDest[8] = pabyImage[8*nBands]; \
1069 : pabyImageDest[9] = pabyImage[9*nBands]; \
1070 : pabyImageDest[10] = pabyImage[10*nBands]; \
1071 : pabyImageDest[11] = pabyImage[11*nBands]; \
1072 : pabyImageDest[12] = pabyImage[12*nBands]; \
1073 : pabyImageDest[13] = pabyImage[13*nBands]; \
1074 : pabyImageDest[14] = pabyImage[14*nBands]; \
1075 : pabyImageDest[15] = pabyImage[15*nBands]; \
1076 : pabyImageDest += 16; \
1077 : pabyImage += 16*nBands; \
1078 : } \
1079 : nBlockPixels = nBlockPixels % 16; \
1080 : } \
1081 : for( i = 0; i < nBlockPixels; i++ ) \
1082 : { \
1083 : pabyImageDest[i] = *pabyImage; \
1084 : pabyImage += nBands; \
1085 : }
1086 :
1087 71520 : switch (nBands)
1088 : {
1089 4444 : case 3: COPY_TO_DST_BUFFER(3); break;
1090 1472 : case 4: COPY_TO_DST_BUFFER(4); break;
1091 : default:
1092 : {
1093 507933 : for( i = 0; i < nBlockPixels; i++ )
1094 : {
1095 442329 : pabyImageDest[i] = *pabyImage;
1096 442329 : pabyImage += nBands;
1097 : }
1098 : }
1099 : }
1100 : #undef COPY_TO_DST_BUFFER
1101 : }
1102 :
1103 : else
1104 : {
1105 : int i, nBlockPixels, nWordBytes;
1106 : GByte *pabyImage;
1107 :
1108 94 : nWordBytes = poGDS->nBitsPerSample / 8;
1109 94 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
1110 :
1111 94 : nBlockPixels = nBlockXSize * nBlockYSize;
1112 551822 : for( i = 0; i < nBlockPixels; i++ )
1113 : {
1114 2755440 : for( int j = 0; j < nWordBytes; j++ )
1115 : {
1116 2203712 : ((GByte *) pImage)[i*nWordBytes + j] = pabyImage[j];
1117 : }
1118 551728 : pabyImage += poGDS->nBands * nWordBytes;
1119 : }
1120 : }
1121 :
1122 71614 : if (eErr == CE_None)
1123 71614 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
1124 :
1125 71614 : return eErr;
1126 : }
1127 :
1128 :
1129 : /************************************************************************/
1130 : /* FillCacheForOtherBands() */
1131 : /************************************************************************/
1132 :
1133 71630 : CPLErr GTiffRasterBand::FillCacheForOtherBands( int nBlockXOff, int nBlockYOff )
1134 :
1135 : {
1136 71630 : CPLErr eErr = CE_None;
1137 : /* -------------------------------------------------------------------- */
1138 : /* In the fairly common case of pixel interleaved 8bit data */
1139 : /* that is multi-band, lets push the rest of the data into the */
1140 : /* block cache too, to avoid (hopefully) having to redecode it. */
1141 : /* */
1142 : /* Our following logic actually depends on the fact that the */
1143 : /* this block is already loaded, so subsequent calls will end */
1144 : /* up back in this method and pull from the loaded block. */
1145 : /* */
1146 : /* Be careful not entering this portion of code from */
1147 : /* the other bands, otherwise we'll get very deep nested calls */
1148 : /* and O(nBands^2) performance ! */
1149 : /* */
1150 : /* If there are many bands and the block cache size is not big */
1151 : /* enough to accomodate the size of all the blocks, don't enter */
1152 : /* -------------------------------------------------------------------- */
1153 71630 : if( poGDS->nBands != 1 && !poGDS->bLoadingOtherBands &&
1154 : nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) < GDALGetCacheMax64() / poGDS->nBands)
1155 : {
1156 : int iOtherBand;
1157 :
1158 1919 : poGDS->bLoadingOtherBands = TRUE;
1159 :
1160 73546 : for( iOtherBand = 1; iOtherBand <= poGDS->nBands; iOtherBand++ )
1161 : {
1162 71627 : if( iOtherBand == nBand )
1163 1919 : continue;
1164 :
1165 : GDALRasterBlock *poBlock;
1166 :
1167 : poBlock = poGDS->GetRasterBand(iOtherBand)->
1168 69708 : GetLockedBlockRef(nBlockXOff,nBlockYOff);
1169 69708 : if (poBlock == NULL)
1170 : {
1171 0 : eErr = CE_Failure;
1172 0 : break;
1173 : }
1174 69708 : poBlock->DropLock();
1175 : }
1176 :
1177 1919 : poGDS->bLoadingOtherBands = FALSE;
1178 : }
1179 :
1180 71630 : return eErr;
1181 : }
1182 :
1183 : /************************************************************************/
1184 : /* IWriteBlock() */
1185 : /************************************************************************/
1186 :
1187 24192 : CPLErr GTiffRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1188 : void * pImage )
1189 :
1190 : {
1191 : int nBlockId;
1192 24192 : CPLErr eErr = CE_None;
1193 :
1194 24192 : if (poGDS->bDebugDontWriteBlocks)
1195 7024 : return CE_None;
1196 :
1197 17168 : if (poGDS->bWriteErrorInFlushBlockBuf)
1198 : {
1199 : /* Report as an error if a previously loaded block couldn't be */
1200 : /* written correctly */
1201 0 : poGDS->bWriteErrorInFlushBlockBuf = FALSE;
1202 0 : return CE_Failure;
1203 : }
1204 :
1205 17168 : if (!poGDS->SetDirectory())
1206 0 : return CE_Failure;
1207 :
1208 : CPLAssert( poGDS != NULL
1209 : && nBlockXOff >= 0
1210 : && nBlockYOff >= 0
1211 17168 : && pImage != NULL );
1212 17168 : CPLAssert(nBlocksPerRow != 0);
1213 :
1214 : /* -------------------------------------------------------------------- */
1215 : /* Handle case of "separate" images */
1216 : /* -------------------------------------------------------------------- */
1217 17168 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
1218 : || poGDS->nBands == 1 )
1219 : {
1220 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow
1221 15054 : + (nBand-1) * poGDS->nBlocksPerBand;
1222 :
1223 15054 : eErr = poGDS->WriteEncodedTileOrStrip(nBlockId, pImage, TRUE);
1224 :
1225 15054 : return eErr;
1226 : }
1227 :
1228 : /* -------------------------------------------------------------------- */
1229 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
1230 : /* -------------------------------------------------------------------- */
1231 2114 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1232 :
1233 2114 : eErr = poGDS->LoadBlockBuf( nBlockId );
1234 2114 : if( eErr != CE_None )
1235 0 : return eErr;
1236 :
1237 : /* -------------------------------------------------------------------- */
1238 : /* On write of pixel interleaved data, we might as well flush */
1239 : /* out any other bands that are dirty in our cache. This is */
1240 : /* especially helpful when writing compressed blocks. */
1241 : /* -------------------------------------------------------------------- */
1242 : int iBand;
1243 2114 : int nWordBytes = poGDS->nBitsPerSample / 8;
1244 2114 : int nBands = poGDS->nBands;
1245 :
1246 8699 : for( iBand = 0; iBand < nBands; iBand++ )
1247 : {
1248 6585 : const GByte *pabyThisImage = NULL;
1249 6585 : GDALRasterBlock *poBlock = NULL;
1250 :
1251 6585 : if( iBand+1 == nBand )
1252 2114 : pabyThisImage = (GByte *) pImage;
1253 : else
1254 : {
1255 : poBlock = ((GTiffRasterBand *)poGDS->GetRasterBand( iBand+1 ))
1256 4471 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
1257 :
1258 4471 : if( poBlock == NULL )
1259 117 : continue;
1260 :
1261 4354 : if( !poBlock->GetDirty() )
1262 : {
1263 90 : poBlock->DropLock();
1264 90 : continue;
1265 : }
1266 :
1267 4264 : pabyThisImage = (GByte *) poBlock->GetDataRef();
1268 : }
1269 :
1270 6378 : int i, nBlockPixels = nBlockXSize * nBlockYSize;
1271 6378 : GByte *pabyOut = poGDS->pabyBlockBuf + iBand*nWordBytes;
1272 :
1273 6378 : if (nWordBytes == 1)
1274 : {
1275 :
1276 : /* ==================================================================== */
1277 : /* Optimization for high number of words to transfer and some */
1278 : /* typical band numbers : we unroll the loop. */
1279 : /* ==================================================================== */
1280 : #define COPY_TO_DST_BUFFER(nBands) \
1281 : if (nBlockPixels > 100) \
1282 : { \
1283 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
1284 : { \
1285 : pabyOut[0*nBands] = pabyThisImage[0]; \
1286 : pabyOut[1*nBands] = pabyThisImage[1]; \
1287 : pabyOut[2*nBands] = pabyThisImage[2]; \
1288 : pabyOut[3*nBands] = pabyThisImage[3]; \
1289 : pabyOut[4*nBands] = pabyThisImage[4]; \
1290 : pabyOut[5*nBands] = pabyThisImage[5]; \
1291 : pabyOut[6*nBands] = pabyThisImage[6]; \
1292 : pabyOut[7*nBands] = pabyThisImage[7]; \
1293 : pabyOut[8*nBands] = pabyThisImage[8]; \
1294 : pabyOut[9*nBands] = pabyThisImage[9]; \
1295 : pabyOut[10*nBands] = pabyThisImage[10]; \
1296 : pabyOut[11*nBands] = pabyThisImage[11]; \
1297 : pabyOut[12*nBands] = pabyThisImage[12]; \
1298 : pabyOut[13*nBands] = pabyThisImage[13]; \
1299 : pabyOut[14*nBands] = pabyThisImage[14]; \
1300 : pabyOut[15*nBands] = pabyThisImage[15]; \
1301 : pabyThisImage += 16; \
1302 : pabyOut += 16*nBands; \
1303 : } \
1304 : nBlockPixels = nBlockPixels % 16; \
1305 : } \
1306 : for( i = 0; i < nBlockPixels; i++ ) \
1307 : { \
1308 : *pabyOut = pabyThisImage[i]; \
1309 : pabyOut += nBands; \
1310 : }
1311 :
1312 6314 : switch (nBands)
1313 : {
1314 5270 : case 3: COPY_TO_DST_BUFFER(3); break;
1315 985 : case 4: COPY_TO_DST_BUFFER(4); break;
1316 : default:
1317 : {
1318 230905 : for( i = 0; i < nBlockPixels; i++ )
1319 : {
1320 230846 : *pabyOut = pabyThisImage[i];
1321 230846 : pabyOut += nBands;
1322 : }
1323 : }
1324 : }
1325 : #undef COPY_TO_DST_BUFFER
1326 : }
1327 : else
1328 : {
1329 205496 : for( i = 0; i < nBlockPixels; i++ )
1330 : {
1331 205432 : memcpy( pabyOut, pabyThisImage, nWordBytes );
1332 :
1333 205432 : pabyOut += nWordBytes * nBands;
1334 205432 : pabyThisImage += nWordBytes;
1335 : }
1336 : }
1337 :
1338 6378 : if( poBlock != NULL )
1339 : {
1340 4264 : poBlock->MarkClean();
1341 4264 : poBlock->DropLock();
1342 : }
1343 : }
1344 :
1345 2114 : poGDS->bLoadedBlockDirty = TRUE;
1346 :
1347 2114 : return CE_None;
1348 : }
1349 :
1350 : /************************************************************************/
1351 : /* GetOffset() */
1352 : /************************************************************************/
1353 :
1354 133908 : double GTiffRasterBand::GetOffset( int *pbSuccess )
1355 :
1356 : {
1357 133908 : if( pbSuccess )
1358 133396 : *pbSuccess = bHaveOffsetScale;
1359 133908 : return dfOffset;
1360 : }
1361 :
1362 : /************************************************************************/
1363 : /* SetOffset() */
1364 : /************************************************************************/
1365 :
1366 10 : CPLErr GTiffRasterBand::SetOffset( double dfNewValue )
1367 :
1368 : {
1369 10 : if( !bHaveOffsetScale || dfNewValue != dfOffset )
1370 10 : poGDS->bMetadataChanged = TRUE;
1371 :
1372 10 : bHaveOffsetScale = TRUE;
1373 10 : dfOffset = dfNewValue;
1374 10 : return CE_None;
1375 : }
1376 :
1377 : /************************************************************************/
1378 : /* GetScale() */
1379 : /************************************************************************/
1380 :
1381 133908 : double GTiffRasterBand::GetScale( int *pbSuccess )
1382 :
1383 : {
1384 133908 : if( pbSuccess )
1385 975 : *pbSuccess = bHaveOffsetScale;
1386 133908 : return dfScale;
1387 : }
1388 :
1389 : /************************************************************************/
1390 : /* SetScale() */
1391 : /************************************************************************/
1392 :
1393 10 : CPLErr GTiffRasterBand::SetScale( double dfNewValue )
1394 :
1395 : {
1396 10 : if( !bHaveOffsetScale || dfNewValue != dfScale )
1397 10 : poGDS->bMetadataChanged = TRUE;
1398 :
1399 10 : bHaveOffsetScale = TRUE;
1400 10 : dfScale = dfNewValue;
1401 10 : return CE_None;
1402 : }
1403 :
1404 : /************************************************************************/
1405 : /* GetUnitType() */
1406 : /************************************************************************/
1407 :
1408 133244 : const char* GTiffRasterBand::GetUnitType()
1409 :
1410 : {
1411 133244 : return osUnitType.c_str();
1412 : }
1413 :
1414 : /************************************************************************/
1415 : /* SetUnitType() */
1416 : /************************************************************************/
1417 :
1418 17 : CPLErr GTiffRasterBand::SetUnitType( const char* pszNewValue )
1419 :
1420 : {
1421 17 : CPLString osNewValue(pszNewValue ? pszNewValue : "");
1422 17 : if( osNewValue.compare(osUnitType) != 0 )
1423 17 : poGDS->bMetadataChanged = TRUE;
1424 :
1425 17 : osUnitType = osNewValue;
1426 17 : return CE_None;
1427 : }
1428 :
1429 : /************************************************************************/
1430 : /* GetMetadata() */
1431 : /************************************************************************/
1432 :
1433 2062 : char **GTiffRasterBand::GetMetadata( const char * pszDomain )
1434 :
1435 : {
1436 2062 : return oGTiffMDMD.GetMetadata( pszDomain );
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* SetMetadata() */
1441 : /************************************************************************/
1442 :
1443 318 : CPLErr GTiffRasterBand::SetMetadata( char ** papszMD, const char *pszDomain )
1444 :
1445 : {
1446 318 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1447 : {
1448 318 : if( papszMD != NULL )
1449 34 : poGDS->bMetadataChanged = TRUE;
1450 : }
1451 :
1452 318 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
1453 : }
1454 :
1455 : /************************************************************************/
1456 : /* GetMetadataItem() */
1457 : /************************************************************************/
1458 :
1459 3620 : const char *GTiffRasterBand::GetMetadataItem( const char * pszName,
1460 : const char * pszDomain )
1461 :
1462 : {
1463 3620 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
1464 : }
1465 :
1466 : /************************************************************************/
1467 : /* SetMetadataItem() */
1468 : /************************************************************************/
1469 :
1470 658 : CPLErr GTiffRasterBand::SetMetadataItem( const char *pszName,
1471 : const char *pszValue,
1472 : const char *pszDomain )
1473 :
1474 : {
1475 658 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1476 658 : poGDS->bMetadataChanged = TRUE;
1477 :
1478 658 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
1479 : }
1480 :
1481 : /************************************************************************/
1482 : /* GetColorInterpretation() */
1483 : /************************************************************************/
1484 :
1485 3065 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1486 :
1487 : {
1488 3065 : return eBandInterp;
1489 : }
1490 :
1491 : /************************************************************************/
1492 : /* SetColorInterpretation() */
1493 : /************************************************************************/
1494 :
1495 31 : CPLErr GTiffRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
1496 :
1497 : {
1498 31 : if( eInterp == eBandInterp )
1499 23 : return CE_None;
1500 :
1501 8 : if( poGDS->bCrystalized )
1502 0 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1503 :
1504 : /* greyscale + alpha */
1505 8 : else if( eInterp == GCI_AlphaBand
1506 : && nBand == 2
1507 : && poGDS->nSamplesPerPixel == 2
1508 : && poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK )
1509 : {
1510 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
1511 :
1512 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1513 1 : eBandInterp = eInterp;
1514 1 : return CE_None;
1515 : }
1516 :
1517 : /* RGB + alpha */
1518 7 : else if( eInterp == GCI_AlphaBand
1519 : && nBand == 4
1520 : && poGDS->nSamplesPerPixel == 4
1521 : && poGDS->nPhotometric == PHOTOMETRIC_RGB )
1522 : {
1523 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
1524 :
1525 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1526 1 : eBandInterp = eInterp;
1527 1 : return CE_None;
1528 : }
1529 :
1530 : else
1531 6 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1532 : }
1533 :
1534 : /************************************************************************/
1535 : /* GetColorTable() */
1536 : /************************************************************************/
1537 :
1538 2115 : GDALColorTable *GTiffRasterBand::GetColorTable()
1539 :
1540 : {
1541 2115 : if( nBand == 1 )
1542 1707 : return poGDS->poColorTable;
1543 : else
1544 408 : return NULL;
1545 : }
1546 :
1547 : /************************************************************************/
1548 : /* SetColorTable() */
1549 : /************************************************************************/
1550 :
1551 15 : CPLErr GTiffRasterBand::SetColorTable( GDALColorTable * poCT )
1552 :
1553 : {
1554 : /* -------------------------------------------------------------------- */
1555 : /* Check if this is even a candidate for applying a PCT. */
1556 : /* -------------------------------------------------------------------- */
1557 15 : if( nBand != 1)
1558 : {
1559 : CPLError( CE_Failure, CPLE_NotSupported,
1560 0 : "SetColorTable() can only be called on band 1." );
1561 0 : return CE_Failure;
1562 : }
1563 :
1564 15 : if( poGDS->nSamplesPerPixel != 1 && poGDS->nSamplesPerPixel != 2)
1565 : {
1566 : CPLError( CE_Failure, CPLE_NotSupported,
1567 0 : "SetColorTable() not supported for multi-sample TIFF files." );
1568 0 : return CE_Failure;
1569 : }
1570 :
1571 15 : if( eDataType != GDT_Byte && eDataType != GDT_UInt16 )
1572 : {
1573 : CPLError( CE_Failure, CPLE_NotSupported,
1574 0 : "SetColorTable() only supported for Byte or UInt16 bands in TIFF format." );
1575 0 : return CE_Failure;
1576 : }
1577 :
1578 : /* -------------------------------------------------------------------- */
1579 : /* We are careful about calling SetDirectory() to avoid */
1580 : /* prematurely crystalizing the directory. (#2820) */
1581 : /* -------------------------------------------------------------------- */
1582 15 : if( poGDS->bCrystalized )
1583 : {
1584 4 : if (!poGDS->SetDirectory())
1585 0 : return CE_Failure;
1586 : }
1587 :
1588 : /* -------------------------------------------------------------------- */
1589 : /* Is this really a request to clear the color table? */
1590 : /* -------------------------------------------------------------------- */
1591 15 : if( poCT == NULL || poCT->GetColorEntryCount() == 0 )
1592 : {
1593 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC,
1594 1 : PHOTOMETRIC_MINISBLACK );
1595 :
1596 : #ifdef HAVE_UNSETFIELD
1597 1 : TIFFUnsetField( poGDS->hTIFF, TIFFTAG_COLORMAP );
1598 : #else
1599 : CPLDebug( "GTiff",
1600 : "TIFFUnsetField() not supported, colormap may not be cleared." );
1601 : #endif
1602 :
1603 1 : if( poGDS->poColorTable )
1604 : {
1605 1 : delete poGDS->poColorTable;
1606 1 : poGDS->poColorTable = NULL;
1607 : }
1608 :
1609 1 : return CE_None;
1610 : }
1611 :
1612 : /* -------------------------------------------------------------------- */
1613 : /* Write out the colortable, and update the configuration. */
1614 : /* -------------------------------------------------------------------- */
1615 : int nColors;
1616 :
1617 14 : if( eDataType == GDT_Byte )
1618 13 : nColors = 256;
1619 : else
1620 1 : nColors = 65536;
1621 :
1622 : unsigned short *panTRed, *panTGreen, *panTBlue;
1623 :
1624 14 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1625 14 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1626 14 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1627 :
1628 68878 : for( int iColor = 0; iColor < nColors; iColor++ )
1629 : {
1630 68864 : if( iColor < poCT->GetColorEntryCount() )
1631 : {
1632 : GDALColorEntry sRGB;
1633 :
1634 824 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
1635 :
1636 824 : panTRed[iColor] = (unsigned short) (257 * sRGB.c1);
1637 824 : panTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
1638 824 : panTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
1639 : }
1640 : else
1641 : {
1642 68040 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
1643 : }
1644 : }
1645 :
1646 14 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
1647 : TIFFSetField( poGDS->hTIFF, TIFFTAG_COLORMAP,
1648 14 : panTRed, panTGreen, panTBlue );
1649 :
1650 14 : CPLFree( panTRed );
1651 14 : CPLFree( panTGreen );
1652 14 : CPLFree( panTBlue );
1653 :
1654 14 : if( poGDS->poColorTable )
1655 3 : delete poGDS->poColorTable;
1656 :
1657 : /* libtiff 3.X needs setting this in all cases (creation or update) */
1658 : /* whereas libtiff 4.X would just need it if there */
1659 : /* was no color table before */
1660 : #if 0
1661 : else
1662 : #endif
1663 14 : poGDS->bNeedsRewrite = TRUE;
1664 :
1665 14 : poGDS->poColorTable = poCT->Clone();
1666 :
1667 14 : return CE_None;
1668 : }
1669 :
1670 : /************************************************************************/
1671 : /* GetNoDataValue() */
1672 : /************************************************************************/
1673 :
1674 18579 : double GTiffRasterBand::GetNoDataValue( int * pbSuccess )
1675 :
1676 : {
1677 18579 : if( bNoDataSet )
1678 : {
1679 91 : if( pbSuccess )
1680 82 : *pbSuccess = TRUE;
1681 :
1682 91 : return dfNoDataValue;
1683 : }
1684 :
1685 18488 : if( poGDS->bNoDataSet )
1686 : {
1687 241 : if( pbSuccess )
1688 225 : *pbSuccess = TRUE;
1689 :
1690 241 : return poGDS->dfNoDataValue;
1691 : }
1692 :
1693 18247 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
1694 : }
1695 :
1696 : /************************************************************************/
1697 : /* SetNoDataValue() */
1698 : /************************************************************************/
1699 :
1700 64 : CPLErr GTiffRasterBand::SetNoDataValue( double dfNoData )
1701 :
1702 : {
1703 64 : if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
1704 16 : return CE_None;
1705 :
1706 48 : if (!poGDS->SetDirectory()) // needed to call TIFFSetField().
1707 0 : return CE_Failure;
1708 :
1709 48 : poGDS->bNoDataSet = TRUE;
1710 48 : poGDS->dfNoDataValue = dfNoData;
1711 :
1712 48 : poGDS->WriteNoDataValue( poGDS->hTIFF, dfNoData );
1713 48 : poGDS->bNeedsRewrite = TRUE;
1714 :
1715 48 : bNoDataSet = TRUE;
1716 48 : dfNoDataValue = dfNoData;
1717 48 : return CE_None;
1718 : }
1719 :
1720 : /************************************************************************/
1721 : /* NullBlock() */
1722 : /* */
1723 : /* Set the block data to the null value if it is set, or zero */
1724 : /* if there is no null data value. */
1725 : /************************************************************************/
1726 :
1727 13224 : void GTiffRasterBand::NullBlock( void *pData )
1728 :
1729 : {
1730 13224 : int nWords = nBlockXSize * nBlockYSize;
1731 13224 : int nChunkSize = MAX(1,GDALGetDataTypeSize(eDataType)/8);
1732 :
1733 : int bNoDataSet;
1734 13224 : double dfNoData = GetNoDataValue( &bNoDataSet );
1735 13224 : if( !bNoDataSet )
1736 : {
1737 : #ifdef ESRI_BUILD
1738 : if ( poGDS->nBitsPerSample >= 2 )
1739 : memset( pData, 0, nWords*nChunkSize );
1740 : else
1741 : memset( pData, 1, nWords*nChunkSize );
1742 : #else
1743 13140 : memset( pData, 0, nWords*nChunkSize );
1744 : #endif
1745 : }
1746 : else
1747 : {
1748 : /* Will convert nodata value to the right type and copy efficiently */
1749 : GDALCopyWords( &dfNoData, GDT_Float64, 0,
1750 84 : pData, eDataType, nChunkSize, nWords);
1751 : }
1752 13224 : }
1753 :
1754 : /************************************************************************/
1755 : /* GetOverviewCount() */
1756 : /************************************************************************/
1757 :
1758 300667 : int GTiffRasterBand::GetOverviewCount()
1759 :
1760 : {
1761 300667 : poGDS->ScanDirectories();
1762 :
1763 300667 : if( poGDS->nOverviewCount > 0 )
1764 921 : return poGDS->nOverviewCount;
1765 : else
1766 299746 : return GDALRasterBand::GetOverviewCount();
1767 : }
1768 :
1769 : /************************************************************************/
1770 : /* GetOverview() */
1771 : /************************************************************************/
1772 :
1773 1051 : GDALRasterBand *GTiffRasterBand::GetOverview( int i )
1774 :
1775 : {
1776 1051 : poGDS->ScanDirectories();
1777 :
1778 1051 : if( poGDS->nOverviewCount > 0 )
1779 : {
1780 767 : if( i < 0 || i >= poGDS->nOverviewCount )
1781 0 : return NULL;
1782 : else
1783 767 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
1784 : }
1785 : else
1786 284 : return GDALRasterBand::GetOverview( i );
1787 : }
1788 :
1789 : /************************************************************************/
1790 : /* GetMaskFlags() */
1791 : /************************************************************************/
1792 :
1793 3199 : int GTiffRasterBand::GetMaskFlags()
1794 : {
1795 3199 : poGDS->ScanDirectories();
1796 :
1797 3199 : if( poGDS->poMaskDS != NULL )
1798 : {
1799 51 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1800 : {
1801 45 : return GMF_PER_DATASET;
1802 : }
1803 : else
1804 : {
1805 6 : return 0;
1806 : }
1807 : }
1808 : else
1809 3148 : return GDALPamRasterBand::GetMaskFlags();
1810 : }
1811 :
1812 : /************************************************************************/
1813 : /* GetMaskBand() */
1814 : /************************************************************************/
1815 :
1816 2432 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1817 : {
1818 2432 : poGDS->ScanDirectories();
1819 :
1820 2432 : if( poGDS->poMaskDS != NULL )
1821 : {
1822 1419 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1823 1413 : return poGDS->poMaskDS->GetRasterBand(1);
1824 : else
1825 6 : return poGDS->poMaskDS->GetRasterBand(nBand);
1826 : }
1827 : else
1828 1013 : return GDALPamRasterBand::GetMaskBand();
1829 : }
1830 :
1831 : /************************************************************************/
1832 : /* ==================================================================== */
1833 : /* GTiffSplitBand */
1834 : /* ==================================================================== */
1835 : /************************************************************************/
1836 :
1837 : class GTiffSplitBand : public GTiffRasterBand
1838 : {
1839 : friend class GTiffDataset;
1840 :
1841 : public:
1842 :
1843 : GTiffSplitBand( GTiffDataset *, int );
1844 : virtual ~GTiffSplitBand();
1845 :
1846 : virtual CPLErr IReadBlock( int, int, void * );
1847 : virtual CPLErr IWriteBlock( int, int, void * );
1848 : };
1849 :
1850 : /************************************************************************/
1851 : /* GTiffSplitBand() */
1852 : /************************************************************************/
1853 :
1854 27 : GTiffSplitBand::GTiffSplitBand( GTiffDataset *poDS, int nBand )
1855 27 : : GTiffRasterBand( poDS, nBand )
1856 :
1857 : {
1858 27 : nBlockXSize = poDS->GetRasterXSize();
1859 27 : nBlockYSize = 1;
1860 27 : }
1861 :
1862 : /************************************************************************/
1863 : /* ~GTiffSplitBand() */
1864 : /************************************************************************/
1865 :
1866 27 : GTiffSplitBand::~GTiffSplitBand()
1867 : {
1868 27 : }
1869 :
1870 : /************************************************************************/
1871 : /* IReadBlock() */
1872 : /************************************************************************/
1873 :
1874 69856 : CPLErr GTiffSplitBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1875 : void * pImage )
1876 :
1877 : {
1878 : (void) nBlockXOff;
1879 :
1880 : /* Optimization when reading the same line in a contig multi-band TIFF */
1881 69856 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 &&
1882 : poGDS->nLastLineRead == nBlockYOff )
1883 : {
1884 9 : goto extract_band_data;
1885 : }
1886 :
1887 69847 : if (!poGDS->SetDirectory())
1888 0 : return CE_Failure;
1889 :
1890 109694 : if (poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
1891 : poGDS->nBands > 1)
1892 : {
1893 39847 : if (poGDS->pabyBlockBuf == NULL)
1894 4 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
1895 : }
1896 : else
1897 : {
1898 30000 : CPLAssert(TIFFScanlineSize(poGDS->hTIFF) == nBlockXSize);
1899 : }
1900 :
1901 : /* -------------------------------------------------------------------- */
1902 : /* Read through to target scanline. */
1903 : /* -------------------------------------------------------------------- */
1904 69847 : if( poGDS->nLastLineRead >= nBlockYOff )
1905 31 : poGDS->nLastLineRead = -1;
1906 :
1907 69847 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE && poGDS->nBands > 1 )
1908 : {
1909 : /* If we change of band, we must start reading the */
1910 : /* new strip from its beginning */
1911 30000 : if ( poGDS->nLastBandRead != nBand )
1912 20 : poGDS->nLastLineRead = -1;
1913 30000 : poGDS->nLastBandRead = nBand;
1914 : }
1915 :
1916 258854 : while( poGDS->nLastLineRead < nBlockYOff )
1917 : {
1918 119160 : if( TIFFReadScanline( poGDS->hTIFF,
1919 : poGDS->pabyBlockBuf ? poGDS->pabyBlockBuf : pImage,
1920 : ++poGDS->nLastLineRead,
1921 : (poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE) ? (uint16) (nBand-1) : 0 ) == -1
1922 : && !poGDS->bIgnoreReadErrors )
1923 : {
1924 : CPLError( CE_Failure, CPLE_AppDefined,
1925 0 : "TIFFReadScanline() failed." );
1926 0 : return CE_Failure;
1927 : }
1928 : }
1929 :
1930 : extract_band_data:
1931 : /* -------------------------------------------------------------------- */
1932 : /* Extract band data from contig buffer. */
1933 : /* -------------------------------------------------------------------- */
1934 69856 : if ( poGDS->pabyBlockBuf != NULL )
1935 : {
1936 39856 : int iPixel, iSrcOffset= nBand - 1, iDstOffset=0;
1937 :
1938 13947104 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset+=poGDS->nBands, iDstOffset++ )
1939 : {
1940 13907248 : ((GByte *) pImage)[iDstOffset] = poGDS->pabyBlockBuf[iSrcOffset];
1941 : }
1942 : }
1943 :
1944 69856 : return CE_None;
1945 : }
1946 :
1947 : /************************************************************************/
1948 : /* IWriteBlock() */
1949 : /************************************************************************/
1950 :
1951 0 : CPLErr GTiffSplitBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1952 : void * pImage )
1953 :
1954 : {
1955 : (void) nBlockXOff;
1956 : (void) nBlockYOff;
1957 : (void) pImage;
1958 :
1959 : CPLError( CE_Failure, CPLE_AppDefined,
1960 0 : "Split bands are read-only." );
1961 0 : return CE_Failure;
1962 : }
1963 :
1964 : /************************************************************************/
1965 : /* ==================================================================== */
1966 : /* GTiffRGBABand */
1967 : /* ==================================================================== */
1968 : /************************************************************************/
1969 :
1970 : class GTiffRGBABand : public GTiffRasterBand
1971 20 : {
1972 : friend class GTiffDataset;
1973 :
1974 : public:
1975 :
1976 : GTiffRGBABand( GTiffDataset *, int );
1977 :
1978 : virtual CPLErr IReadBlock( int, int, void * );
1979 : virtual CPLErr IWriteBlock( int, int, void * );
1980 :
1981 : virtual GDALColorInterp GetColorInterpretation();
1982 : };
1983 :
1984 :
1985 : /************************************************************************/
1986 : /* GTiffRGBABand() */
1987 : /************************************************************************/
1988 :
1989 20 : GTiffRGBABand::GTiffRGBABand( GTiffDataset *poDS, int nBand )
1990 20 : : GTiffRasterBand( poDS, nBand )
1991 :
1992 : {
1993 20 : eDataType = GDT_Byte;
1994 20 : }
1995 :
1996 : /************************************************************************/
1997 : /* IWriteBlock() */
1998 : /************************************************************************/
1999 :
2000 0 : CPLErr GTiffRGBABand::IWriteBlock( int, int, void * )
2001 :
2002 : {
2003 : CPLError( CE_Failure, CPLE_AppDefined,
2004 0 : "RGBA interpreted raster bands are read-only." );
2005 0 : return CE_Failure;
2006 : }
2007 :
2008 : /************************************************************************/
2009 : /* IReadBlock() */
2010 : /************************************************************************/
2011 :
2012 16 : CPLErr GTiffRGBABand::IReadBlock( int nBlockXOff, int nBlockYOff,
2013 : void * pImage )
2014 :
2015 : {
2016 : int nBlockBufSize, nBlockId;
2017 16 : CPLErr eErr = CE_None;
2018 :
2019 16 : if (!poGDS->SetDirectory())
2020 0 : return CE_Failure;
2021 :
2022 16 : CPLAssert(nBlocksPerRow != 0);
2023 16 : nBlockBufSize = 4 * nBlockXSize * nBlockYSize;
2024 16 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2025 :
2026 : /* -------------------------------------------------------------------- */
2027 : /* Allocate a temporary buffer for this strip. */
2028 : /* -------------------------------------------------------------------- */
2029 16 : if( poGDS->pabyBlockBuf == NULL )
2030 : {
2031 3 : poGDS->pabyBlockBuf = (GByte *) VSIMalloc3( 4, nBlockXSize, nBlockYSize );
2032 3 : if( poGDS->pabyBlockBuf == NULL )
2033 0 : return( CE_Failure );
2034 : }
2035 :
2036 : /* -------------------------------------------------------------------- */
2037 : /* Read the strip */
2038 : /* -------------------------------------------------------------------- */
2039 16 : if( poGDS->nLoadedBlock != nBlockId )
2040 : {
2041 4 : if( TIFFIsTiled( poGDS->hTIFF ) )
2042 : {
2043 1 : if( TIFFReadRGBATile(poGDS->hTIFF,
2044 : nBlockXOff * nBlockXSize,
2045 : nBlockYOff * nBlockYSize,
2046 : (uint32 *) poGDS->pabyBlockBuf) == -1
2047 : && !poGDS->bIgnoreReadErrors )
2048 : {
2049 : /* Once TIFFError() is properly hooked, this can go away */
2050 : CPLError( CE_Failure, CPLE_AppDefined,
2051 0 : "TIFFReadRGBATile() failed." );
2052 :
2053 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
2054 :
2055 0 : eErr = CE_Failure;
2056 : }
2057 : }
2058 : else
2059 : {
2060 3 : if( TIFFReadRGBAStrip(poGDS->hTIFF,
2061 : nBlockId * nBlockYSize,
2062 : (uint32 *) poGDS->pabyBlockBuf) == -1
2063 : && !poGDS->bIgnoreReadErrors )
2064 : {
2065 : /* Once TIFFError() is properly hooked, this can go away */
2066 : CPLError( CE_Failure, CPLE_AppDefined,
2067 0 : "TIFFReadRGBAStrip() failed." );
2068 :
2069 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
2070 :
2071 0 : eErr = CE_Failure;
2072 : }
2073 : }
2074 : }
2075 :
2076 16 : poGDS->nLoadedBlock = nBlockId;
2077 :
2078 : /* -------------------------------------------------------------------- */
2079 : /* Handle simple case of eight bit data, and pixel interleaving. */
2080 : /* -------------------------------------------------------------------- */
2081 : int iDestLine, nBO;
2082 : int nThisBlockYSize;
2083 :
2084 16 : if( (nBlockYOff+1) * nBlockYSize > GetYSize()
2085 : && !TIFFIsTiled( poGDS->hTIFF ) )
2086 4 : nThisBlockYSize = GetYSize() - nBlockYOff * nBlockYSize;
2087 : else
2088 12 : nThisBlockYSize = nBlockYSize;
2089 :
2090 : #ifdef CPL_LSB
2091 16 : nBO = nBand - 1;
2092 : #else
2093 : nBO = 4 - nBand;
2094 : #endif
2095 :
2096 1116 : for( iDestLine = 0; iDestLine < nThisBlockYSize; iDestLine++ )
2097 : {
2098 : int nSrcOffset;
2099 :
2100 1100 : nSrcOffset = (nThisBlockYSize - iDestLine - 1) * nBlockXSize * 4;
2101 :
2102 : GDALCopyWords( poGDS->pabyBlockBuf + nBO + nSrcOffset, GDT_Byte, 4,
2103 : ((GByte *) pImage)+iDestLine*nBlockXSize, GDT_Byte, 1,
2104 1100 : nBlockXSize );
2105 : }
2106 :
2107 16 : if (eErr == CE_None)
2108 16 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
2109 :
2110 16 : return eErr;
2111 : }
2112 :
2113 : /************************************************************************/
2114 : /* GetColorInterpretation() */
2115 : /************************************************************************/
2116 :
2117 6 : GDALColorInterp GTiffRGBABand::GetColorInterpretation()
2118 :
2119 : {
2120 6 : if( nBand == 1 )
2121 2 : return GCI_RedBand;
2122 4 : else if( nBand == 2 )
2123 1 : return GCI_GreenBand;
2124 3 : else if( nBand == 3 )
2125 1 : return GCI_BlueBand;
2126 : else
2127 2 : return GCI_AlphaBand;
2128 : }
2129 :
2130 : /************************************************************************/
2131 : /* ==================================================================== */
2132 : /* GTiffOddBitsBand */
2133 : /* ==================================================================== */
2134 : /************************************************************************/
2135 :
2136 : class GTiffOddBitsBand : public GTiffRasterBand
2137 : {
2138 : friend class GTiffDataset;
2139 : public:
2140 :
2141 : GTiffOddBitsBand( GTiffDataset *, int );
2142 : virtual ~GTiffOddBitsBand();
2143 :
2144 : virtual CPLErr IReadBlock( int, int, void * );
2145 : virtual CPLErr IWriteBlock( int, int, void * );
2146 : };
2147 :
2148 :
2149 : /************************************************************************/
2150 : /* GTiffOddBitsBand() */
2151 : /************************************************************************/
2152 :
2153 382 : GTiffOddBitsBand::GTiffOddBitsBand( GTiffDataset *poGDS, int nBand )
2154 382 : : GTiffRasterBand( poGDS, nBand )
2155 :
2156 : {
2157 382 : eDataType = GDT_Byte;
2158 382 : if( poGDS->nSampleFormat == SAMPLEFORMAT_IEEEFP )
2159 2 : eDataType = GDT_Float32;
2160 477 : else if( poGDS->nBitsPerSample > 8 && poGDS->nBitsPerSample < 16 )
2161 97 : eDataType = GDT_UInt16;
2162 283 : else if( poGDS->nBitsPerSample > 16 )
2163 67 : eDataType = GDT_UInt32;
2164 382 : }
2165 :
2166 : /************************************************************************/
2167 : /* ~GTiffOddBitsBand() */
2168 : /************************************************************************/
2169 :
2170 382 : GTiffOddBitsBand::~GTiffOddBitsBand()
2171 :
2172 : {
2173 382 : }
2174 :
2175 : /************************************************************************/
2176 : /* IWriteBlock() */
2177 : /************************************************************************/
2178 :
2179 441 : CPLErr GTiffOddBitsBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2180 : void *pImage )
2181 :
2182 : {
2183 : int nBlockId;
2184 441 : CPLErr eErr = CE_None;
2185 :
2186 441 : if (poGDS->bWriteErrorInFlushBlockBuf)
2187 : {
2188 : /* Report as an error if a previously loaded block couldn't be */
2189 : /* written correctly */
2190 0 : poGDS->bWriteErrorInFlushBlockBuf = FALSE;
2191 0 : return CE_Failure;
2192 : }
2193 :
2194 441 : if (!poGDS->SetDirectory())
2195 0 : return CE_Failure;
2196 :
2197 : CPLAssert( poGDS != NULL
2198 : && nBlockXOff >= 0
2199 : && nBlockYOff >= 0
2200 441 : && pImage != NULL );
2201 :
2202 441 : if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
2203 : {
2204 : CPLError(CE_Failure, CPLE_NotSupported,
2205 0 : "Writing float data with nBitsPerSample < 32 is unsupported");
2206 0 : return CE_Failure;
2207 : }
2208 :
2209 : /* -------------------------------------------------------------------- */
2210 : /* Load the block buffer. */
2211 : /* -------------------------------------------------------------------- */
2212 441 : CPLAssert(nBlocksPerRow != 0);
2213 441 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2214 :
2215 441 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
2216 18 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
2217 :
2218 : /* Only read content from disk in the CONTIG case */
2219 : eErr = poGDS->LoadBlockBuf( nBlockId,
2220 441 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 );
2221 441 : if( eErr != CE_None )
2222 0 : return eErr;
2223 :
2224 441 : GUInt32 nMaxVal = (1 << poGDS->nBitsPerSample) - 1;
2225 :
2226 : /* -------------------------------------------------------------------- */
2227 : /* Handle case of "separate" images or single band images where */
2228 : /* no interleaving with other data is required. */
2229 : /* -------------------------------------------------------------------- */
2230 441 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
2231 : || poGDS->nBands == 1 )
2232 : {
2233 425 : int iBit, iPixel, iBitOffset = 0;
2234 : int iX, iY, nBitsPerLine;
2235 :
2236 : // bits per line rounds up to next byte boundary.
2237 425 : nBitsPerLine = nBlockXSize * poGDS->nBitsPerSample;
2238 425 : if( (nBitsPerLine & 7) != 0 )
2239 35 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2240 :
2241 : /* Initialize to zero as we set the buffer with binary or operations */
2242 425 : if (poGDS->nBitsPerSample != 24)
2243 420 : memset(poGDS->pabyBlockBuf, 0, (nBitsPerLine / 8) * nBlockYSize);
2244 :
2245 425 : iPixel = 0;
2246 40759 : for( iY = 0; iY < nBlockYSize; iY++ )
2247 : {
2248 40334 : iBitOffset = iY * nBitsPerLine;
2249 :
2250 : /* Small optimization in 1 bit case */
2251 40334 : if (poGDS->nBitsPerSample == 1)
2252 : {
2253 18178763 : for( iX = 0; iX < nBlockXSize; iX++ )
2254 : {
2255 18139027 : if (((GByte *) pImage)[iPixel++])
2256 10262134 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2257 18139027 : iBitOffset++;
2258 : }
2259 :
2260 39736 : continue;
2261 : }
2262 :
2263 39368 : for( iX = 0; iX < nBlockXSize; iX++ )
2264 : {
2265 38770 : GUInt32 nInWord = 0;
2266 38770 : if( eDataType == GDT_Byte )
2267 400 : nInWord = ((GByte *) pImage)[iPixel++];
2268 38370 : else if( eDataType == GDT_UInt16 )
2269 35569 : nInWord = ((GUInt16 *) pImage)[iPixel++];
2270 2801 : else if( eDataType == GDT_UInt32 )
2271 2801 : nInWord = ((GUInt32 *) pImage)[iPixel++];
2272 : else
2273 0 : CPLAssert(0);
2274 :
2275 38770 : if (nInWord > nMaxVal)
2276 : {
2277 400 : nInWord = nMaxVal;
2278 400 : if( !poGDS->bClipWarn )
2279 : {
2280 1 : poGDS->bClipWarn = TRUE;
2281 : CPLError( CE_Warning, CPLE_AppDefined,
2282 1 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
2283 : }
2284 : }
2285 :
2286 38770 : if (poGDS->nBitsPerSample == 24)
2287 : {
2288 : /* -------------------------------------------------------------------- */
2289 : /* Special case for 24bit data which is pre-byteswapped since */
2290 : /* the size falls on a byte boundary ... ugg (#2361). */
2291 : /* -------------------------------------------------------------------- */
2292 : #ifdef CPL_MSB
2293 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2294 : (GByte) nInWord;
2295 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2296 : (GByte) (nInWord >> 8);
2297 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2298 : (GByte) (nInWord >> 16);
2299 : #else
2300 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2301 1400 : (GByte) (nInWord >> 16);
2302 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2303 1400 : (GByte) (nInWord >> 8);
2304 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2305 1400 : (GByte) nInWord;
2306 : #endif
2307 1400 : iBitOffset += 24;
2308 : }
2309 : else
2310 : {
2311 485812 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2312 : {
2313 448442 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
2314 18485 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2315 448442 : iBitOffset++;
2316 : }
2317 : }
2318 : }
2319 : }
2320 :
2321 425 : poGDS->bLoadedBlockDirty = TRUE;
2322 :
2323 425 : return eErr;
2324 : }
2325 :
2326 : /* -------------------------------------------------------------------- */
2327 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
2328 : /* -------------------------------------------------------------------- */
2329 :
2330 : /* -------------------------------------------------------------------- */
2331 : /* On write of pixel interleaved data, we might as well flush */
2332 : /* out any other bands that are dirty in our cache. This is */
2333 : /* especially helpful when writing compressed blocks. */
2334 : /* -------------------------------------------------------------------- */
2335 : int iBand;
2336 :
2337 54 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
2338 : {
2339 38 : const GByte *pabyThisImage = NULL;
2340 38 : GDALRasterBlock *poBlock = NULL;
2341 38 : int iBit, iPixel, iBitOffset = 0;
2342 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2343 :
2344 38 : if( iBand+1 == nBand )
2345 16 : pabyThisImage = (GByte *) pImage;
2346 : else
2347 : {
2348 : poBlock = ((GTiffOddBitsBand *)poGDS->GetRasterBand( iBand+1 ))
2349 22 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
2350 :
2351 22 : if( poBlock == NULL )
2352 10 : continue;
2353 :
2354 12 : if( !poBlock->GetDirty() )
2355 : {
2356 0 : poBlock->DropLock();
2357 0 : continue;
2358 : }
2359 :
2360 12 : pabyThisImage = (GByte *) poBlock->GetDataRef();
2361 : }
2362 :
2363 28 : iPixelBitSkip = poGDS->nBitsPerSample * poGDS->nBands;
2364 28 : iBandBitOffset = iBand * poGDS->nBitsPerSample;
2365 :
2366 : // bits per line rounds up to next byte boundary.
2367 28 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2368 28 : if( (nBitsPerLine & 7) != 0 )
2369 15 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2370 :
2371 28 : iPixel = 0;
2372 671 : for( iY = 0; iY < nBlockYSize; iY++ )
2373 : {
2374 643 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2375 :
2376 22616 : for( iX = 0; iX < nBlockXSize; iX++ )
2377 : {
2378 21973 : GUInt32 nInWord = 0;
2379 21973 : if( eDataType == GDT_Byte )
2380 4085 : nInWord = ((GByte *) pabyThisImage)[iPixel++];
2381 17888 : else if( eDataType == GDT_UInt16 )
2382 15088 : nInWord = ((GUInt16 *) pabyThisImage)[iPixel++];
2383 2800 : else if( eDataType == GDT_UInt32 )
2384 2800 : nInWord = ((GUInt32 *) pabyThisImage)[iPixel++];
2385 : else
2386 0 : CPLAssert(0);
2387 :
2388 21973 : if (nInWord > nMaxVal)
2389 : {
2390 0 : nInWord = nMaxVal;
2391 0 : if( !poGDS->bClipWarn )
2392 : {
2393 0 : poGDS->bClipWarn = TRUE;
2394 : CPLError( CE_Warning, CPLE_AppDefined,
2395 0 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
2396 : }
2397 : }
2398 :
2399 21973 : if (poGDS->nBitsPerSample == 24)
2400 : {
2401 : /* -------------------------------------------------------------------- */
2402 : /* Special case for 24bit data which is pre-byteswapped since */
2403 : /* the size falls on a byte boundary ... ugg (#2361). */
2404 : /* -------------------------------------------------------------------- */
2405 : #ifdef CPL_MSB
2406 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2407 : (GByte) nInWord;
2408 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2409 : (GByte) (nInWord >> 8);
2410 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2411 : (GByte) (nInWord >> 16);
2412 : #else
2413 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2414 1400 : (GByte) (nInWord >> 16);
2415 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2416 1400 : (GByte) (nInWord >> 8);
2417 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2418 1400 : (GByte) nInWord;
2419 : #endif
2420 1400 : iBitOffset += 24;
2421 : }
2422 : else
2423 : {
2424 248624 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2425 : {
2426 228051 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
2427 101895 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2428 : else
2429 : {
2430 : /* We must explictly unset the bit as we may update an existing block */
2431 126156 : poGDS->pabyBlockBuf[iBitOffset>>3] &= ~(0x80 >>(iBitOffset & 7));
2432 : }
2433 :
2434 228051 : iBitOffset++;
2435 : }
2436 : }
2437 :
2438 21973 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2439 : }
2440 : }
2441 :
2442 28 : if( poBlock != NULL )
2443 : {
2444 12 : poBlock->MarkClean();
2445 12 : poBlock->DropLock();
2446 : }
2447 : }
2448 :
2449 16 : poGDS->bLoadedBlockDirty = TRUE;
2450 :
2451 16 : return CE_None;
2452 : }
2453 :
2454 : /************************************************************************/
2455 : /* IReadBlock() */
2456 : /************************************************************************/
2457 :
2458 814 : CPLErr GTiffOddBitsBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2459 : void * pImage )
2460 :
2461 : {
2462 : int nBlockId;
2463 814 : CPLErr eErr = CE_None;
2464 :
2465 814 : if (!poGDS->SetDirectory())
2466 0 : return CE_Failure;
2467 :
2468 814 : CPLAssert(nBlocksPerRow != 0);
2469 814 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2470 :
2471 814 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
2472 20 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
2473 :
2474 : /* -------------------------------------------------------------------- */
2475 : /* Handle the case of a strip in a writable file that doesn't */
2476 : /* exist yet, but that we want to read. Just set to zeros and */
2477 : /* return. */
2478 : /* -------------------------------------------------------------------- */
2479 814 : if( !poGDS->IsBlockAvailable(nBlockId) )
2480 : {
2481 566 : NullBlock( pImage );
2482 566 : return CE_None;
2483 : }
2484 :
2485 : /* -------------------------------------------------------------------- */
2486 : /* Load the block buffer. */
2487 : /* -------------------------------------------------------------------- */
2488 248 : eErr = poGDS->LoadBlockBuf( nBlockId );
2489 248 : if( eErr != CE_None )
2490 0 : return eErr;
2491 :
2492 414 : if ( poGDS->nBitsPerSample == 1 && (poGDS->nBands == 1 || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) )
2493 : {
2494 : /* -------------------------------------------------------------------- */
2495 : /* Translate 1bit data to eight bit. */
2496 : /* -------------------------------------------------------------------- */
2497 166 : int iDstOffset=0, iLine;
2498 166 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2499 :
2500 17839 : for( iLine = 0; iLine < nBlockYSize; iLine++ )
2501 : {
2502 : int iSrcOffset, iPixel;
2503 :
2504 17673 : iSrcOffset = ((nBlockXSize+7) >> 3) * 8 * iLine;
2505 :
2506 17673 : GByte bSetVal = (poGDS->bPromoteTo8Bits) ? 255 : 1;
2507 :
2508 4724880 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2509 : {
2510 4707207 : if( pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2511 1534422 : ((GByte *) pImage)[iDstOffset++] = bSetVal;
2512 : else
2513 3172785 : ((GByte *) pImage)[iDstOffset++] = 0;
2514 : }
2515 : }
2516 : }
2517 : /* -------------------------------------------------------------------- */
2518 : /* Handle the case of 16- and 24-bit floating point data as per */
2519 : /* TIFF Technical Note 3. */
2520 : /* -------------------------------------------------------------------- */
2521 84 : else if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
2522 : {
2523 : int i, nBlockPixels, nWordBytes, iSkipBytes;
2524 : GByte *pabyImage;
2525 :
2526 2 : nWordBytes = poGDS->nBitsPerSample / 8;
2527 2 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
2528 : iSkipBytes = ( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) ?
2529 2 : nWordBytes : poGDS->nBands * nWordBytes;
2530 :
2531 2 : nBlockPixels = nBlockXSize * nBlockYSize;
2532 2 : if ( poGDS->nBitsPerSample == 16 )
2533 : {
2534 401 : for( i = 0; i < nBlockPixels; i++ )
2535 : {
2536 400 : ((GUInt32 *) pImage)[i] =
2537 400 : HalfToFloat( *((GUInt16 *)pabyImage) );
2538 400 : pabyImage += iSkipBytes;
2539 : }
2540 : }
2541 1 : else if ( poGDS->nBitsPerSample == 24 )
2542 : {
2543 401 : for( i = 0; i < nBlockPixels; i++ )
2544 : {
2545 : #ifdef CPL_MSB
2546 : ((GUInt32 *) pImage)[i] =
2547 : TripleToFloat( ((GUInt32)*(pabyImage + 0) << 16)
2548 : | ((GUInt32)*(pabyImage + 1) << 8)
2549 : | (GUInt32)*(pabyImage + 2) );
2550 : #else
2551 400 : ((GUInt32 *) pImage)[i] =
2552 : TripleToFloat( ((GUInt32)*(pabyImage + 2) << 16)
2553 : | ((GUInt32)*(pabyImage + 1) << 8)
2554 400 : | (GUInt32)*pabyImage );
2555 : #endif
2556 400 : pabyImage += iSkipBytes;
2557 : }
2558 : }
2559 : }
2560 :
2561 : /* -------------------------------------------------------------------- */
2562 : /* Special case for moving 12bit data somewhat more efficiently. */
2563 : /* -------------------------------------------------------------------- */
2564 80 : else if( poGDS->nBitsPerSample == 12 )
2565 : {
2566 20 : int iPixel, iBitOffset = 0;
2567 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2568 :
2569 20 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2570 : {
2571 17 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2572 17 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2573 : }
2574 : else
2575 : {
2576 3 : iPixelBitSkip = poGDS->nBitsPerSample;
2577 3 : iBandBitOffset = 0;
2578 : }
2579 :
2580 : // bits per line rounds up to next byte boundary.
2581 20 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2582 20 : if( (nBitsPerLine & 7) != 0 )
2583 0 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2584 :
2585 20 : iPixel = 0;
2586 904 : for( iY = 0; iY < nBlockYSize; iY++ )
2587 : {
2588 884 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2589 :
2590 65524 : for( iX = 0; iX < nBlockXSize; iX++ )
2591 : {
2592 64640 : int iByte = iBitOffset>>3;
2593 :
2594 64640 : if( (iBitOffset & 0x7) == 0 )
2595 : {
2596 : /* starting on byte boundary */
2597 :
2598 64840 : ((GUInt16 *) pImage)[iPixel++] =
2599 32420 : (poGDS->pabyBlockBuf[iByte] << 4)
2600 32420 : | (poGDS->pabyBlockBuf[iByte+1] >> 4);
2601 : }
2602 : else
2603 : {
2604 : /* starting off byte boundary */
2605 :
2606 64440 : ((GUInt16 *) pImage)[iPixel++] =
2607 32220 : ((poGDS->pabyBlockBuf[iByte] & 0xf) << 8)
2608 32220 : | (poGDS->pabyBlockBuf[iByte+1]);
2609 : }
2610 64640 : iBitOffset += iPixelBitSkip;
2611 : }
2612 : }
2613 : }
2614 :
2615 : /* -------------------------------------------------------------------- */
2616 : /* Special case for 24bit data which is pre-byteswapped since */
2617 : /* the size falls on a byte boundary ... ugg (#2361). */
2618 : /* -------------------------------------------------------------------- */
2619 60 : else if( poGDS->nBitsPerSample == 24 )
2620 : {
2621 : int iPixel;
2622 : int iPixelByteSkip, iBandByteOffset, iX, iY, nBytesPerLine;
2623 :
2624 11 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2625 : {
2626 8 : iPixelByteSkip = (poGDS->nBands * poGDS->nBitsPerSample) / 8;
2627 8 : iBandByteOffset = ((nBand-1) * poGDS->nBitsPerSample) / 8;
2628 : }
2629 : else
2630 : {
2631 3 : iPixelByteSkip = poGDS->nBitsPerSample / 8;
2632 3 : iBandByteOffset = 0;
2633 : }
2634 :
2635 11 : nBytesPerLine = nBlockXSize * iPixelByteSkip;
2636 :
2637 11 : iPixel = 0;
2638 191 : for( iY = 0; iY < nBlockYSize; iY++ )
2639 : {
2640 : GByte *pabyImage =
2641 180 : poGDS->pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
2642 :
2643 3380 : for( iX = 0; iX < nBlockXSize; iX++ )
2644 : {
2645 : #ifdef CPL_MSB
2646 : ((GUInt32 *) pImage)[iPixel++] =
2647 : ((GUInt32)*(pabyImage + 2) << 16)
2648 : | ((GUInt32)*(pabyImage + 1) << 8)
2649 : | (GUInt32)*(pabyImage + 0);
2650 : #else
2651 6400 : ((GUInt32 *) pImage)[iPixel++] =
2652 : ((GUInt32)*(pabyImage + 0) << 16)
2653 : | ((GUInt32)*(pabyImage + 1) << 8)
2654 3200 : | (GUInt32)*(pabyImage + 2);
2655 : #endif
2656 3200 : pabyImage += iPixelByteSkip;
2657 : }
2658 : }
2659 : }
2660 :
2661 : /* -------------------------------------------------------------------- */
2662 : /* Handle 1-32 bit integer data. */
2663 : /* -------------------------------------------------------------------- */
2664 : else
2665 : {
2666 49 : int iBit, iPixel, iBitOffset = 0;
2667 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2668 :
2669 49 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2670 : {
2671 43 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2672 43 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2673 : }
2674 : else
2675 : {
2676 6 : iPixelBitSkip = poGDS->nBitsPerSample;
2677 6 : iBandBitOffset = 0;
2678 : }
2679 :
2680 : // bits per line rounds up to next byte boundary.
2681 49 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2682 49 : if( (nBitsPerLine & 7) != 0 )
2683 48 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2684 :
2685 49 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2686 49 : iPixel = 0;
2687 :
2688 2285 : for( iY = 0; iY < nBlockYSize; iY++ )
2689 : {
2690 2236 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2691 :
2692 180540 : for( iX = 0; iX < nBlockXSize; iX++ )
2693 : {
2694 178304 : int nOutWord = 0;
2695 :
2696 452342 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2697 : {
2698 274038 : if( pabyBlockBuf[iBitOffset>>3]
2699 : & (0x80 >>(iBitOffset & 7)) )
2700 137696 : nOutWord |= (1 << (poGDS->nBitsPerSample - 1 - iBit));
2701 274038 : iBitOffset++;
2702 : }
2703 :
2704 178304 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2705 :
2706 178304 : if( eDataType == GDT_Byte )
2707 172302 : ((GByte *) pImage)[iPixel++] = (GByte) nOutWord;
2708 6002 : else if( eDataType == GDT_UInt16 )
2709 3201 : ((GUInt16 *) pImage)[iPixel++] = (GUInt16) nOutWord;
2710 2801 : else if( eDataType == GDT_UInt32 )
2711 2801 : ((GUInt32 *) pImage)[iPixel++] = nOutWord;
2712 : else
2713 0 : CPLAssert(0);
2714 : }
2715 : }
2716 : }
2717 :
2718 248 : return CE_None;
2719 : }
2720 :
2721 :
2722 : /************************************************************************/
2723 : /* ==================================================================== */
2724 : /* GTiffBitmapBand */
2725 : /* ==================================================================== */
2726 : /************************************************************************/
2727 :
2728 : class GTiffBitmapBand : public GTiffOddBitsBand
2729 : {
2730 : friend class GTiffDataset;
2731 :
2732 : GDALColorTable *poColorTable;
2733 :
2734 : public:
2735 :
2736 : GTiffBitmapBand( GTiffDataset *, int );
2737 : virtual ~GTiffBitmapBand();
2738 :
2739 : virtual GDALColorInterp GetColorInterpretation();
2740 : virtual GDALColorTable *GetColorTable();
2741 : };
2742 :
2743 :
2744 : /************************************************************************/
2745 : /* GTiffBitmapBand() */
2746 : /************************************************************************/
2747 :
2748 128 : GTiffBitmapBand::GTiffBitmapBand( GTiffDataset *poDS, int nBand )
2749 128 : : GTiffOddBitsBand( poDS, nBand )
2750 :
2751 : {
2752 128 : eDataType = GDT_Byte;
2753 :
2754 128 : if( poDS->poColorTable != NULL )
2755 17 : poColorTable = poDS->poColorTable->Clone();
2756 : else
2757 : {
2758 : #ifdef ESRI_BUILD
2759 : poColorTable = NULL;
2760 : #else
2761 : GDALColorEntry oWhite, oBlack;
2762 :
2763 111 : oWhite.c1 = 255;
2764 111 : oWhite.c2 = 255;
2765 111 : oWhite.c3 = 255;
2766 111 : oWhite.c4 = 255;
2767 :
2768 111 : oBlack.c1 = 0;
2769 111 : oBlack.c2 = 0;
2770 111 : oBlack.c3 = 0;
2771 111 : oBlack.c4 = 255;
2772 :
2773 111 : poColorTable = new GDALColorTable();
2774 :
2775 111 : if( poDS->nPhotometric == PHOTOMETRIC_MINISWHITE )
2776 : {
2777 0 : poColorTable->SetColorEntry( 0, &oWhite );
2778 0 : poColorTable->SetColorEntry( 1, &oBlack );
2779 : }
2780 : else
2781 : {
2782 111 : poColorTable->SetColorEntry( 0, &oBlack );
2783 111 : poColorTable->SetColorEntry( 1, &oWhite );
2784 : }
2785 : #endif /* not defined ESRI_BUILD */
2786 : }
2787 128 : }
2788 :
2789 : /************************************************************************/
2790 : /* ~GTiffBitmapBand() */
2791 : /************************************************************************/
2792 :
2793 128 : GTiffBitmapBand::~GTiffBitmapBand()
2794 :
2795 : {
2796 128 : delete poColorTable;
2797 128 : }
2798 :
2799 : /************************************************************************/
2800 : /* GetColorInterpretation() */
2801 : /************************************************************************/
2802 :
2803 21 : GDALColorInterp GTiffBitmapBand::GetColorInterpretation()
2804 :
2805 : {
2806 21 : if (poGDS->bPromoteTo8Bits)
2807 13 : return GCI_Undefined;
2808 : else
2809 8 : return GCI_PaletteIndex;
2810 : }
2811 :
2812 : /************************************************************************/
2813 : /* GetColorTable() */
2814 : /************************************************************************/
2815 :
2816 12 : GDALColorTable *GTiffBitmapBand::GetColorTable()
2817 :
2818 : {
2819 12 : if (poGDS->bPromoteTo8Bits)
2820 0 : return NULL;
2821 : else
2822 12 : return poColorTable;
2823 : }
2824 :
2825 : /************************************************************************/
2826 : /* ==================================================================== */
2827 : /* GTiffSplitBitmapBand */
2828 : /* ==================================================================== */
2829 : /************************************************************************/
2830 :
2831 : class GTiffSplitBitmapBand : public GTiffBitmapBand
2832 : {
2833 : friend class GTiffDataset;
2834 :
2835 : public:
2836 :
2837 : GTiffSplitBitmapBand( GTiffDataset *, int );
2838 : virtual ~GTiffSplitBitmapBand();
2839 :
2840 : virtual CPLErr IReadBlock( int, int, void * );
2841 : virtual CPLErr IWriteBlock( int, int, void * );
2842 : };
2843 :
2844 :
2845 : /************************************************************************/
2846 : /* GTiffSplitBitmapBand() */
2847 : /************************************************************************/
2848 :
2849 4 : GTiffSplitBitmapBand::GTiffSplitBitmapBand( GTiffDataset *poDS, int nBand )
2850 4 : : GTiffBitmapBand( poDS, nBand )
2851 :
2852 : {
2853 4 : nBlockXSize = poDS->GetRasterXSize();
2854 4 : nBlockYSize = 1;
2855 4 : }
2856 :
2857 : /************************************************************************/
2858 : /* ~GTiffSplitBitmapBand() */
2859 : /************************************************************************/
2860 :
2861 4 : GTiffSplitBitmapBand::~GTiffSplitBitmapBand()
2862 :
2863 : {
2864 4 : }
2865 :
2866 :
2867 : /************************************************************************/
2868 : /* IReadBlock() */
2869 : /************************************************************************/
2870 :
2871 21600 : CPLErr GTiffSplitBitmapBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2872 : void * pImage )
2873 :
2874 : {
2875 : (void) nBlockXOff;
2876 :
2877 21600 : if (!poGDS->SetDirectory())
2878 0 : return CE_Failure;
2879 :
2880 21600 : if (poGDS->pabyBlockBuf == NULL)
2881 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
2882 :
2883 : /* -------------------------------------------------------------------- */
2884 : /* Read through to target scanline. */
2885 : /* -------------------------------------------------------------------- */
2886 21600 : if( poGDS->nLastLineRead >= nBlockYOff )
2887 0 : poGDS->nLastLineRead = -1;
2888 :
2889 64800 : while( poGDS->nLastLineRead < nBlockYOff )
2890 : {
2891 21600 : if( TIFFReadScanline( poGDS->hTIFF, poGDS->pabyBlockBuf, ++poGDS->nLastLineRead, 0 ) == -1
2892 : && !poGDS->bIgnoreReadErrors )
2893 : {
2894 : CPLError( CE_Failure, CPLE_AppDefined,
2895 0 : "TIFFReadScanline() failed." );
2896 0 : return CE_Failure;
2897 : }
2898 : }
2899 :
2900 : /* -------------------------------------------------------------------- */
2901 : /* Translate 1bit data to eight bit. */
2902 : /* -------------------------------------------------------------------- */
2903 21600 : int iPixel, iSrcOffset=0, iDstOffset=0;
2904 :
2905 21621600 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2906 : {
2907 21600000 : if( poGDS->pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2908 21243630 : ((GByte *) pImage)[iDstOffset++] = 1;
2909 : else
2910 356370 : ((GByte *) pImage)[iDstOffset++] = 0;
2911 : }
2912 :
2913 21600 : return CE_None;
2914 : }
2915 :
2916 : /************************************************************************/
2917 : /* IWriteBlock() */
2918 : /************************************************************************/
2919 :
2920 0 : CPLErr GTiffSplitBitmapBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2921 : void * pImage )
2922 :
2923 : {
2924 : (void) nBlockXOff;
2925 : (void) nBlockYOff;
2926 : (void) pImage;
2927 :
2928 : CPLError( CE_Failure, CPLE_AppDefined,
2929 0 : "Split bitmap bands are read-only." );
2930 0 : return CE_Failure;
2931 : }
2932 :
2933 : /************************************************************************/
2934 : /* ==================================================================== */
2935 : /* GTiffDataset */
2936 : /* ==================================================================== */
2937 : /************************************************************************/
2938 :
2939 :
2940 : /************************************************************************/
2941 : /* GTiffDataset() */
2942 : /************************************************************************/
2943 :
2944 5021 : GTiffDataset::GTiffDataset()
2945 :
2946 : {
2947 5021 : nLoadedBlock = -1;
2948 5021 : bLoadedBlockDirty = FALSE;
2949 5021 : pabyBlockBuf = NULL;
2950 5021 : bWriteErrorInFlushBlockBuf = FALSE;
2951 5021 : hTIFF = NULL;
2952 5021 : bNeedsRewrite = FALSE;
2953 5021 : bMetadataChanged = FALSE;
2954 5021 : bGeoTIFFInfoChanged = FALSE;
2955 5021 : bCrystalized = TRUE;
2956 5021 : poColorTable = NULL;
2957 5021 : bNoDataSet = FALSE;
2958 5021 : dfNoDataValue = -9999.0;
2959 5021 : pszProjection = CPLStrdup("");
2960 5021 : bLookedForProjection = FALSE;
2961 5021 : bBase = TRUE;
2962 5021 : bCloseTIFFHandle = FALSE;
2963 5021 : bTreatAsRGBA = FALSE;
2964 5021 : nOverviewCount = 0;
2965 5021 : papoOverviewDS = NULL;
2966 5021 : nDirOffset = 0;
2967 5021 : poActiveDS = NULL;
2968 5021 : ppoActiveDSRef = NULL;
2969 :
2970 5021 : bGeoTransformValid = FALSE;
2971 5021 : adfGeoTransform[0] = 0.0;
2972 5021 : adfGeoTransform[1] = 1.0;
2973 5021 : adfGeoTransform[2] = 0.0;
2974 5021 : adfGeoTransform[3] = 0.0;
2975 5021 : adfGeoTransform[4] = 0.0;
2976 5021 : adfGeoTransform[5] = 1.0;
2977 :
2978 5021 : nGCPCount = 0;
2979 5021 : pasGCPList = NULL;
2980 :
2981 5021 : osProfile = "GDALGeoTIFF";
2982 :
2983 5021 : papszCreationOptions = NULL;
2984 :
2985 5021 : nTempWriteBufferSize = 0;
2986 5021 : pabyTempWriteBuffer = NULL;
2987 :
2988 5021 : poMaskDS = NULL;
2989 5021 : poBaseDS = NULL;
2990 :
2991 5021 : bFillEmptyTiles = FALSE;
2992 5021 : bLoadingOtherBands = FALSE;
2993 5021 : nLastLineRead = -1;
2994 5021 : nLastBandRead = -1;
2995 5021 : bTreatAsSplit = FALSE;
2996 5021 : bTreatAsSplitBitmap = FALSE;
2997 5021 : bClipWarn = FALSE;
2998 5021 : bHasWarnedDisableAggressiveBandCaching = FALSE;
2999 5021 : bDontReloadFirstBlock = FALSE;
3000 :
3001 5021 : nZLevel = -1;
3002 5021 : nLZMAPreset = -1;
3003 5021 : nJpegQuality = -1;
3004 :
3005 5021 : bPromoteTo8Bits = FALSE;
3006 :
3007 5021 : bDebugDontWriteBlocks = CSLTestBoolean(CPLGetConfigOption("GTIFF_DONT_WRITE_BLOCKS", "NO"));
3008 :
3009 5021 : bIsFinalized = FALSE;
3010 5021 : bIgnoreReadErrors = CSLTestBoolean(CPLGetConfigOption("GTIFF_IGNORE_READ_ERRORS", "NO"));
3011 :
3012 5021 : bHasSearchedRPC = FALSE;
3013 5021 : bHasSearchedIMD = FALSE;
3014 :
3015 5021 : bScanDeferred = TRUE;
3016 :
3017 5021 : bDirectIO = CSLTestBoolean(CPLGetConfigOption("GTIFF_DIRECT_IO", "NO"));
3018 5021 : }
3019 :
3020 : /************************************************************************/
3021 : /* ~GTiffDataset() */
3022 : /************************************************************************/
3023 :
3024 5021 : GTiffDataset::~GTiffDataset()
3025 :
3026 : {
3027 5021 : Finalize();
3028 5021 : }
3029 :
3030 : /************************************************************************/
3031 : /* Finalize() */
3032 : /************************************************************************/
3033 :
3034 5022 : int GTiffDataset::Finalize()
3035 : {
3036 5022 : if (bIsFinalized)
3037 1 : return FALSE;
3038 :
3039 5021 : int bHasDroppedRef = FALSE;
3040 :
3041 5021 : Crystalize();
3042 :
3043 : /* -------------------------------------------------------------------- */
3044 : /* Handle forcing xml:ESRI data to be written to PAM. */
3045 : /* -------------------------------------------------------------------- */
3046 5021 : if( CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
3047 : {
3048 7 : char **papszESRIMD = GetMetadata("xml:ESRI");
3049 7 : if( papszESRIMD )
3050 : {
3051 5 : GDALPamDataset::SetMetadata( papszESRIMD, "xml:ESRI");
3052 : }
3053 : }
3054 :
3055 : /* -------------------------------------------------------------------- */
3056 : /* Ensure any blocks write cached by GDAL gets pushed through libtiff.*/
3057 : /* -------------------------------------------------------------------- */
3058 5021 : GDALPamDataset::FlushCache();
3059 :
3060 : /* -------------------------------------------------------------------- */
3061 : /* Fill in missing blocks with empty data. */
3062 : /* -------------------------------------------------------------------- */
3063 5021 : if( bFillEmptyTiles )
3064 : {
3065 926 : FillEmptyTiles();
3066 926 : bFillEmptyTiles = FALSE;
3067 : }
3068 :
3069 : /* -------------------------------------------------------------------- */
3070 : /* Force a complete flush, including either rewriting(moving) */
3071 : /* of writing in place the current directory. */
3072 : /* -------------------------------------------------------------------- */
3073 5021 : FlushCache();
3074 :
3075 : /* -------------------------------------------------------------------- */
3076 : /* If there is still changed metadata, then presumably we want */
3077 : /* to push it into PAM. */
3078 : /* -------------------------------------------------------------------- */
3079 5021 : if( bMetadataChanged )
3080 : {
3081 30 : PushMetadataToPam();
3082 30 : bMetadataChanged = FALSE;
3083 30 : GDALPamDataset::FlushCache();
3084 : }
3085 :
3086 : /* -------------------------------------------------------------------- */
3087 : /* Cleanup overviews. */
3088 : /* -------------------------------------------------------------------- */
3089 5021 : if( bBase )
3090 : {
3091 4905 : for( int i = 0; i < nOverviewCount; i++ )
3092 : {
3093 253 : delete papoOverviewDS[i];
3094 253 : bHasDroppedRef = TRUE;
3095 : }
3096 4652 : nOverviewCount = 0;
3097 : }
3098 :
3099 : /* If we are a mask dataset, we can have overviews, but we don't */
3100 : /* own them. We can only free the array, not the overviews themselves */
3101 5021 : CPLFree( papoOverviewDS );
3102 5021 : papoOverviewDS = NULL;
3103 :
3104 : /* poMaskDS is owned by the main image and the overviews */
3105 : /* so because of the latter case, we can delete it even if */
3106 : /* we are not the base image */
3107 5021 : if (poMaskDS)
3108 : {
3109 108 : delete poMaskDS;
3110 108 : poMaskDS = NULL;
3111 108 : bHasDroppedRef = TRUE;
3112 : }
3113 :
3114 5021 : if( poColorTable != NULL )
3115 98 : delete poColorTable;
3116 5021 : poColorTable = NULL;
3117 :
3118 5021 : if( bBase || bCloseTIFFHandle )
3119 : {
3120 4658 : XTIFFClose( hTIFF );
3121 4658 : hTIFF = NULL;
3122 : }
3123 :
3124 5021 : if( nGCPCount > 0 )
3125 : {
3126 29 : GDALDeinitGCPs( nGCPCount, pasGCPList );
3127 29 : CPLFree( pasGCPList );
3128 29 : pasGCPList = NULL;
3129 29 : nGCPCount = 0;
3130 : }
3131 :
3132 5021 : CPLFree( pszProjection );
3133 5021 : pszProjection = NULL;
3134 :
3135 5021 : CSLDestroy( papszCreationOptions );
3136 5021 : papszCreationOptions = NULL;
3137 :
3138 5021 : CPLFree(pabyTempWriteBuffer);
3139 5021 : pabyTempWriteBuffer = NULL;
3140 :
3141 5021 : if( *ppoActiveDSRef == this )
3142 4758 : *ppoActiveDSRef = NULL;
3143 5021 : ppoActiveDSRef = NULL;
3144 :
3145 5021 : bIsFinalized = TRUE;
3146 :
3147 5021 : return bHasDroppedRef;
3148 : }
3149 :
3150 : /************************************************************************/
3151 : /* CloseDependentDatasets() */
3152 : /************************************************************************/
3153 :
3154 1 : int GTiffDataset::CloseDependentDatasets()
3155 : {
3156 1 : if (!bBase)
3157 0 : return FALSE;
3158 :
3159 1 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
3160 :
3161 1 : bHasDroppedRef |= Finalize();
3162 :
3163 1 : return bHasDroppedRef;
3164 : }
3165 :
3166 : /************************************************************************/
3167 : /* FillEmptyTiles() */
3168 : /************************************************************************/
3169 :
3170 926 : void GTiffDataset::FillEmptyTiles()
3171 :
3172 : {
3173 926 : toff_t *panByteCounts = NULL;
3174 : int nBlockCount, iBlock;
3175 :
3176 926 : if (!SetDirectory())
3177 0 : return;
3178 :
3179 : /* -------------------------------------------------------------------- */
3180 : /* How many blocks are there in this file? */
3181 : /* -------------------------------------------------------------------- */
3182 926 : if( nPlanarConfig == PLANARCONFIG_SEPARATE )
3183 7 : nBlockCount = nBlocksPerBand * nBands;
3184 : else
3185 919 : nBlockCount = nBlocksPerBand;
3186 :
3187 : /* -------------------------------------------------------------------- */
3188 : /* Fetch block maps. */
3189 : /* -------------------------------------------------------------------- */
3190 926 : if( TIFFIsTiled( hTIFF ) )
3191 18 : TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts );
3192 : else
3193 908 : TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
3194 :
3195 926 : if (panByteCounts == NULL)
3196 : {
3197 : /* Got here with libtiff 3.9.3 and tiff_write_8 test */
3198 0 : CPLError(CE_Failure, CPLE_AppDefined, "FillEmptyTiles() failed because panByteCounts == NULL");
3199 0 : return;
3200 : }
3201 :
3202 : /* -------------------------------------------------------------------- */
3203 : /* Prepare a blank data buffer to write for uninitialized blocks. */
3204 : /* -------------------------------------------------------------------- */
3205 : int nBlockBytes;
3206 :
3207 926 : if( TIFFIsTiled( hTIFF ) )
3208 18 : nBlockBytes = TIFFTileSize(hTIFF);
3209 : else
3210 908 : nBlockBytes = TIFFStripSize(hTIFF);
3211 :
3212 926 : GByte *pabyData = (GByte *) VSICalloc(nBlockBytes,1);
3213 926 : if (pabyData == NULL)
3214 : {
3215 : CPLError(CE_Failure, CPLE_OutOfMemory,
3216 0 : "Cannot allocate %d bytes", nBlockBytes);
3217 0 : return;
3218 : }
3219 :
3220 : /* -------------------------------------------------------------------- */
3221 : /* Check all blocks, writing out data for uninitialized blocks. */
3222 : /* -------------------------------------------------------------------- */
3223 98831 : for( iBlock = 0; iBlock < nBlockCount; iBlock++ )
3224 : {
3225 97905 : if( panByteCounts[iBlock] == 0 )
3226 : {
3227 86823 : if( WriteEncodedTileOrStrip( iBlock, pabyData, FALSE ) != CE_None )
3228 0 : break;
3229 : }
3230 : }
3231 :
3232 926 : CPLFree( pabyData );
3233 : }
3234 :
3235 : /************************************************************************/
3236 : /* WriteEncodedTile() */
3237 : /************************************************************************/
3238 :
3239 9670 : int GTiffDataset::WriteEncodedTile(uint32 tile, GByte *pabyData,
3240 : int bPreserveDataBuffer)
3241 : {
3242 9670 : int cc = TIFFTileSize( hTIFF );
3243 9670 : int bNeedTileFill = FALSE;
3244 9670 : int iRow=0, iColumn=0;
3245 9670 : int nBlocksPerRow=1, nBlocksPerColumn=1;
3246 :
3247 : /*
3248 : ** Do we need to spread edge values right or down for a partial
3249 : ** JPEG encoded tile? We do this to avoid edge artifacts.
3250 : */
3251 9670 : if( nCompression == COMPRESSION_JPEG )
3252 : {
3253 350 : nBlocksPerRow = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
3254 350 : nBlocksPerColumn = (nRasterYSize + nBlockYSize - 1) / nBlockYSize;
3255 :
3256 350 : iColumn = (tile % nBlocksPerBand) % nBlocksPerRow;
3257 350 : iRow = (tile % nBlocksPerBand) / nBlocksPerRow;
3258 :
3259 : // Is this a partial right edge tile?
3260 350 : if( iRow == nBlocksPerRow - 1
3261 : && nRasterXSize % nBlockXSize != 0 )
3262 27 : bNeedTileFill = TRUE;
3263 :
3264 : // Is this a partial bottom edge tile?
3265 350 : if( iColumn == nBlocksPerColumn - 1
3266 : && nRasterYSize % nBlockYSize != 0 )
3267 37 : bNeedTileFill = TRUE;
3268 : }
3269 :
3270 : /*
3271 : ** If we need to fill out the tile, or if we want to prevent
3272 : ** TIFFWriteEncodedTile from altering the buffer as part of
3273 : ** byte swapping the data on write then we will need a temporary
3274 : ** working buffer. If not, we can just do a direct write.
3275 : */
3276 9670 : if (bPreserveDataBuffer
3277 : && (TIFFIsByteSwapped(hTIFF) || bNeedTileFill) )
3278 : {
3279 76 : if (cc != nTempWriteBufferSize)
3280 : {
3281 29 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
3282 29 : nTempWriteBufferSize = cc;
3283 : }
3284 76 : memcpy(pabyTempWriteBuffer, pabyData, cc);
3285 :
3286 76 : pabyData = (GByte *) pabyTempWriteBuffer;
3287 : }
3288 :
3289 : /*
3290 : ** Perform tile fill if needed.
3291 : */
3292 9670 : if( bNeedTileFill )
3293 : {
3294 37 : int nRightPixelsToFill = 0;
3295 37 : int nBottomPixelsToFill = 0;
3296 37 : int nPixelSize = cc / (nBlockXSize * nBlockYSize);
3297 : unsigned int iX, iY, iSrcX, iSrcY;
3298 :
3299 37 : CPLDebug( "GTiff", "Filling out jpeg edge tile on write." );
3300 :
3301 37 : if( iColumn == nBlocksPerRow - 1 )
3302 27 : nRightPixelsToFill = nBlockXSize * (iColumn+1) - nRasterXSize;
3303 37 : if( iRow == nBlocksPerColumn - 1 )
3304 29 : nBottomPixelsToFill = nBlockYSize * (iRow+1) - nRasterYSize;
3305 :
3306 : // Fill out to the right.
3307 37 : iSrcX = nBlockXSize - nRightPixelsToFill - 1;
3308 :
3309 2033 : for( iX = iSrcX+1; iX < nBlockXSize; iX++ )
3310 : {
3311 257484 : for( iY = 0; iY < nBlockYSize; iY++ )
3312 : {
3313 : memcpy( pabyData + (nBlockXSize * iY + iX) * nPixelSize,
3314 : pabyData + (nBlockXSize * iY + iSrcX) * nPixelSize,
3315 255488 : nPixelSize );
3316 : }
3317 : }
3318 :
3319 : // now fill out the bottom.
3320 37 : iSrcY = nBlockYSize - nBottomPixelsToFill - 1;
3321 2173 : for( iY = iSrcY+1; iY < nBlockYSize; iY++ )
3322 : {
3323 : memcpy( pabyData + nBlockXSize * nPixelSize * iY,
3324 : pabyData + nBlockXSize * nPixelSize * iSrcY,
3325 2136 : nPixelSize * nBlockXSize );
3326 : }
3327 : }
3328 :
3329 9670 : return TIFFWriteEncodedTile(hTIFF, tile, pabyData, cc);
3330 : }
3331 :
3332 : /************************************************************************/
3333 : /* WriteEncodedStrip() */
3334 : /************************************************************************/
3335 :
3336 94762 : int GTiffDataset::WriteEncodedStrip(uint32 strip, GByte* pabyData,
3337 : int bPreserveDataBuffer)
3338 : {
3339 94762 : int cc = TIFFStripSize( hTIFF );
3340 :
3341 : /* -------------------------------------------------------------------- */
3342 : /* If this is the last strip in the image, and is partial, then */
3343 : /* we need to trim the number of scanlines written to the */
3344 : /* amount of valid data we have. (#2748) */
3345 : /* -------------------------------------------------------------------- */
3346 94762 : int nStripWithinBand = strip % nBlocksPerBand;
3347 :
3348 94762 : if( (int) ((nStripWithinBand+1) * nRowsPerStrip) > GetRasterYSize() )
3349 : {
3350 : cc = (cc / nRowsPerStrip)
3351 159 : * (GetRasterYSize() - nStripWithinBand * nRowsPerStrip);
3352 : CPLDebug( "GTiff", "Adjusted bytes to write from %d to %d.",
3353 159 : (int) TIFFStripSize(hTIFF), cc );
3354 : }
3355 :
3356 : /* -------------------------------------------------------------------- */
3357 : /* TIFFWriteEncodedStrip can alter the passed buffer if */
3358 : /* byte-swapping is necessary so we use a temporary buffer */
3359 : /* before calling it. */
3360 : /* -------------------------------------------------------------------- */
3361 94762 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
3362 : {
3363 28 : if (cc != nTempWriteBufferSize)
3364 : {
3365 22 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
3366 22 : nTempWriteBufferSize = cc;
3367 : }
3368 28 : memcpy(pabyTempWriteBuffer, pabyData, cc);
3369 28 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyTempWriteBuffer, cc);
3370 : }
3371 : else
3372 94734 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyData, cc);
3373 : }
3374 :
3375 : /************************************************************************/
3376 : /* WriteEncodedTileOrStrip() */
3377 : /************************************************************************/
3378 :
3379 104432 : CPLErr GTiffDataset::WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data,
3380 : int bPreserveDataBuffer)
3381 : {
3382 104432 : CPLErr eErr = CE_None;
3383 :
3384 104432 : if( TIFFIsTiled( hTIFF ) )
3385 : {
3386 9670 : if( WriteEncodedTile(tile_or_strip, (GByte*) data,
3387 : bPreserveDataBuffer) == -1 )
3388 : {
3389 0 : eErr = CE_Failure;
3390 : }
3391 : }
3392 : else
3393 : {
3394 94762 : if( WriteEncodedStrip(tile_or_strip, (GByte *) data,
3395 : bPreserveDataBuffer) == -1 )
3396 : {
3397 0 : eErr = CE_Failure;
3398 : }
3399 : }
3400 :
3401 104432 : return eErr;
3402 : }
3403 :
3404 : /************************************************************************/
3405 : /* FlushBlockBuf() */
3406 : /************************************************************************/
3407 :
3408 221430 : CPLErr GTiffDataset::FlushBlockBuf()
3409 :
3410 : {
3411 221430 : CPLErr eErr = CE_None;
3412 :
3413 221430 : if( nLoadedBlock < 0 || !bLoadedBlockDirty )
3414 218875 : return CE_None;
3415 :
3416 2555 : bLoadedBlockDirty = FALSE;
3417 :
3418 2555 : if (!SetDirectory())
3419 0 : return CE_Failure;
3420 :
3421 2555 : eErr = WriteEncodedTileOrStrip(nLoadedBlock, pabyBlockBuf, TRUE);
3422 2555 : if (eErr != CE_None)
3423 : {
3424 : CPLError( CE_Failure, CPLE_AppDefined,
3425 0 : "WriteEncodedTile/Strip() failed." );
3426 0 : bWriteErrorInFlushBlockBuf = TRUE;
3427 : }
3428 :
3429 2555 : return eErr;
3430 : }
3431 :
3432 : /************************************************************************/
3433 : /* LoadBlockBuf() */
3434 : /* */
3435 : /* Load working block buffer with request block (tile/strip). */
3436 : /************************************************************************/
3437 :
3438 74417 : CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
3439 :
3440 : {
3441 : int nBlockBufSize;
3442 74417 : CPLErr eErr = CE_None;
3443 :
3444 74417 : if( nLoadedBlock == nBlockId )
3445 69792 : return CE_None;
3446 :
3447 : /* -------------------------------------------------------------------- */
3448 : /* If we have a dirty loaded block, flush it out first. */
3449 : /* -------------------------------------------------------------------- */
3450 4625 : if( nLoadedBlock != -1 && bLoadedBlockDirty )
3451 : {
3452 0 : eErr = FlushBlockBuf();
3453 0 : if( eErr != CE_None )
3454 0 : return eErr;
3455 : }
3456 :
3457 : /* -------------------------------------------------------------------- */
3458 : /* Get block size. */
3459 : /* -------------------------------------------------------------------- */
3460 4625 : if( TIFFIsTiled(hTIFF) )
3461 844 : nBlockBufSize = TIFFTileSize( hTIFF );
3462 : else
3463 3781 : nBlockBufSize = TIFFStripSize( hTIFF );
3464 :
3465 4625 : if ( !nBlockBufSize )
3466 : {
3467 : CPLError( CE_Failure, CPLE_AppDefined,
3468 0 : "Bogus block size; unable to allocate a buffer.");
3469 0 : return CE_Failure;
3470 : }
3471 :
3472 : /* -------------------------------------------------------------------- */
3473 : /* Allocate a temporary buffer for this strip. */
3474 : /* -------------------------------------------------------------------- */
3475 4625 : if( pabyBlockBuf == NULL )
3476 : {
3477 499 : pabyBlockBuf = (GByte *) VSICalloc( 1, nBlockBufSize );
3478 499 : if( pabyBlockBuf == NULL )
3479 : {
3480 : CPLError( CE_Failure, CPLE_OutOfMemory,
3481 : "Unable to allocate %d bytes for a temporary strip "
3482 : "buffer in GTIFF driver.",
3483 0 : nBlockBufSize );
3484 :
3485 0 : return( CE_Failure );
3486 : }
3487 : }
3488 :
3489 : /* -------------------------------------------------------------------- */
3490 : /* When called from ::IWriteBlock in separate cases (or in single band */
3491 : /* geotiffs), the ::IWriteBlock will override the content of the buffer*/
3492 : /* with pImage, so we don't need to read data from disk */
3493 : /* -------------------------------------------------------------------- */
3494 4625 : if( !bReadFromDisk )
3495 : {
3496 419 : nLoadedBlock = nBlockId;
3497 419 : return CE_None;
3498 : }
3499 :
3500 : /* libtiff 3.X doesn't like mixing read&write of JPEG compressed blocks */
3501 : /* The below hack is necessary due to another hack that consist in */
3502 : /* writing zero block to force creation of JPEG tables */
3503 4206 : if( nBlockId == 0 && bDontReloadFirstBlock )
3504 : {
3505 0 : bDontReloadFirstBlock = FALSE;
3506 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3507 0 : nLoadedBlock = nBlockId;
3508 0 : return CE_None;
3509 : }
3510 :
3511 : /* -------------------------------------------------------------------- */
3512 : /* The bottom most partial tiles and strips are sometimes only */
3513 : /* partially encoded. This code reduces the requested data so */
3514 : /* an error won't be reported in this case. (#1179) */
3515 : /* -------------------------------------------------------------------- */
3516 4206 : int nBlockReqSize = nBlockBufSize;
3517 4206 : int nBlocksPerRow = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
3518 4206 : int nBlockYOff = (nBlockId % nBlocksPerBand) / nBlocksPerRow;
3519 :
3520 4206 : if( (int)((nBlockYOff+1) * nBlockYSize) > nRasterYSize )
3521 : {
3522 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
3523 213 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
3524 213 : memset( pabyBlockBuf, 0, nBlockBufSize );
3525 : }
3526 :
3527 : /* -------------------------------------------------------------------- */
3528 : /* If we don't have this block already loaded, and we know it */
3529 : /* doesn't yet exist on disk, just zero the memory buffer and */
3530 : /* pretend we loaded it. */
3531 : /* -------------------------------------------------------------------- */
3532 4206 : if( !IsBlockAvailable( nBlockId ) )
3533 : {
3534 2069 : memset( pabyBlockBuf, 0, nBlockBufSize );
3535 2069 : nLoadedBlock = nBlockId;
3536 2069 : return CE_None;
3537 : }
3538 :
3539 : /* -------------------------------------------------------------------- */
3540 : /* Load the block, if it isn't our current block. */
3541 : /* -------------------------------------------------------------------- */
3542 2137 : if( TIFFIsTiled( hTIFF ) )
3543 : {
3544 347 : if( TIFFReadEncodedTile(hTIFF, nBlockId, pabyBlockBuf,
3545 : nBlockReqSize) == -1
3546 : && !bIgnoreReadErrors )
3547 : {
3548 : /* Once TIFFError() is properly hooked, this can go away */
3549 : CPLError( CE_Failure, CPLE_AppDefined,
3550 0 : "TIFFReadEncodedTile() failed." );
3551 :
3552 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3553 :
3554 0 : eErr = CE_Failure;
3555 : }
3556 : }
3557 : else
3558 : {
3559 1790 : if( TIFFReadEncodedStrip(hTIFF, nBlockId, pabyBlockBuf,
3560 : nBlockReqSize) == -1
3561 : && !bIgnoreReadErrors )
3562 : {
3563 : /* Once TIFFError() is properly hooked, this can go away */
3564 : CPLError( CE_Failure, CPLE_AppDefined,
3565 0 : "TIFFReadEncodedStrip() failed." );
3566 :
3567 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3568 :
3569 0 : eErr = CE_Failure;
3570 : }
3571 : }
3572 :
3573 2137 : nLoadedBlock = nBlockId;
3574 2137 : bLoadedBlockDirty = FALSE;
3575 :
3576 2137 : return eErr;
3577 : }
3578 :
3579 :
3580 : /************************************************************************/
3581 : /* Crystalize() */
3582 : /* */
3583 : /* Make sure that the directory information is written out for */
3584 : /* a new file, require before writing any imagery data. */
3585 : /************************************************************************/
3586 :
3587 226308 : void GTiffDataset::Crystalize()
3588 :
3589 : {
3590 226308 : if( !bCrystalized )
3591 : {
3592 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
3593 944 : papszCreationOptions );
3594 944 : WriteGeoTIFFInfo();
3595 :
3596 944 : bMetadataChanged = FALSE;
3597 944 : bGeoTIFFInfoChanged = FALSE;
3598 944 : bNeedsRewrite = FALSE;
3599 :
3600 944 : bCrystalized = TRUE;
3601 :
3602 944 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffDataset::Crystalize");
3603 :
3604 : // Keep zip and tiff quality, and jpegcolormode which get reset when we call
3605 : // TIFFWriteDirectory
3606 944 : int jquality = -1, zquality = -1, nColorMode = -1;
3607 944 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
3608 944 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
3609 944 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
3610 :
3611 944 : TIFFWriteDirectory( hTIFF );
3612 944 : TIFFSetDirectory( hTIFF, 0 );
3613 :
3614 :
3615 : // Now, reset zip and tiff quality and jpegcolormode.
3616 944 : if(jquality > 0)
3617 14 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
3618 944 : if(zquality > 0)
3619 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
3620 944 : if (nColorMode >= 0)
3621 14 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, nColorMode);
3622 :
3623 944 : nDirOffset = TIFFCurrentDirOffset( hTIFF );
3624 : }
3625 226308 : }
3626 :
3627 :
3628 : /************************************************************************/
3629 : /* IsBlockAvailable() */
3630 : /* */
3631 : /* Return TRUE if the indicated strip/tile is available. We */
3632 : /* establish this by testing if the stripbytecount is zero. If */
3633 : /* zero then the block has never been committed to disk. */
3634 : /************************************************************************/
3635 :
3636 102020 : int GTiffDataset::IsBlockAvailable( int nBlockId )
3637 :
3638 : {
3639 102020 : toff_t *panByteCounts = NULL;
3640 :
3641 102020 : if( ( TIFFIsTiled( hTIFF )
3642 : && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts ) )
3643 : || ( !TIFFIsTiled( hTIFF )
3644 : && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts ) ) )
3645 : {
3646 102020 : if( panByteCounts == NULL )
3647 0 : return FALSE;
3648 : else
3649 102020 : return panByteCounts[nBlockId] != 0;
3650 : }
3651 : else
3652 0 : return FALSE;
3653 : }
3654 :
3655 : /************************************************************************/
3656 : /* FlushCache() */
3657 : /* */
3658 : /* We override this so we can also flush out local tiff strip */
3659 : /* cache if need be. */
3660 : /************************************************************************/
3661 :
3662 5630 : void GTiffDataset::FlushCache()
3663 :
3664 : {
3665 5630 : if (bIsFinalized)
3666 0 : return;
3667 :
3668 5630 : GDALPamDataset::FlushCache();
3669 :
3670 5630 : if( bLoadedBlockDirty && nLoadedBlock != -1 )
3671 143 : FlushBlockBuf();
3672 :
3673 5630 : CPLFree( pabyBlockBuf );
3674 5630 : pabyBlockBuf = NULL;
3675 5630 : nLoadedBlock = -1;
3676 5630 : bLoadedBlockDirty = FALSE;
3677 :
3678 5630 : if (!SetDirectory())
3679 0 : return;
3680 5630 : FlushDirectory();
3681 : }
3682 :
3683 : /************************************************************************/
3684 : /* FlushDirectory() */
3685 : /************************************************************************/
3686 :
3687 6940 : void GTiffDataset::FlushDirectory()
3688 :
3689 : {
3690 6940 : if( GetAccess() == GA_Update )
3691 : {
3692 3330 : if( bMetadataChanged )
3693 : {
3694 15 : if (!SetDirectory())
3695 0 : return;
3696 : bNeedsRewrite =
3697 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
3698 15 : papszCreationOptions );
3699 15 : bMetadataChanged = FALSE;
3700 : }
3701 :
3702 3330 : if( bGeoTIFFInfoChanged )
3703 : {
3704 16 : if (!SetDirectory())
3705 0 : return;
3706 16 : WriteGeoTIFFInfo();
3707 : }
3708 :
3709 3330 : if( bNeedsRewrite )
3710 : {
3711 : #if defined(TIFFLIB_VERSION)
3712 : #if defined(HAVE_TIFFGETSIZEPROC)
3713 72 : if (!SetDirectory())
3714 0 : return;
3715 :
3716 72 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3717 :
3718 72 : nDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3719 72 : if( (nDirOffset % 2) == 1 )
3720 14 : nDirOffset++;
3721 :
3722 72 : TIFFRewriteDirectory( hTIFF );
3723 :
3724 72 : TIFFSetSubDirectory( hTIFF, nDirOffset );
3725 : #elif TIFFLIB_VERSION > 20010925 && TIFFLIB_VERSION != 20011807
3726 : if (!SetDirectory())
3727 : return;
3728 :
3729 : TIFFRewriteDirectory( hTIFF );
3730 : #endif
3731 : #endif
3732 72 : bNeedsRewrite = FALSE;
3733 : }
3734 : }
3735 :
3736 : // there are some circumstances in which we can reach this point
3737 : // without having made this our directory (SetDirectory()) in which
3738 : // case we should not risk a flush.
3739 6940 : if( GetAccess() == GA_Update && TIFFCurrentDirOffset(hTIFF) == nDirOffset )
3740 : {
3741 : #if defined(BIGTIFF_SUPPORT)
3742 3312 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3743 :
3744 3312 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3745 3312 : if( (nNewDirOffset % 2) == 1 )
3746 403 : nNewDirOffset++;
3747 :
3748 3312 : TIFFFlush( hTIFF );
3749 :
3750 3312 : if( nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
3751 : {
3752 52 : nDirOffset = nNewDirOffset;
3753 : CPLDebug( "GTiff",
3754 52 : "directory moved during flush in FlushDirectory()" );
3755 : }
3756 : #else
3757 : /* For libtiff 3.X, the above causes regressions and crashes in */
3758 : /* tiff_write.py and tiff_ovr.py */
3759 : TIFFFlush( hTIFF );
3760 : #endif
3761 : }
3762 : }
3763 :
3764 : /************************************************************************/
3765 : /* TIFF_OvLevelAdjust() */
3766 : /* */
3767 : /* Some overview levels cannot be achieved closely enough to be */
3768 : /* recognised as the desired overview level. This function */
3769 : /* will adjust an overview level to one that is achievable on */
3770 : /* the given raster size. */
3771 : /* */
3772 : /* For instance a 1200x1200 image on which a 256 level overview */
3773 : /* is request will end up generating a 5x5 overview. However, */
3774 : /* this will appear to the system be a level 240 overview. */
3775 : /* This function will adjust 256 to 240 based on knowledge of */
3776 : /* the image size. */
3777 : /* */
3778 : /* This is a copy of the GDALOvLevelAdjust() function in */
3779 : /* gdaldefaultoverviews.cpp. */
3780 : /************************************************************************/
3781 :
3782 151 : static int TIFF_OvLevelAdjust( int nOvLevel, int nXSize )
3783 :
3784 : {
3785 151 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
3786 :
3787 151 : return (int) (0.5 + nXSize / (double) nOXSize);
3788 : }
3789 :
3790 : /************************************************************************/
3791 : /* CleanOverviews() */
3792 : /************************************************************************/
3793 :
3794 2 : CPLErr GTiffDataset::CleanOverviews()
3795 :
3796 : {
3797 2 : CPLAssert( bBase );
3798 :
3799 2 : ScanDirectories();
3800 :
3801 2 : FlushDirectory();
3802 2 : *ppoActiveDSRef = NULL;
3803 :
3804 : /* -------------------------------------------------------------------- */
3805 : /* Cleanup overviews objects, and get offsets to all overview */
3806 : /* directories. */
3807 : /* -------------------------------------------------------------------- */
3808 2 : std::vector<toff_t> anOvDirOffsets;
3809 : int i;
3810 :
3811 4 : for( i = 0; i < nOverviewCount; i++ )
3812 : {
3813 2 : anOvDirOffsets.push_back( papoOverviewDS[i]->nDirOffset );
3814 2 : delete papoOverviewDS[i];
3815 : }
3816 :
3817 : /* -------------------------------------------------------------------- */
3818 : /* Loop through all the directories, translating the offsets */
3819 : /* into indexes we can use with TIFFUnlinkDirectory(). */
3820 : /* -------------------------------------------------------------------- */
3821 2 : std::vector<uint16> anOvDirIndexes;
3822 2 : int iThisOffset = 1;
3823 :
3824 2 : TIFFSetDirectory( hTIFF, 0 );
3825 :
3826 2 : for( ; TRUE; )
3827 : {
3828 8 : for( i = 0; i < nOverviewCount; i++ )
3829 : {
3830 4 : if( anOvDirOffsets[i] == TIFFCurrentDirOffset( hTIFF ) )
3831 : {
3832 : CPLDebug( "GTiff", "%d -> %d",
3833 2 : (int) anOvDirOffsets[i], iThisOffset );
3834 2 : anOvDirIndexes.push_back( (uint16) iThisOffset );
3835 : }
3836 : }
3837 :
3838 4 : if( TIFFLastDirectory( hTIFF ) )
3839 : break;
3840 :
3841 2 : TIFFReadDirectory( hTIFF );
3842 2 : iThisOffset++;
3843 : }
3844 :
3845 : /* -------------------------------------------------------------------- */
3846 : /* Actually unlink the target directories. Note that we do */
3847 : /* this from last to first so as to avoid renumbering any of */
3848 : /* the earlier directories we need to remove. */
3849 : /* -------------------------------------------------------------------- */
3850 6 : while( !anOvDirIndexes.empty() )
3851 : {
3852 2 : TIFFUnlinkDirectory( hTIFF, anOvDirIndexes.back() );
3853 2 : anOvDirIndexes.pop_back();
3854 : }
3855 :
3856 2 : CPLFree( papoOverviewDS );
3857 :
3858 2 : nOverviewCount = 0;
3859 2 : papoOverviewDS = NULL;
3860 :
3861 2 : if (!SetDirectory())
3862 0 : return CE_Failure;
3863 :
3864 2 : return CE_None;
3865 : }
3866 :
3867 :
3868 : /************************************************************************/
3869 : /* RegisterNewOverviewDataset() */
3870 : /************************************************************************/
3871 :
3872 122 : CPLErr GTiffDataset::RegisterNewOverviewDataset(toff_t nOverviewOffset)
3873 : {
3874 122 : GTiffDataset* poODS = new GTiffDataset();
3875 122 : poODS->nJpegQuality = nJpegQuality;
3876 122 : poODS->nZLevel = nZLevel;
3877 122 : poODS->nLZMAPreset = nLZMAPreset;
3878 :
3879 122 : if( nCompression == COMPRESSION_JPEG )
3880 : {
3881 18 : if ( CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
3882 : {
3883 8 : poODS->nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
3884 : }
3885 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
3886 18 : poODS->nJpegQuality );
3887 : }
3888 :
3889 122 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nOverviewOffset, FALSE,
3890 : GA_Update ) != CE_None )
3891 : {
3892 0 : delete poODS;
3893 0 : return CE_Failure;
3894 : }
3895 : else
3896 : {
3897 122 : nOverviewCount++;
3898 : papoOverviewDS = (GTiffDataset **)
3899 : CPLRealloc(papoOverviewDS,
3900 122 : nOverviewCount * (sizeof(void*)));
3901 122 : papoOverviewDS[nOverviewCount-1] = poODS;
3902 122 : poODS->poBaseDS = this;
3903 122 : return CE_None;
3904 : }
3905 : }
3906 :
3907 : /************************************************************************/
3908 : /* CreateOverviewsFromSrcOverviews() */
3909 : /************************************************************************/
3910 :
3911 5 : CPLErr GTiffDataset::CreateOverviewsFromSrcOverviews(GDALDataset* poSrcDS)
3912 : {
3913 5 : CPLAssert(poSrcDS->GetRasterCount() != 0);
3914 5 : CPLAssert(nOverviewCount == 0);
3915 :
3916 5 : ScanDirectories();
3917 :
3918 : /* -------------------------------------------------------------------- */
3919 : /* Move to the directory for this dataset. */
3920 : /* -------------------------------------------------------------------- */
3921 5 : if (!SetDirectory())
3922 0 : return CE_Failure;
3923 5 : FlushDirectory();
3924 :
3925 5 : int nOvBitsPerSample = nBitsPerSample;
3926 :
3927 : /* -------------------------------------------------------------------- */
3928 : /* Do we have a palette? If so, create a TIFF compatible version. */
3929 : /* -------------------------------------------------------------------- */
3930 5 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
3931 5 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
3932 :
3933 5 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
3934 : {
3935 : int nColors;
3936 :
3937 0 : if( nOvBitsPerSample == 8 )
3938 0 : nColors = 256;
3939 0 : else if( nOvBitsPerSample < 8 )
3940 0 : nColors = 1 << nOvBitsPerSample;
3941 : else
3942 0 : nColors = 65536;
3943 :
3944 0 : anTRed.resize(nColors,0);
3945 0 : anTGreen.resize(nColors,0);
3946 0 : anTBlue.resize(nColors,0);
3947 :
3948 0 : for( int iColor = 0; iColor < nColors; iColor++ )
3949 : {
3950 0 : if( iColor < poColorTable->GetColorEntryCount() )
3951 : {
3952 : GDALColorEntry sRGB;
3953 :
3954 0 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
3955 :
3956 0 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
3957 0 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
3958 0 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
3959 : }
3960 : else
3961 : {
3962 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
3963 : }
3964 : }
3965 :
3966 0 : panRed = &(anTRed[0]);
3967 0 : panGreen = &(anTGreen[0]);
3968 0 : panBlue = &(anTBlue[0]);
3969 : }
3970 :
3971 : /* -------------------------------------------------------------------- */
3972 : /* Do we need some metadata for the overviews? */
3973 : /* -------------------------------------------------------------------- */
3974 5 : CPLString osMetadata;
3975 :
3976 5 : GTIFFBuildOverviewMetadata( "NONE", this, osMetadata );
3977 :
3978 : /* -------------------------------------------------------------------- */
3979 : /* Fetch extra sample tag */
3980 : /* -------------------------------------------------------------------- */
3981 5 : uint16 *panExtraSampleValues = NULL;
3982 5 : uint16 nExtraSamples = 0;
3983 :
3984 5 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
3985 : {
3986 0 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
3987 0 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
3988 0 : panExtraSampleValues = panExtraSampleValuesNew;
3989 : }
3990 : else
3991 : {
3992 5 : panExtraSampleValues = NULL;
3993 5 : nExtraSamples = 0;
3994 : }
3995 :
3996 : /* -------------------------------------------------------------------- */
3997 : /* Fetch predictor tag */
3998 : /* -------------------------------------------------------------------- */
3999 5 : uint16 nPredictor = PREDICTOR_NONE;
4000 5 : if ( nCompression == COMPRESSION_LZW ||
4001 : nCompression == COMPRESSION_ADOBE_DEFLATE )
4002 0 : TIFFGetField( hTIFF, TIFFTAG_PREDICTOR, &nPredictor );
4003 : int nOvrBlockXSize, nOvrBlockYSize;
4004 5 : GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
4005 :
4006 5 : int nSrcOverviews = poSrcDS->GetRasterBand(1)->GetOverviewCount();
4007 : int i;
4008 5 : CPLErr eErr = CE_None;
4009 :
4010 18 : for(i=0;i<nSrcOverviews && eErr == CE_None;i++)
4011 : {
4012 13 : GDALRasterBand* poOvrBand = poSrcDS->GetRasterBand(1)->GetOverview(i);
4013 :
4014 13 : int nOXSize = poOvrBand->GetXSize(), nOYSize = poOvrBand->GetYSize();
4015 :
4016 : toff_t nOverviewOffset =
4017 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
4018 : nOXSize, nOYSize,
4019 : nOvBitsPerSample, nPlanarConfig,
4020 : nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4021 : nCompression, nPhotometric, nSampleFormat,
4022 : nPredictor,
4023 : panRed, panGreen, panBlue,
4024 : nExtraSamples, panExtraSampleValues,
4025 13 : osMetadata );
4026 :
4027 13 : if( nOverviewOffset == 0 )
4028 0 : eErr = CE_Failure;
4029 : else
4030 13 : eErr = RegisterNewOverviewDataset(nOverviewOffset);
4031 : }
4032 :
4033 5 : CPLFree(panExtraSampleValues);
4034 5 : panExtraSampleValues = NULL;
4035 :
4036 : /* -------------------------------------------------------------------- */
4037 : /* Create overviews for the mask. */
4038 : /* -------------------------------------------------------------------- */
4039 5 : if (eErr == CE_None)
4040 5 : eErr = CreateInternalMaskOverviews(nOvrBlockXSize, nOvrBlockYSize);
4041 :
4042 5 : return eErr;
4043 : }
4044 :
4045 :
4046 : /************************************************************************/
4047 : /* CreateInternalMaskOverviews() */
4048 : /************************************************************************/
4049 :
4050 83 : CPLErr GTiffDataset::CreateInternalMaskOverviews(int nOvrBlockXSize,
4051 : int nOvrBlockYSize)
4052 : {
4053 : GTiffDataset *poODS;
4054 :
4055 83 : ScanDirectories();
4056 :
4057 : /* -------------------------------------------------------------------- */
4058 : /* Create overviews for the mask. */
4059 : /* -------------------------------------------------------------------- */
4060 83 : CPLErr eErr = CE_None;
4061 :
4062 83 : if (poMaskDS != NULL &&
4063 : poMaskDS->GetRasterCount() == 1 &&
4064 : CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
4065 : {
4066 : int nMaskOvrCompression;
4067 4 : if( strstr(GDALGetMetadataItem(GDALGetDriverByName( "GTiff" ),
4068 : GDAL_DMD_CREATIONOPTIONLIST, NULL ),
4069 : "<Value>DEFLATE</Value>") != NULL )
4070 4 : nMaskOvrCompression = COMPRESSION_ADOBE_DEFLATE;
4071 : else
4072 0 : nMaskOvrCompression = COMPRESSION_PACKBITS;
4073 :
4074 : int i;
4075 12 : for( i = 0; i < nOverviewCount; i++ )
4076 : {
4077 8 : if (papoOverviewDS[i]->poMaskDS == NULL)
4078 : {
4079 : toff_t nOverviewOffset;
4080 :
4081 : nOverviewOffset =
4082 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
4083 16 : papoOverviewDS[i]->nRasterXSize, papoOverviewDS[i]->nRasterYSize,
4084 : 1, PLANARCONFIG_CONTIG,
4085 : 1, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4086 : nMaskOvrCompression, PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT, PREDICTOR_NONE,
4087 : NULL, NULL, NULL, 0, NULL,
4088 24 : "" );
4089 :
4090 8 : if( nOverviewOffset == 0 )
4091 : {
4092 0 : eErr = CE_Failure;
4093 0 : continue;
4094 : }
4095 :
4096 8 : poODS = new GTiffDataset();
4097 8 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef,
4098 : nOverviewOffset, FALSE,
4099 : GA_Update ) != CE_None )
4100 : {
4101 0 : delete poODS;
4102 0 : eErr = CE_Failure;
4103 : }
4104 : else
4105 : {
4106 8 : poODS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
4107 8 : poODS->poBaseDS = this;
4108 8 : papoOverviewDS[i]->poMaskDS = poODS;
4109 8 : poMaskDS->nOverviewCount++;
4110 : poMaskDS->papoOverviewDS = (GTiffDataset **)
4111 : CPLRealloc(poMaskDS->papoOverviewDS,
4112 8 : poMaskDS->nOverviewCount * (sizeof(void*)));
4113 8 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] = poODS;
4114 : }
4115 : }
4116 : }
4117 : }
4118 :
4119 83 : return eErr;
4120 : }
4121 :
4122 : /************************************************************************/
4123 : /* IBuildOverviews() */
4124 : /************************************************************************/
4125 :
4126 146 : CPLErr GTiffDataset::IBuildOverviews(
4127 : const char * pszResampling,
4128 : int nOverviews, int * panOverviewList,
4129 : int nBands, int * panBandList,
4130 : GDALProgressFunc pfnProgress, void * pProgressData )
4131 :
4132 : {
4133 146 : CPLErr eErr = CE_None;
4134 : int i;
4135 : GTiffDataset *poODS;
4136 146 : int bUseGenericHandling = FALSE;
4137 :
4138 146 : ScanDirectories();
4139 :
4140 : /* -------------------------------------------------------------------- */
4141 : /* If RRD or external OVR overviews requested, then invoke */
4142 : /* generic handling. */
4143 : /* -------------------------------------------------------------------- */
4144 146 : if( CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" ))
4145 : || CSLTestBoolean(CPLGetConfigOption( "TIFF_USE_OVR", "NO" )) )
4146 : {
4147 2 : bUseGenericHandling = TRUE;
4148 : }
4149 :
4150 : /* -------------------------------------------------------------------- */
4151 : /* If we don't have read access, then create the overviews */
4152 : /* externally. */
4153 : /* -------------------------------------------------------------------- */
4154 146 : if( GetAccess() != GA_Update )
4155 : {
4156 : CPLDebug( "GTiff",
4157 : "File open for read-only accessing, "
4158 63 : "creating overviews externally." );
4159 :
4160 63 : bUseGenericHandling = TRUE;
4161 : }
4162 :
4163 146 : if( bUseGenericHandling )
4164 : {
4165 65 : if (nOverviewCount != 0)
4166 : {
4167 : CPLError(CE_Failure, CPLE_NotSupported,
4168 0 : "Cannot add external overviews when there are already internal overviews");
4169 0 : return CE_Failure;
4170 : }
4171 :
4172 : return GDALDataset::IBuildOverviews(
4173 : pszResampling, nOverviews, panOverviewList,
4174 65 : nBands, panBandList, pfnProgress, pProgressData );
4175 : }
4176 :
4177 : /* -------------------------------------------------------------------- */
4178 : /* Our TIFF overview support currently only works safely if all */
4179 : /* bands are handled at the same time. */
4180 : /* -------------------------------------------------------------------- */
4181 81 : if( nBands != GetRasterCount() )
4182 : {
4183 : CPLError( CE_Failure, CPLE_NotSupported,
4184 : "Generation of overviews in TIFF currently only"
4185 : " supported when operating on all bands.\n"
4186 0 : "Operation failed.\n" );
4187 0 : return CE_Failure;
4188 : }
4189 :
4190 : /* -------------------------------------------------------------------- */
4191 : /* Initialize progress counter. */
4192 : /* -------------------------------------------------------------------- */
4193 81 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
4194 : {
4195 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
4196 0 : return CE_Failure;
4197 : }
4198 :
4199 : /* -------------------------------------------------------------------- */
4200 : /* If zero overviews were requested, we need to clear all */
4201 : /* existing overviews. */
4202 : /* -------------------------------------------------------------------- */
4203 81 : if( nOverviews == 0 )
4204 : {
4205 3 : if( nOverviewCount == 0 )
4206 : return GDALDataset::IBuildOverviews(
4207 : pszResampling, nOverviews, panOverviewList,
4208 1 : nBands, panBandList, pfnProgress, pProgressData );
4209 : else
4210 2 : return CleanOverviews();
4211 : }
4212 :
4213 : /* -------------------------------------------------------------------- */
4214 : /* Move to the directory for this dataset. */
4215 : /* -------------------------------------------------------------------- */
4216 78 : if (!SetDirectory())
4217 0 : return CE_Failure;
4218 78 : FlushDirectory();
4219 :
4220 : /* -------------------------------------------------------------------- */
4221 : /* If we are averaging bit data to grayscale we need to create */
4222 : /* 8bit overviews. */
4223 : /* -------------------------------------------------------------------- */
4224 78 : int nOvBitsPerSample = nBitsPerSample;
4225 :
4226 78 : if( EQUALN(pszResampling,"AVERAGE_BIT2",12) )
4227 2 : nOvBitsPerSample = 8;
4228 :
4229 : /* -------------------------------------------------------------------- */
4230 : /* Do we have a palette? If so, create a TIFF compatible version. */
4231 : /* -------------------------------------------------------------------- */
4232 78 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
4233 78 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
4234 :
4235 78 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
4236 : {
4237 : int nColors;
4238 :
4239 9 : if( nOvBitsPerSample == 8 )
4240 9 : nColors = 256;
4241 0 : else if( nOvBitsPerSample < 8 )
4242 0 : nColors = 1 << nOvBitsPerSample;
4243 : else
4244 0 : nColors = 65536;
4245 :
4246 9 : anTRed.resize(nColors,0);
4247 9 : anTGreen.resize(nColors,0);
4248 9 : anTBlue.resize(nColors,0);
4249 :
4250 2313 : for( int iColor = 0; iColor < nColors; iColor++ )
4251 : {
4252 2304 : if( iColor < poColorTable->GetColorEntryCount() )
4253 : {
4254 : GDALColorEntry sRGB;
4255 :
4256 2304 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
4257 :
4258 2304 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
4259 2304 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
4260 2304 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
4261 : }
4262 : else
4263 : {
4264 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
4265 : }
4266 : }
4267 :
4268 9 : panRed = &(anTRed[0]);
4269 9 : panGreen = &(anTGreen[0]);
4270 9 : panBlue = &(anTBlue[0]);
4271 : }
4272 :
4273 : /* -------------------------------------------------------------------- */
4274 : /* Do we need some metadata for the overviews? */
4275 : /* -------------------------------------------------------------------- */
4276 78 : CPLString osMetadata;
4277 :
4278 78 : GTIFFBuildOverviewMetadata( pszResampling, this, osMetadata );
4279 :
4280 : /* -------------------------------------------------------------------- */
4281 : /* Fetch extra sample tag */
4282 : /* -------------------------------------------------------------------- */
4283 78 : uint16 *panExtraSampleValues = NULL;
4284 78 : uint16 nExtraSamples = 0;
4285 :
4286 78 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
4287 : {
4288 8 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
4289 8 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
4290 8 : panExtraSampleValues = panExtraSampleValuesNew;
4291 : }
4292 : else
4293 : {
4294 70 : panExtraSampleValues = NULL;
4295 70 : nExtraSamples = 0;
4296 : }
4297 :
4298 : /* -------------------------------------------------------------------- */
4299 : /* Fetch predictor tag */
4300 : /* -------------------------------------------------------------------- */
4301 78 : uint16 nPredictor = PREDICTOR_NONE;
4302 78 : if ( nCompression == COMPRESSION_LZW ||
4303 : nCompression == COMPRESSION_ADOBE_DEFLATE )
4304 7 : TIFFGetField( hTIFF, TIFFTAG_PREDICTOR, &nPredictor );
4305 :
4306 : /* -------------------------------------------------------------------- */
4307 : /* Establish which of the overview levels we already have, and */
4308 : /* which are new. We assume that band 1 of the file is */
4309 : /* representative. */
4310 : /* -------------------------------------------------------------------- */
4311 : int nOvrBlockXSize, nOvrBlockYSize;
4312 78 : GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
4313 201 : for( i = 0; i < nOverviews && eErr == CE_None; i++ )
4314 : {
4315 : int j;
4316 :
4317 198 : for( j = 0; j < nOverviewCount && eErr == CE_None; j++ )
4318 : {
4319 : int nOvFactor;
4320 :
4321 75 : poODS = papoOverviewDS[j];
4322 :
4323 : nOvFactor = (int)
4324 75 : (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
4325 :
4326 75 : if( nOvFactor == panOverviewList[i]
4327 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4328 : GetRasterXSize() ) )
4329 14 : panOverviewList[i] *= -1;
4330 : }
4331 :
4332 123 : if( panOverviewList[i] > 0 )
4333 : {
4334 : toff_t nOverviewOffset;
4335 : int nOXSize, nOYSize;
4336 :
4337 109 : nOXSize = (GetRasterXSize() + panOverviewList[i] - 1)
4338 218 : / panOverviewList[i];
4339 109 : nOYSize = (GetRasterYSize() + panOverviewList[i] - 1)
4340 218 : / panOverviewList[i];
4341 :
4342 : nOverviewOffset =
4343 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
4344 : nOXSize, nOYSize,
4345 : nOvBitsPerSample, nPlanarConfig,
4346 : nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4347 : nCompression, nPhotometric, nSampleFormat,
4348 : nPredictor,
4349 : panRed, panGreen, panBlue,
4350 : nExtraSamples, panExtraSampleValues,
4351 109 : osMetadata );
4352 :
4353 :
4354 109 : if( nOverviewOffset == 0 )
4355 0 : eErr = CE_Failure;
4356 : else
4357 109 : eErr = RegisterNewOverviewDataset(nOverviewOffset);
4358 : }
4359 : else
4360 14 : panOverviewList[i] *= -1;
4361 : }
4362 :
4363 78 : CPLFree(panExtraSampleValues);
4364 78 : panExtraSampleValues = NULL;
4365 :
4366 : /* -------------------------------------------------------------------- */
4367 : /* Create overviews for the mask. */
4368 : /* -------------------------------------------------------------------- */
4369 78 : if (eErr == CE_None)
4370 78 : eErr = CreateInternalMaskOverviews(nOvrBlockXSize, nOvrBlockYSize);
4371 : else
4372 0 : return eErr;
4373 :
4374 : /* -------------------------------------------------------------------- */
4375 : /* Refresh overviews for the mask */
4376 : /* -------------------------------------------------------------------- */
4377 89 : if (poMaskDS != NULL &&
4378 : poMaskDS->GetRasterCount() == 1)
4379 : {
4380 : GDALRasterBand **papoOverviewBands;
4381 11 : int nMaskOverviews = 0;
4382 :
4383 11 : papoOverviewBands = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviewCount);
4384 33 : for( i = 0; i < nOverviewCount; i++ )
4385 : {
4386 22 : if (papoOverviewDS[i]->poMaskDS != NULL)
4387 : {
4388 36 : papoOverviewBands[nMaskOverviews ++] =
4389 18 : papoOverviewDS[i]->poMaskDS->GetRasterBand(1);
4390 : }
4391 : }
4392 : eErr = GDALRegenerateOverviews( (GDALRasterBandH)
4393 : poMaskDS->GetRasterBand(1),
4394 : nMaskOverviews,
4395 : (GDALRasterBandH *) papoOverviewBands,
4396 11 : pszResampling, GDALDummyProgress, NULL);
4397 11 : CPLFree(papoOverviewBands);
4398 : }
4399 :
4400 :
4401 : /* -------------------------------------------------------------------- */
4402 : /* Refresh old overviews that were listed. */
4403 : /* -------------------------------------------------------------------- */
4404 94 : if (nCompression != COMPRESSION_NONE &&
4405 : nPlanarConfig == PLANARCONFIG_CONTIG &&
4406 : GDALDataTypeIsComplex(GetRasterBand( panBandList[0] )->GetRasterDataType()) == FALSE &&
4407 16 : GetRasterBand( panBandList[0] )->GetColorTable() == NULL &&
4408 : (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
4409 : {
4410 : /* In the case of pixel interleaved compressed overviews, we want to generate */
4411 : /* the overviews for all the bands block by block, and not band after band, */
4412 : /* in order to write the block once and not loose space in the TIFF file */
4413 :
4414 : GDALRasterBand ***papapoOverviewBands;
4415 : GDALRasterBand **papoBandList;
4416 :
4417 16 : int nNewOverviews = 0;
4418 : int iBand;
4419 :
4420 16 : papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
4421 16 : papoBandList = (GDALRasterBand **) CPLCalloc(sizeof(void*),nBands);
4422 60 : for( iBand = 0; iBand < nBands; iBand++ )
4423 : {
4424 44 : GDALRasterBand* poBand = GetRasterBand( panBandList[iBand] );
4425 :
4426 44 : papoBandList[iBand] = poBand;
4427 44 : papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*), poBand->GetOverviewCount());
4428 :
4429 44 : int iCurOverview = 0;
4430 114 : for( i = 0; i < nOverviews; i++ )
4431 : {
4432 : int j;
4433 :
4434 96 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
4435 : {
4436 : int nOvFactor;
4437 96 : GDALRasterBand * poOverview = poBand->GetOverview( j );
4438 :
4439 : nOvFactor = (int)
4440 96 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
4441 :
4442 : int bHasNoData;
4443 96 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
4444 :
4445 96 : if (bHasNoData)
4446 18 : poOverview->SetNoDataValue(noDataValue);
4447 :
4448 96 : if( nOvFactor == panOverviewList[i]
4449 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4450 : poBand->GetXSize() ) )
4451 : {
4452 70 : papapoOverviewBands[iBand][iCurOverview] = poOverview;
4453 70 : iCurOverview++ ;
4454 70 : break;
4455 : }
4456 : }
4457 : }
4458 :
4459 44 : if (nNewOverviews == 0)
4460 16 : nNewOverviews = iCurOverview;
4461 28 : else if (nNewOverviews != iCurOverview)
4462 : {
4463 0 : CPLAssert(0);
4464 0 : return CE_Failure;
4465 : }
4466 : }
4467 :
4468 : GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
4469 : nNewOverviews, papapoOverviewBands,
4470 16 : pszResampling, pfnProgress, pProgressData );
4471 :
4472 60 : for( iBand = 0; iBand < nBands; iBand++ )
4473 : {
4474 44 : CPLFree(papapoOverviewBands[iBand]);
4475 : }
4476 16 : CPLFree(papapoOverviewBands);
4477 16 : CPLFree(papoBandList);
4478 : }
4479 : else
4480 : {
4481 : GDALRasterBand **papoOverviewBands;
4482 :
4483 : papoOverviewBands = (GDALRasterBand **)
4484 62 : CPLCalloc(sizeof(void*),nOverviews);
4485 :
4486 146 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
4487 : {
4488 : GDALRasterBand *poBand;
4489 : int nNewOverviews;
4490 :
4491 84 : poBand = GetRasterBand( panBandList[iBand] );
4492 :
4493 84 : nNewOverviews = 0;
4494 221 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
4495 : {
4496 : int j;
4497 :
4498 200 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
4499 : {
4500 : int nOvFactor;
4501 200 : GDALRasterBand * poOverview = poBand->GetOverview( j );
4502 :
4503 : int bHasNoData;
4504 200 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
4505 :
4506 200 : if (bHasNoData)
4507 7 : poOverview->SetNoDataValue(noDataValue);
4508 :
4509 : nOvFactor = (int)
4510 200 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
4511 :
4512 200 : if( nOvFactor == panOverviewList[i]
4513 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4514 : poBand->GetXSize() ) )
4515 : {
4516 137 : papoOverviewBands[nNewOverviews++] = poOverview;
4517 137 : break;
4518 : }
4519 : }
4520 : }
4521 :
4522 : void *pScaledProgressData;
4523 :
4524 : pScaledProgressData =
4525 : GDALCreateScaledProgress( iBand / (double) nBands,
4526 : (iBand+1) / (double) nBands,
4527 84 : pfnProgress, pProgressData );
4528 :
4529 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
4530 : nNewOverviews,
4531 : (GDALRasterBandH *) papoOverviewBands,
4532 : pszResampling,
4533 : GDALScaledProgress,
4534 84 : pScaledProgressData);
4535 :
4536 84 : GDALDestroyScaledProgress( pScaledProgressData );
4537 : }
4538 :
4539 : /* -------------------------------------------------------------------- */
4540 : /* Cleanup */
4541 : /* -------------------------------------------------------------------- */
4542 62 : CPLFree( papoOverviewBands );
4543 : }
4544 :
4545 :
4546 78 : pfnProgress( 1.0, NULL, pProgressData );
4547 :
4548 78 : return eErr;
4549 : }
4550 :
4551 :
4552 : /************************************************************************/
4553 : /* WriteGeoTIFFInfo() */
4554 : /************************************************************************/
4555 :
4556 960 : void GTiffDataset::WriteGeoTIFFInfo()
4557 :
4558 : {
4559 960 : bool bPixelIsPoint = false;
4560 960 : int bPointGeoIgnore = FALSE;
4561 :
4562 972 : if( GetMetadataItem( GDALMD_AREA_OR_POINT )
4563 12 : && EQUAL(GetMetadataItem(GDALMD_AREA_OR_POINT),
4564 : GDALMD_AOP_POINT) )
4565 : {
4566 4 : bPixelIsPoint = true;
4567 : bPointGeoIgnore =
4568 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
4569 4 : "FALSE") );
4570 : }
4571 :
4572 : /* -------------------------------------------------------------------- */
4573 : /* If the geotransform is the default, don't bother writing it. */
4574 : /* -------------------------------------------------------------------- */
4575 3010 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
4576 552 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
4577 807 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 )
4578 : {
4579 691 : bNeedsRewrite = TRUE;
4580 :
4581 : /* -------------------------------------------------------------------- */
4582 : /* Clear old tags to ensure we don't end up with conflicting */
4583 : /* information. (#2625) */
4584 : /* -------------------------------------------------------------------- */
4585 : #ifdef HAVE_UNSETFIELD
4586 691 : TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
4587 691 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTIEPOINTS );
4588 691 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTRANSMATRIX );
4589 : #endif
4590 :
4591 : /* -------------------------------------------------------------------- */
4592 : /* Write the transform. If we have a normal north-up image we */
4593 : /* use the tiepoint plus pixelscale otherwise we use a matrix. */
4594 : /* -------------------------------------------------------------------- */
4595 2068 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
4596 689 : && adfGeoTransform[5] < 0.0 )
4597 : {
4598 : double adfPixelScale[3], adfTiePoints[6];
4599 :
4600 688 : adfPixelScale[0] = adfGeoTransform[1];
4601 688 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
4602 688 : adfPixelScale[2] = 0.0;
4603 :
4604 688 : if( !EQUAL(osProfile,"BASELINE") )
4605 683 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
4606 :
4607 688 : adfTiePoints[0] = 0.0;
4608 688 : adfTiePoints[1] = 0.0;
4609 688 : adfTiePoints[2] = 0.0;
4610 688 : adfTiePoints[3] = adfGeoTransform[0];
4611 688 : adfTiePoints[4] = adfGeoTransform[3];
4612 688 : adfTiePoints[5] = 0.0;
4613 :
4614 688 : if( bPixelIsPoint && !bPointGeoIgnore )
4615 : {
4616 0 : adfTiePoints[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
4617 0 : adfTiePoints[4] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
4618 : }
4619 :
4620 688 : if( !EQUAL(osProfile,"BASELINE") )
4621 683 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
4622 : }
4623 : else
4624 : {
4625 : double adfMatrix[16];
4626 :
4627 3 : memset(adfMatrix,0,sizeof(double) * 16);
4628 :
4629 3 : adfMatrix[0] = adfGeoTransform[1];
4630 3 : adfMatrix[1] = adfGeoTransform[2];
4631 3 : adfMatrix[3] = adfGeoTransform[0];
4632 3 : adfMatrix[4] = adfGeoTransform[4];
4633 3 : adfMatrix[5] = adfGeoTransform[5];
4634 3 : adfMatrix[7] = adfGeoTransform[3];
4635 3 : adfMatrix[15] = 1.0;
4636 :
4637 3 : if( bPixelIsPoint && !bPointGeoIgnore )
4638 : {
4639 0 : adfMatrix[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
4640 0 : adfMatrix[7] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
4641 : }
4642 :
4643 3 : if( !EQUAL(osProfile,"BASELINE") )
4644 3 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
4645 : }
4646 :
4647 : // Do we need a world file?
4648 691 : if( CSLFetchBoolean( papszCreationOptions, "TFW", FALSE ) )
4649 2 : GDALWriteWorldFile( osFilename, "tfw", adfGeoTransform );
4650 689 : else if( CSLFetchBoolean( papszCreationOptions, "WORLDFILE", FALSE ) )
4651 2 : GDALWriteWorldFile( osFilename, "wld", adfGeoTransform );
4652 : }
4653 269 : else if( GetGCPCount() > 0 )
4654 : {
4655 : double *padfTiePoints;
4656 : int iGCP;
4657 :
4658 2 : bNeedsRewrite = TRUE;
4659 :
4660 : padfTiePoints = (double *)
4661 2 : CPLMalloc( 6 * sizeof(double) * GetGCPCount() );
4662 :
4663 14 : for( iGCP = 0; iGCP < GetGCPCount(); iGCP++ )
4664 : {
4665 :
4666 12 : padfTiePoints[iGCP*6+0] = pasGCPList[iGCP].dfGCPPixel;
4667 12 : padfTiePoints[iGCP*6+1] = pasGCPList[iGCP].dfGCPLine;
4668 12 : padfTiePoints[iGCP*6+2] = 0;
4669 12 : padfTiePoints[iGCP*6+3] = pasGCPList[iGCP].dfGCPX;
4670 12 : padfTiePoints[iGCP*6+4] = pasGCPList[iGCP].dfGCPY;
4671 12 : padfTiePoints[iGCP*6+5] = pasGCPList[iGCP].dfGCPZ;
4672 :
4673 12 : if( bPixelIsPoint && !bPointGeoIgnore )
4674 : {
4675 0 : padfTiePoints[iGCP*6+0] += 0.5;
4676 0 : padfTiePoints[iGCP*6+1] += 0.5;
4677 : }
4678 : }
4679 :
4680 2 : if( !EQUAL(osProfile,"BASELINE") )
4681 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
4682 2 : 6 * GetGCPCount(), padfTiePoints );
4683 2 : CPLFree( padfTiePoints );
4684 : }
4685 :
4686 : /* -------------------------------------------------------------------- */
4687 : /* Write out projection definition. */
4688 : /* -------------------------------------------------------------------- */
4689 960 : if( pszProjection != NULL && !EQUAL( pszProjection, "" )
4690 : && !EQUAL(osProfile,"BASELINE") )
4691 : {
4692 : GTIF *psGTIF;
4693 :
4694 732 : bNeedsRewrite = TRUE;
4695 :
4696 : // If we have existing geokeys, try to wipe them
4697 : // by writing a dummy goekey directory. (#2546)
4698 732 : uint16 *panVI = NULL;
4699 : uint16 nKeyCount;
4700 :
4701 732 : if( TIFFGetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
4702 : &nKeyCount, &panVI ) )
4703 : {
4704 10 : GUInt16 anGKVersionInfo[4] = { 1, 1, 0, 0 };
4705 10 : double adfDummyDoubleParams[1] = { 0.0 };
4706 : TIFFSetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
4707 10 : 4, anGKVersionInfo );
4708 : TIFFSetField( hTIFF, TIFFTAG_GEODOUBLEPARAMS,
4709 10 : 1, adfDummyDoubleParams );
4710 10 : TIFFSetField( hTIFF, TIFFTAG_GEOASCIIPARAMS, "" );
4711 : }
4712 :
4713 732 : psGTIF = GTIFNew( hTIFF );
4714 :
4715 : // set according to coordinate system.
4716 732 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
4717 :
4718 732 : if( bPixelIsPoint )
4719 : {
4720 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
4721 4 : RasterPixelIsPoint);
4722 : }
4723 :
4724 732 : GTIFWriteKeys( psGTIF );
4725 732 : GTIFFree( psGTIF );
4726 : }
4727 960 : }
4728 :
4729 : /************************************************************************/
4730 : /* AppendMetadataItem() */
4731 : /************************************************************************/
4732 :
4733 203 : static void AppendMetadataItem( CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
4734 : const char *pszKey, const char *pszValue,
4735 : int nBand, const char *pszRole,
4736 : const char *pszDomain )
4737 :
4738 : {
4739 : char szBandId[32];
4740 : CPLXMLNode *psItem;
4741 :
4742 : /* -------------------------------------------------------------------- */
4743 : /* Create the Item element, and subcomponents. */
4744 : /* -------------------------------------------------------------------- */
4745 203 : psItem = CPLCreateXMLNode( NULL, CXT_Element, "Item" );
4746 : CPLCreateXMLNode( CPLCreateXMLNode( psItem, CXT_Attribute, "name"),
4747 203 : CXT_Text, pszKey );
4748 :
4749 203 : if( nBand > 0 )
4750 : {
4751 47 : sprintf( szBandId, "%d", nBand - 1 );
4752 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"sample"),
4753 47 : CXT_Text, szBandId );
4754 : }
4755 :
4756 203 : if( pszRole != NULL )
4757 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"role"),
4758 9 : CXT_Text, pszRole );
4759 :
4760 203 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
4761 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"domain"),
4762 1 : CXT_Text, pszDomain );
4763 :
4764 203 : char *pszEscapedItemValue = CPLEscapeString(pszValue,-1,CPLES_XML);
4765 203 : CPLCreateXMLNode( psItem, CXT_Text, pszEscapedItemValue );
4766 203 : CPLFree( pszEscapedItemValue );
4767 :
4768 : /* -------------------------------------------------------------------- */
4769 : /* Create root, if missing. */
4770 : /* -------------------------------------------------------------------- */
4771 203 : if( *ppsRoot == NULL )
4772 60 : *ppsRoot = CPLCreateXMLNode( NULL, CXT_Element, "GDALMetadata" );
4773 :
4774 : /* -------------------------------------------------------------------- */
4775 : /* Append item to tail. We keep track of the tail to avoid */
4776 : /* O(nsquared) time as the list gets longer. */
4777 : /* -------------------------------------------------------------------- */
4778 203 : if( *ppsTail == NULL )
4779 60 : CPLAddXMLChild( *ppsRoot, psItem );
4780 : else
4781 143 : CPLAddXMLSibling( *ppsTail, psItem );
4782 :
4783 203 : *ppsTail = psItem;
4784 203 : }
4785 :
4786 : /************************************************************************/
4787 : /* WriteMDMDMetadata() */
4788 : /************************************************************************/
4789 :
4790 133346 : static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
4791 : CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
4792 : int nBand, const char *pszProfile )
4793 :
4794 : {
4795 : int iDomain;
4796 : char **papszDomainList;
4797 :
4798 : (void) pszProfile;
4799 :
4800 : /* ==================================================================== */
4801 : /* Process each domain. */
4802 : /* ==================================================================== */
4803 133346 : papszDomainList = poMDMD->GetDomainList();
4804 133570 : for( iDomain = 0; papszDomainList && papszDomainList[iDomain]; iDomain++ )
4805 : {
4806 224 : char **papszMD = poMDMD->GetMetadata( papszDomainList[iDomain] );
4807 : int iItem;
4808 224 : int bIsXML = FALSE;
4809 :
4810 224 : if( EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") )
4811 55 : continue; // ignored
4812 169 : if( EQUAL(papszDomainList[iDomain], "RPC") )
4813 0 : continue; // handled elsewhere
4814 169 : if( EQUAL(papszDomainList[iDomain], "xml:ESRI")
4815 : && CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
4816 1 : continue; // handled elsewhere
4817 :
4818 168 : if( EQUALN(papszDomainList[iDomain], "xml:",4 ) )
4819 1 : bIsXML = TRUE;
4820 :
4821 : /* -------------------------------------------------------------------- */
4822 : /* Process each item in this domain. */
4823 : /* -------------------------------------------------------------------- */
4824 471 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
4825 : {
4826 : const char *pszItemValue;
4827 303 : char *pszItemName = NULL;
4828 :
4829 303 : if( bIsXML )
4830 : {
4831 1 : pszItemName = CPLStrdup("doc");
4832 1 : pszItemValue = papszMD[iItem];
4833 : }
4834 : else
4835 : {
4836 302 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
4837 : }
4838 :
4839 : /* -------------------------------------------------------------------- */
4840 : /* Convert into XML item or handle as a special TIFF tag. */
4841 : /* -------------------------------------------------------------------- */
4842 332 : if( strlen(papszDomainList[iDomain]) == 0
4843 : && nBand == 0 && EQUALN(pszItemName,"TIFFTAG_",8) )
4844 : {
4845 29 : if( EQUAL(pszItemName,"TIFFTAG_DOCUMENTNAME") )
4846 4 : TIFFSetField( hTIFF, TIFFTAG_DOCUMENTNAME, pszItemValue );
4847 25 : else if( EQUAL(pszItemName,"TIFFTAG_IMAGEDESCRIPTION") )
4848 1 : TIFFSetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, pszItemValue );
4849 24 : else if( EQUAL(pszItemName,"TIFFTAG_SOFTWARE") )
4850 2 : TIFFSetField( hTIFF, TIFFTAG_SOFTWARE, pszItemValue );
4851 22 : else if( EQUAL(pszItemName,"TIFFTAG_DATETIME") )
4852 1 : TIFFSetField( hTIFF, TIFFTAG_DATETIME, pszItemValue );
4853 21 : else if( EQUAL(pszItemName,"TIFFTAG_ARTIST") )
4854 1 : TIFFSetField( hTIFF, TIFFTAG_ARTIST, pszItemValue );
4855 20 : else if( EQUAL(pszItemName,"TIFFTAG_HOSTCOMPUTER") )
4856 1 : TIFFSetField( hTIFF, TIFFTAG_HOSTCOMPUTER, pszItemValue );
4857 19 : else if( EQUAL(pszItemName,"TIFFTAG_COPYRIGHT") )
4858 1 : TIFFSetField( hTIFF, TIFFTAG_COPYRIGHT, pszItemValue );
4859 18 : else if( EQUAL(pszItemName,"TIFFTAG_XRESOLUTION") )
4860 6 : TIFFSetField( hTIFF, TIFFTAG_XRESOLUTION, CPLAtof(pszItemValue) );
4861 12 : else if( EQUAL(pszItemName,"TIFFTAG_YRESOLUTION") )
4862 6 : TIFFSetField( hTIFF, TIFFTAG_YRESOLUTION, CPLAtof(pszItemValue) );
4863 6 : else if( EQUAL(pszItemName,"TIFFTAG_RESOLUTIONUNIT") )
4864 6 : TIFFSetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, atoi(pszItemValue) );
4865 0 : else if( EQUAL(pszItemName,"TIFFTAG_MINSAMPLEVALUE") )
4866 0 : TIFFSetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, atoi(pszItemValue) );
4867 0 : else if( EQUAL(pszItemName,"TIFFTAG_MAXSAMPLEVALUE") )
4868 0 : TIFFSetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, atoi(pszItemValue) );
4869 : else
4870 : CPLError(CE_Warning, CPLE_NotSupported,
4871 : "%s metadata item is unhandled and will not be written",
4872 0 : pszItemName);
4873 : }
4874 274 : else if( nBand == 0 && EQUAL(pszItemName,GDALMD_AREA_OR_POINT) )
4875 : /* do nothing, handled elsewhere */;
4876 : else
4877 : AppendMetadataItem( ppsRoot, ppsTail,
4878 : pszItemName, pszItemValue,
4879 194 : nBand, NULL, papszDomainList[iDomain] );
4880 :
4881 303 : CPLFree( pszItemName );
4882 : }
4883 : }
4884 133346 : }
4885 :
4886 : /************************************************************************/
4887 : /* WriteMetadata() */
4888 : /************************************************************************/
4889 :
4890 1161 : int GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
4891 : int bSrcIsGeoTIFF,
4892 : const char *pszProfile,
4893 : const char *pszTIFFFilename,
4894 : char **papszCreationOptions,
4895 : int bExcludeRPBandIMGFileWriting)
4896 :
4897 : {
4898 : /* -------------------------------------------------------------------- */
4899 : /* Convert all the remaining metadata into a simple XML */
4900 : /* format. */
4901 : /* -------------------------------------------------------------------- */
4902 1161 : CPLXMLNode *psRoot = NULL, *psTail = NULL;
4903 :
4904 1161 : if( bSrcIsGeoTIFF )
4905 : {
4906 : WriteMDMetadata( &(((GTiffDataset *)poSrcDS)->oGTiffMDMD),
4907 963 : hTIFF, &psRoot, &psTail, 0, pszProfile );
4908 : }
4909 : else
4910 : {
4911 198 : char **papszMD = poSrcDS->GetMetadata();
4912 :
4913 198 : if( CSLCount(papszMD) > 0 )
4914 : {
4915 95 : GDALMultiDomainMetadata oMDMD;
4916 95 : oMDMD.SetMetadata( papszMD );
4917 :
4918 95 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, 0, pszProfile );
4919 : }
4920 : }
4921 :
4922 : /* -------------------------------------------------------------------- */
4923 : /* Handle RPC data written to an RPB file. */
4924 : /* -------------------------------------------------------------------- */
4925 1161 : char **papszRPCMD = poSrcDS->GetMetadata("RPC");
4926 1161 : if( papszRPCMD != NULL && !bExcludeRPBandIMGFileWriting )
4927 : {
4928 4 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
4929 2 : WriteRPCTag( hTIFF, papszRPCMD );
4930 :
4931 4 : if( !EQUAL(pszProfile,"GDALGeoTIFF")
4932 : || CSLFetchBoolean( papszCreationOptions, "RPB", FALSE ) )
4933 : {
4934 2 : GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
4935 : }
4936 : }
4937 :
4938 : /* -------------------------------------------------------------------- */
4939 : /* Handle metadata data written to an IMD file. */
4940 : /* -------------------------------------------------------------------- */
4941 1161 : char **papszIMDMD = poSrcDS->GetMetadata("IMD");
4942 1161 : if( papszIMDMD != NULL && !bExcludeRPBandIMGFileWriting)
4943 : {
4944 4 : GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
4945 : }
4946 :
4947 : /* -------------------------------------------------------------------- */
4948 : /* We also need to address band specific metadata, and special */
4949 : /* "role" metadata. */
4950 : /* -------------------------------------------------------------------- */
4951 : int nBand;
4952 133733 : for( nBand = 1; nBand <= poSrcDS->GetRasterCount(); nBand++ )
4953 : {
4954 132572 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( nBand );
4955 :
4956 132572 : if( bSrcIsGeoTIFF )
4957 : {
4958 : WriteMDMetadata( &(((GTiffRasterBand *)poBand)->oGTiffMDMD),
4959 132261 : hTIFF, &psRoot, &psTail, nBand, pszProfile );
4960 : }
4961 : else
4962 : {
4963 311 : char **papszMD = poBand->GetMetadata();
4964 :
4965 311 : if( CSLCount(papszMD) > 0 )
4966 : {
4967 27 : GDALMultiDomainMetadata oMDMD;
4968 27 : oMDMD.SetMetadata( papszMD );
4969 :
4970 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, nBand,
4971 27 : pszProfile );
4972 : }
4973 : }
4974 :
4975 : int bSuccess;
4976 132572 : double dfOffset = poBand->GetOffset( &bSuccess );
4977 132572 : double dfScale = poBand->GetScale();
4978 :
4979 132572 : if( bSuccess && (dfOffset != 0.0 || dfScale != 1.0) )
4980 : {
4981 : char szValue[128];
4982 :
4983 2 : sprintf( szValue, "%.18g", dfOffset );
4984 : AppendMetadataItem( &psRoot, &psTail, "OFFSET", szValue, nBand,
4985 2 : "offset", "" );
4986 2 : sprintf( szValue, "%.18g", dfScale );
4987 : AppendMetadataItem( &psRoot, &psTail, "SCALE", szValue, nBand,
4988 2 : "scale", "" );
4989 : }
4990 :
4991 132572 : const char* pszUnitType = poBand->GetUnitType();
4992 132572 : if (pszUnitType != NULL && pszUnitType[0] != '\0')
4993 : AppendMetadataItem( &psRoot, &psTail, "UNITTYPE", pszUnitType, nBand,
4994 5 : "unittype", "" );
4995 : }
4996 :
4997 : /* -------------------------------------------------------------------- */
4998 : /* Write out the generic XML metadata if there is any. */
4999 : /* -------------------------------------------------------------------- */
5000 1161 : if( psRoot != NULL )
5001 : {
5002 60 : int bRet = TRUE;
5003 :
5004 60 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
5005 : {
5006 50 : char *pszXML_MD = CPLSerializeXMLTree( psRoot );
5007 50 : if( strlen(pszXML_MD) > 32000 )
5008 : {
5009 1 : if( bSrcIsGeoTIFF )
5010 1 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
5011 : else
5012 0 : bRet = FALSE;
5013 : CPLError( CE_Warning, CPLE_AppDefined,
5014 1 : "Lost metadata writing to GeoTIFF ... too large to fit in tag." );
5015 : }
5016 : else
5017 : {
5018 49 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszXML_MD );
5019 : }
5020 50 : CPLFree( pszXML_MD );
5021 : }
5022 : else
5023 : {
5024 10 : if( bSrcIsGeoTIFF )
5025 6 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
5026 : else
5027 4 : bRet = FALSE;
5028 : }
5029 :
5030 60 : CPLDestroyXMLNode( psRoot );
5031 :
5032 60 : return bRet;
5033 : }
5034 : else
5035 : {
5036 : /* If we have no more metadata but it existed before, remove the GDAL_METADATA tag */
5037 1101 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
5038 : {
5039 1095 : char* pszText = NULL;
5040 1095 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
5041 : {
5042 : #ifdef HAVE_UNSETFIELD
5043 2 : TIFFUnsetField( hTIFF, TIFFTAG_GDAL_METADATA );
5044 : #else
5045 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, "" );
5046 : #endif
5047 : }
5048 : }
5049 : }
5050 :
5051 1101 : return TRUE;
5052 : }
5053 :
5054 : /************************************************************************/
5055 : /* PushMetadataToPam() */
5056 : /* */
5057 : /* When producing a strict profile TIFF or if our aggregate */
5058 : /* metadata is too big for a single tiff tag we may end up */
5059 : /* needing to write it via the PAM mechanisms. This method */
5060 : /* copies all the appropriate metadata into the PAM level */
5061 : /* metadata object but with special care to avoid copying */
5062 : /* metadata handled in other ways in TIFF format. */
5063 : /************************************************************************/
5064 :
5065 37 : void GTiffDataset::PushMetadataToPam()
5066 :
5067 : {
5068 : int nBand;
5069 123 : for( nBand = 0; nBand <= GetRasterCount(); nBand++ )
5070 : {
5071 : GDALMultiDomainMetadata *poSrcMDMD;
5072 86 : GTiffRasterBand *poBand = NULL;
5073 :
5074 86 : if( nBand == 0 )
5075 37 : poSrcMDMD = &(this->oGTiffMDMD);
5076 : else
5077 : {
5078 49 : poBand = (GTiffRasterBand *) GetRasterBand(nBand);
5079 49 : poSrcMDMD = &(poBand->oGTiffMDMD);
5080 : }
5081 :
5082 : /* -------------------------------------------------------------------- */
5083 : /* Loop over the available domains. */
5084 : /* -------------------------------------------------------------------- */
5085 : int iDomain, i;
5086 : char **papszDomainList;
5087 :
5088 86 : papszDomainList = poSrcMDMD->GetDomainList();
5089 369 : for( iDomain = 0;
5090 180 : papszDomainList && papszDomainList[iDomain];
5091 : iDomain++ )
5092 : {
5093 103 : char **papszMD = poSrcMDMD->GetMetadata( papszDomainList[iDomain] );
5094 :
5095 412 : if( EQUAL(papszDomainList[iDomain],"RPC")
5096 103 : || EQUAL(papszDomainList[iDomain],"IMD")
5097 103 : || EQUAL(papszDomainList[iDomain],"_temporary_")
5098 103 : || EQUAL(papszDomainList[iDomain],"IMAGE_STRUCTURE") )
5099 40 : continue;
5100 :
5101 63 : papszMD = CSLDuplicate(papszMD);
5102 :
5103 221 : for( i = CSLCount(papszMD)-1; i >= 0; i-- )
5104 : {
5105 310 : if( EQUALN(papszMD[i],"TIFFTAG_",8)
5106 152 : || EQUALN(papszMD[i],GDALMD_AREA_OR_POINT,
5107 : strlen(GDALMD_AREA_OR_POINT)) )
5108 26 : papszMD = CSLRemoveStrings( papszMD, i, 1, NULL );
5109 : }
5110 :
5111 63 : if( nBand == 0 )
5112 27 : GDALPamDataset::SetMetadata( papszMD, papszDomainList[iDomain]);
5113 : else
5114 36 : poBand->GDALPamRasterBand::SetMetadata( papszMD, papszDomainList[iDomain]);
5115 :
5116 63 : CSLDestroy( papszMD );
5117 : }
5118 :
5119 : /* -------------------------------------------------------------------- */
5120 : /* Handle some "special domain" stuff. */
5121 : /* -------------------------------------------------------------------- */
5122 86 : if( poBand != NULL )
5123 : {
5124 49 : poBand->GDALPamRasterBand::SetOffset( poBand->GetOffset() );
5125 49 : poBand->GDALPamRasterBand::SetScale( poBand->GetScale() );
5126 49 : poBand->GDALPamRasterBand::SetUnitType( poBand->GetUnitType() );
5127 : }
5128 : }
5129 37 : }
5130 :
5131 : /************************************************************************/
5132 : /* WriteRPCTag() */
5133 : /* */
5134 : /* Format a TAG according to: */
5135 : /* */
5136 : /* http://geotiff.maptools.org/rpc_prop.html */
5137 : /************************************************************************/
5138 :
5139 : /* static */
5140 2 : void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
5141 :
5142 : {
5143 : double adfRPCTag[92];
5144 : GDALRPCInfo sRPC;
5145 :
5146 2 : if( !GDALExtractRPCInfo( papszRPCMD, &sRPC ) )
5147 0 : return;
5148 :
5149 2 : adfRPCTag[0] = -1.0; // Error Bias
5150 2 : adfRPCTag[1] = -1.0; // Error Random
5151 :
5152 2 : adfRPCTag[2] = sRPC.dfLINE_OFF;
5153 2 : adfRPCTag[3] = sRPC.dfSAMP_OFF;
5154 2 : adfRPCTag[4] = sRPC.dfLAT_OFF;
5155 2 : adfRPCTag[5] = sRPC.dfLONG_OFF;
5156 2 : adfRPCTag[6] = sRPC.dfHEIGHT_OFF;
5157 2 : adfRPCTag[7] = sRPC.dfLINE_SCALE;
5158 2 : adfRPCTag[8] = sRPC.dfSAMP_SCALE;
5159 2 : adfRPCTag[9] = sRPC.dfLAT_SCALE;
5160 2 : adfRPCTag[10] = sRPC.dfLONG_SCALE;
5161 2 : adfRPCTag[11] = sRPC.dfHEIGHT_SCALE;
5162 :
5163 2 : memcpy( adfRPCTag + 12, sRPC.adfLINE_NUM_COEFF, sizeof(double) * 20 );
5164 2 : memcpy( adfRPCTag + 32, sRPC.adfLINE_DEN_COEFF, sizeof(double) * 20 );
5165 2 : memcpy( adfRPCTag + 52, sRPC.adfSAMP_NUM_COEFF, sizeof(double) * 20 );
5166 2 : memcpy( adfRPCTag + 72, sRPC.adfSAMP_DEN_COEFF, sizeof(double) * 20 );
5167 :
5168 2 : TIFFSetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, 92, adfRPCTag );
5169 : }
5170 :
5171 : /************************************************************************/
5172 : /* ReadRPCTag() */
5173 : /* */
5174 : /* Format a TAG according to: */
5175 : /* */
5176 : /* http://geotiff.maptools.org/rpc_prop.html */
5177 : /************************************************************************/
5178 :
5179 2180 : void GTiffDataset::ReadRPCTag()
5180 :
5181 : {
5182 : double *padfRPCTag;
5183 2180 : char **papszMD = NULL;
5184 2180 : CPLString osField;
5185 2180 : CPLString osMultiField;
5186 : int i;
5187 : uint16 nCount;
5188 :
5189 2180 : if( !TIFFGetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag )
5190 : || nCount != 92 )
5191 : return;
5192 :
5193 6 : osField.Printf( "%.15g", padfRPCTag[2] );
5194 6 : papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
5195 :
5196 6 : osField.Printf( "%.15g", padfRPCTag[3] );
5197 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
5198 :
5199 6 : osField.Printf( "%.15g", padfRPCTag[4] );
5200 6 : papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
5201 :
5202 6 : osField.Printf( "%.15g", padfRPCTag[5] );
5203 6 : papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
5204 :
5205 6 : osField.Printf( "%.15g", padfRPCTag[6] );
5206 6 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
5207 :
5208 6 : osField.Printf( "%.15g", padfRPCTag[7] );
5209 6 : papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
5210 :
5211 6 : osField.Printf( "%.15g", padfRPCTag[8] );
5212 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
5213 :
5214 6 : osField.Printf( "%.15g", padfRPCTag[9] );
5215 6 : papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
5216 :
5217 6 : osField.Printf( "%.15g", padfRPCTag[10] );
5218 6 : papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
5219 :
5220 6 : osField.Printf( "%.15g", padfRPCTag[11] );
5221 6 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
5222 :
5223 126 : for( i = 0; i < 20; i++ )
5224 : {
5225 120 : osField.Printf( "%.15g", padfRPCTag[12+i] );
5226 120 : if( i > 0 )
5227 114 : osMultiField += " ";
5228 : else
5229 6 : osMultiField = "";
5230 120 : osMultiField += osField;
5231 : }
5232 6 : papszMD = CSLSetNameValue( papszMD, "LINE_NUM_COEFF", osMultiField );
5233 :
5234 126 : for( i = 0; i < 20; i++ )
5235 : {
5236 120 : osField.Printf( "%.15g", padfRPCTag[32+i] );
5237 120 : if( i > 0 )
5238 114 : osMultiField += " ";
5239 : else
5240 6 : osMultiField = "";
5241 120 : osMultiField += osField;
5242 : }
5243 6 : papszMD = CSLSetNameValue( papszMD, "LINE_DEN_COEFF", osMultiField );
5244 :
5245 126 : for( i = 0; i < 20; i++ )
5246 : {
5247 120 : osField.Printf( "%.15g", padfRPCTag[52+i] );
5248 120 : if( i > 0 )
5249 114 : osMultiField += " ";
5250 : else
5251 6 : osMultiField = "";
5252 120 : osMultiField += osField;
5253 : }
5254 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_NUM_COEFF", osMultiField );
5255 :
5256 126 : for( i = 0; i < 20; i++ )
5257 : {
5258 120 : osField.Printf( "%.15g", padfRPCTag[72+i] );
5259 120 : if( i > 0 )
5260 114 : osMultiField += " ";
5261 : else
5262 6 : osMultiField = "";
5263 120 : osMultiField += osField;
5264 : }
5265 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_DEN_COEFF", osMultiField );
5266 :
5267 6 : oGTiffMDMD.SetMetadata( papszMD, "RPC" );
5268 6 : CSLDestroy( papszMD );
5269 : }
5270 :
5271 : /************************************************************************/
5272 : /* WriteNoDataValue() */
5273 : /************************************************************************/
5274 :
5275 69 : void GTiffDataset::WriteNoDataValue( TIFF *hTIFF, double dfNoData )
5276 :
5277 : {
5278 : char szVal[400];
5279 69 : if (CPLIsNan(dfNoData))
5280 1 : strcpy(szVal, "nan");
5281 : else
5282 68 : snprintf(szVal, sizeof(szVal), "%.18g", dfNoData);
5283 69 : TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, szVal );
5284 69 : }
5285 :
5286 : /************************************************************************/
5287 : /* SetDirectory() */
5288 : /************************************************************************/
5289 :
5290 221287 : int GTiffDataset::SetDirectory( toff_t nNewOffset )
5291 :
5292 : {
5293 221287 : Crystalize();
5294 :
5295 221287 : FlushBlockBuf();
5296 :
5297 221287 : if( nNewOffset == 0 )
5298 217210 : nNewOffset = nDirOffset;
5299 :
5300 221287 : if( TIFFCurrentDirOffset(hTIFF) == nNewOffset )
5301 : {
5302 219823 : CPLAssert( *ppoActiveDSRef == this || *ppoActiveDSRef == NULL );
5303 219823 : *ppoActiveDSRef = this;
5304 219823 : return TRUE;
5305 : }
5306 :
5307 1464 : if( GetAccess() == GA_Update )
5308 : {
5309 1182 : if( *ppoActiveDSRef != NULL )
5310 1064 : (*ppoActiveDSRef)->FlushDirectory();
5311 : }
5312 :
5313 1464 : if( nNewOffset == 0)
5314 0 : return TRUE;
5315 :
5316 1464 : (*ppoActiveDSRef) = this;
5317 :
5318 1464 : int nSetDirResult = TIFFSetSubDirectory( hTIFF, nNewOffset );
5319 1464 : if (!nSetDirResult)
5320 0 : return nSetDirResult;
5321 :
5322 : /* -------------------------------------------------------------------- */
5323 : /* YCbCr JPEG compressed images should be translated on the fly */
5324 : /* to RGB by libtiff/libjpeg unless specifically requested */
5325 : /* otherwise. */
5326 : /* -------------------------------------------------------------------- */
5327 1464 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
5328 0 : nCompression = COMPRESSION_NONE;
5329 :
5330 1464 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
5331 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
5332 :
5333 1464 : if( nCompression == COMPRESSION_JPEG
5334 : && nPhotometric == PHOTOMETRIC_YCBCR
5335 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
5336 : "YES") ) )
5337 : {
5338 : int nColorMode;
5339 :
5340 216 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
5341 216 : if( nColorMode != JPEGCOLORMODE_RGB )
5342 216 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
5343 : }
5344 :
5345 : /* -------------------------------------------------------------------- */
5346 : /* Propogate any quality settings. */
5347 : /* -------------------------------------------------------------------- */
5348 1464 : if( GetAccess() == GA_Update )
5349 : {
5350 : // Now, reset zip and jpeg quality.
5351 1182 : if(nJpegQuality > 0 && nCompression == COMPRESSION_JPEG)
5352 : {
5353 : CPLDebug( "GTiff", "Propgate JPEG_QUALITY(%d) in SetDirectory()",
5354 134 : nJpegQuality );
5355 134 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality);
5356 : }
5357 1182 : if(nZLevel > 0 && nCompression == COMPRESSION_ADOBE_DEFLATE)
5358 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, nZLevel);
5359 1182 : if(nLZMAPreset > 0 && nCompression == COMPRESSION_LZMA)
5360 0 : TIFFSetField(hTIFF, TIFFTAG_LZMAPRESET, nLZMAPreset);
5361 : }
5362 :
5363 1464 : return nSetDirResult;
5364 : }
5365 :
5366 : /************************************************************************/
5367 : /* Identify() */
5368 : /************************************************************************/
5369 :
5370 17697 : int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
5371 :
5372 : {
5373 17697 : const char *pszFilename = poOpenInfo->pszFilename;
5374 17697 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
5375 : {
5376 203 : pszFilename += strlen("GTIFF_RAW:");
5377 203 : GDALOpenInfo oOpenInfo( pszFilename, poOpenInfo->eAccess );
5378 203 : return Identify(&oOpenInfo);
5379 : }
5380 :
5381 : /* -------------------------------------------------------------------- */
5382 : /* We have a special hook for handling opening a specific */
5383 : /* directory of a TIFF file. */
5384 : /* -------------------------------------------------------------------- */
5385 17494 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
5386 6 : return TRUE;
5387 :
5388 : /* -------------------------------------------------------------------- */
5389 : /* First we check to see if the file has the expected header */
5390 : /* bytes. */
5391 : /* -------------------------------------------------------------------- */
5392 17488 : if( poOpenInfo->nHeaderBytes < 2 )
5393 10810 : return FALSE;
5394 :
5395 9761 : if( (poOpenInfo->pabyHeader[0] != 'I' || poOpenInfo->pabyHeader[1] != 'I')
5396 3083 : && (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
5397 2932 : return FALSE;
5398 :
5399 : #ifndef BIGTIFF_SUPPORT
5400 : if( (poOpenInfo->pabyHeader[2] == 0x2B && poOpenInfo->pabyHeader[3] == 0) ||
5401 : (poOpenInfo->pabyHeader[2] == 0 && poOpenInfo->pabyHeader[3] == 0x2B) )
5402 : {
5403 : CPLError( CE_Failure, CPLE_OpenFailed,
5404 : "This is a BigTIFF file. BigTIFF is not supported by this\n"
5405 : "version of GDAL and libtiff." );
5406 : return FALSE;
5407 : }
5408 : #endif
5409 :
5410 4017 : if( (poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0)
5411 177 : && (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0)
5412 78 : && (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0)
5413 16 : && (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
5414 0 : return FALSE;
5415 :
5416 3746 : return TRUE;
5417 : }
5418 :
5419 : /************************************************************************/
5420 : /* Open() */
5421 : /************************************************************************/
5422 :
5423 8111 : GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
5424 :
5425 : {
5426 : TIFF *hTIFF;
5427 8111 : int bAllowRGBAInterface = TRUE;
5428 8111 : const char *pszFilename = poOpenInfo->pszFilename;
5429 :
5430 : /* -------------------------------------------------------------------- */
5431 : /* Check if it looks like a TIFF file. */
5432 : /* -------------------------------------------------------------------- */
5433 8111 : if (!Identify(poOpenInfo))
5434 4397 : return NULL;
5435 :
5436 3714 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
5437 : {
5438 203 : bAllowRGBAInterface = FALSE;
5439 203 : pszFilename += strlen("GTIFF_RAW:");
5440 : }
5441 :
5442 : /* -------------------------------------------------------------------- */
5443 : /* We have a special hook for handling opening a specific */
5444 : /* directory of a TIFF file. */
5445 : /* -------------------------------------------------------------------- */
5446 3714 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
5447 6 : return OpenDir( poOpenInfo );
5448 :
5449 3708 : if (!GTiffOneTimeInit())
5450 0 : return NULL;
5451 :
5452 : /* -------------------------------------------------------------------- */
5453 : /* Try opening the dataset. */
5454 : /* -------------------------------------------------------------------- */
5455 3708 : if( poOpenInfo->eAccess == GA_ReadOnly )
5456 3275 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
5457 : else
5458 433 : hTIFF = VSI_TIFFOpen( pszFilename, "r+" );
5459 :
5460 3708 : if( hTIFF == NULL )
5461 0 : return( NULL );
5462 :
5463 : /* -------------------------------------------------------------------- */
5464 : /* Create a corresponding GDALDataset. */
5465 : /* -------------------------------------------------------------------- */
5466 : GTiffDataset *poDS;
5467 :
5468 3708 : poDS = new GTiffDataset();
5469 3708 : poDS->SetDescription( pszFilename );
5470 7416 : poDS->osFilename = pszFilename;
5471 3708 : poDS->poActiveDS = poDS;
5472 :
5473 3708 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
5474 : TIFFCurrentDirOffset(hTIFF), TRUE,
5475 : poOpenInfo->eAccess,
5476 : bAllowRGBAInterface, TRUE,
5477 : poOpenInfo->papszSiblingFiles) != CE_None )
5478 : {
5479 0 : delete poDS;
5480 0 : return NULL;
5481 : }
5482 :
5483 : /* -------------------------------------------------------------------- */
5484 : /* Initialize any PAM information. */
5485 : /* -------------------------------------------------------------------- */
5486 3708 : poDS->TryLoadXML( poOpenInfo->papszSiblingFiles);
5487 3708 : poDS->ApplyPamInfo();
5488 :
5489 : int i;
5490 270626 : for(i=1;i<=poDS->nBands;i++)
5491 : {
5492 266918 : GTiffRasterBand* poBand = (GTiffRasterBand*) poDS->GetRasterBand(i);
5493 :
5494 : /* Load scale, offset and unittype from PAM if available */
5495 266918 : if (!poBand->bHaveOffsetScale)
5496 : {
5497 266912 : poBand->dfScale = poBand->GDALPamRasterBand::GetScale(&poBand->bHaveOffsetScale);
5498 266912 : poBand->dfOffset = poBand->GDALPamRasterBand::GetOffset();
5499 : }
5500 266918 : if (poBand->osUnitType.size() == 0)
5501 : {
5502 266905 : const char* pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
5503 266905 : if (pszUnitType)
5504 266905 : poBand->osUnitType = pszUnitType;
5505 : }
5506 : }
5507 :
5508 3708 : poDS->bMetadataChanged = FALSE;
5509 3708 : poDS->bGeoTIFFInfoChanged = FALSE;
5510 :
5511 : /* -------------------------------------------------------------------- */
5512 : /* Check for external overviews. */
5513 : /* -------------------------------------------------------------------- */
5514 3708 : poDS->oOvManager.Initialize( poDS, pszFilename, poOpenInfo->papszSiblingFiles );
5515 :
5516 3708 : return poDS;
5517 : }
5518 :
5519 : /************************************************************************/
5520 : /* LookForProjection() */
5521 : /************************************************************************/
5522 :
5523 5427 : void GTiffDataset::LookForProjection()
5524 :
5525 : {
5526 5427 : if( bLookedForProjection )
5527 4495 : return;
5528 :
5529 932 : bLookedForProjection = TRUE;
5530 932 : if (!SetDirectory())
5531 0 : return;
5532 :
5533 : /* -------------------------------------------------------------------- */
5534 : /* Capture the GeoTIFF projection, if available. */
5535 : /* -------------------------------------------------------------------- */
5536 : GTIF *hGTIF;
5537 : GTIFDefn sGTIFDefn;
5538 :
5539 932 : CPLFree( pszProjection );
5540 932 : pszProjection = NULL;
5541 :
5542 932 : hGTIF = GTIFNew(hTIFF);
5543 :
5544 932 : if ( !hGTIF )
5545 : {
5546 : CPLError( CE_Warning, CPLE_AppDefined,
5547 0 : "GeoTIFF tags apparently corrupt, they are being ignored." );
5548 : }
5549 : else
5550 : {
5551 932 : if( GTIFGetDefn( hGTIF, &sGTIFDefn ) )
5552 : {
5553 894 : pszProjection = GTIFGetOGISDefn( hGTIF, &sGTIFDefn );
5554 :
5555 : // Should we simplify away vertical CS stuff?
5556 894 : if( EQUALN(pszProjection,"COMPD_CS",8)
5557 : && !CSLTestBoolean( CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
5558 : "NO") ) )
5559 : {
5560 1 : OGRSpatialReference oSRS;
5561 :
5562 1 : CPLDebug( "GTiff", "Got COMPD_CS, but stripping it." );
5563 1 : char *pszWKT = pszProjection;
5564 1 : oSRS.importFromWkt( &pszWKT );
5565 1 : CPLFree( pszProjection );
5566 :
5567 1 : oSRS.StripVertical();
5568 1 : oSRS.exportToWkt( &pszProjection );
5569 : }
5570 : }
5571 :
5572 : // Is this a pixel-is-point dataset?
5573 : short nRasterType;
5574 :
5575 : // check the tif linear unit and the CS linear unit
5576 : #ifdef ESRI_BUILD
5577 : AdjustLinearUnit(sGTIFDefn.UOMLength);
5578 : #endif
5579 :
5580 932 : if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
5581 : 0, 1 ) == 1 )
5582 : {
5583 893 : if( nRasterType == (short) RasterPixelIsPoint )
5584 21 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
5585 : else
5586 872 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
5587 : }
5588 :
5589 932 : GTIFFree( hGTIF );
5590 : }
5591 :
5592 932 : if( pszProjection == NULL )
5593 : {
5594 38 : pszProjection = CPLStrdup( "" );
5595 : }
5596 :
5597 932 : bGeoTIFFInfoChanged = FALSE;
5598 : }
5599 :
5600 : /************************************************************************/
5601 : /* AdjustLinearUnit() */
5602 : /* */
5603 : /* The following code is only used in ESRI Builds and there is */
5604 : /* outstanding discussion on whether it is even appropriate */
5605 : /* then. */
5606 : /************************************************************************/
5607 : #ifdef ESRI_BUILD
5608 :
5609 : void GTiffDataset::AdjustLinearUnit(short UOMLength)
5610 : {
5611 : if (!pszProjection || strlen(pszProjection) == 0)
5612 : return;
5613 : if( UOMLength == 9001)
5614 : {
5615 : char* pstr = strstr(pszProjection, "PARAMETER");
5616 : if (!pstr)
5617 : return;
5618 : pstr = strstr(pstr, "UNIT[");
5619 : if (!pstr)
5620 : return;
5621 : pstr = strchr(pstr, ',') + 1;
5622 : if (!pstr)
5623 : return;
5624 : char* pstr1 = strchr(pstr, ']');
5625 : if (!pstr1 || pstr1 - pstr >= 128)
5626 : return;
5627 : char csUnitStr[128];
5628 : strncpy(csUnitStr, pstr, pstr1-pstr);
5629 : csUnitStr[pstr1-pstr] = '\0';
5630 : double csUnit = CPLAtof(csUnitStr);
5631 : if(fabs(csUnit - 1.0) > 0.000001)
5632 : {
5633 : for(long i=0; i<6; i++)
5634 : adfGeoTransform[i] /= csUnit;
5635 : }
5636 : }
5637 : }
5638 :
5639 : #endif /* def ESRI_BUILD */
5640 :
5641 : /************************************************************************/
5642 : /* ApplyPamInfo() */
5643 : /* */
5644 : /* PAM Information, if available, overrides the GeoTIFF */
5645 : /* geotransform and projection definition. Check for them */
5646 : /* now. */
5647 : /************************************************************************/
5648 :
5649 3708 : void GTiffDataset::ApplyPamInfo()
5650 :
5651 : {
5652 : double adfPamGeoTransform[6];
5653 :
5654 3708 : if( GDALPamDataset::GetGeoTransform( adfPamGeoTransform ) == CE_None
5655 0 : && (adfPamGeoTransform[0] != 0.0 || adfPamGeoTransform[1] != 1.0
5656 0 : || adfPamGeoTransform[2] != 0.0 || adfPamGeoTransform[3] != 0.0
5657 0 : || adfPamGeoTransform[4] != 0.0 || adfPamGeoTransform[5] != 1.0 ))
5658 : {
5659 0 : memcpy( adfGeoTransform, adfPamGeoTransform, sizeof(double)*6 );
5660 0 : bGeoTransformValid = TRUE;
5661 : }
5662 :
5663 3708 : const char *pszPamSRS = GDALPamDataset::GetProjectionRef();
5664 :
5665 3708 : if( pszPamSRS != NULL && strlen(pszPamSRS) > 0 )
5666 : {
5667 2 : CPLFree( pszProjection );
5668 2 : pszProjection = CPLStrdup( pszPamSRS );
5669 2 : bLookedForProjection = TRUE;
5670 : }
5671 :
5672 3708 : int nPamGCPCount = GDALPamDataset::GetGCPCount();
5673 3708 : if( nPamGCPCount > 0 )
5674 : {
5675 2 : if( nGCPCount > 0 )
5676 : {
5677 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
5678 0 : CPLFree( pasGCPList );
5679 0 : pasGCPList = NULL;
5680 : }
5681 :
5682 2 : nGCPCount = nPamGCPCount;
5683 2 : pasGCPList = GDALDuplicateGCPs(nGCPCount, GDALPamDataset::GetGCPs());
5684 :
5685 2 : CPLFree( pszProjection );
5686 2 : pszProjection = NULL;
5687 :
5688 2 : const char *pszPamGCPProjection = GDALPamDataset::GetGCPProjection();
5689 2 : if( pszPamGCPProjection != NULL && strlen(pszPamGCPProjection) > 0 )
5690 2 : pszProjection = CPLStrdup(pszPamGCPProjection);
5691 :
5692 2 : bLookedForProjection = TRUE;
5693 : }
5694 :
5695 : /* -------------------------------------------------------------------- */
5696 : /* Copy any PAM metadata into our GeoTIFF context, and with */
5697 : /* the PAM info overriding the GeoTIFF context. */
5698 : /* -------------------------------------------------------------------- */
5699 3708 : char **papszPamDomains = oMDMD.GetDomainList();
5700 :
5701 3724 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
5702 : {
5703 16 : const char *pszDomain = papszPamDomains[iDomain];
5704 16 : char **papszGT_MD = CSLDuplicate(oGTiffMDMD.GetMetadata( pszDomain ));
5705 16 : char **papszPAM_MD = oMDMD.GetMetadata( pszDomain );
5706 :
5707 16 : papszGT_MD = CSLMerge( papszGT_MD, papszPAM_MD );
5708 :
5709 16 : oGTiffMDMD.SetMetadata( papszGT_MD, pszDomain );
5710 16 : CSLDestroy( papszGT_MD );
5711 : }
5712 :
5713 270626 : for( int i = 1; i <= GetRasterCount(); i++)
5714 : {
5715 266918 : GTiffRasterBand* poBand = (GTiffRasterBand *)GetRasterBand(i);
5716 266918 : papszPamDomains = poBand->oMDMD.GetDomainList();
5717 :
5718 266948 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
5719 : {
5720 30 : const char *pszDomain = papszPamDomains[iDomain];
5721 30 : char **papszGT_MD = CSLDuplicate(poBand->oGTiffMDMD.GetMetadata( pszDomain ));
5722 30 : char **papszPAM_MD = poBand->oMDMD.GetMetadata( pszDomain );
5723 :
5724 30 : papszGT_MD = CSLMerge( papszGT_MD, papszPAM_MD );
5725 :
5726 30 : poBand->oGTiffMDMD.SetMetadata( papszGT_MD, pszDomain );
5727 30 : CSLDestroy( papszGT_MD );
5728 : }
5729 : }
5730 3708 : }
5731 :
5732 : /************************************************************************/
5733 : /* OpenDir() */
5734 : /* */
5735 : /* Open a specific directory as encoded into a filename. */
5736 : /************************************************************************/
5737 :
5738 6 : GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
5739 :
5740 : {
5741 6 : int bAllowRGBAInterface = TRUE;
5742 6 : const char* pszFilename = poOpenInfo->pszFilename;
5743 6 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
5744 : {
5745 0 : bAllowRGBAInterface = FALSE;
5746 0 : pszFilename += strlen("GTIFF_RAW:");
5747 : }
5748 :
5749 6 : if( !EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
5750 0 : return NULL;
5751 :
5752 : /* -------------------------------------------------------------------- */
5753 : /* Split out filename, and dir#/offset. */
5754 : /* -------------------------------------------------------------------- */
5755 6 : pszFilename += strlen("GTIFF_DIR:");
5756 6 : int bAbsolute = FALSE;
5757 : toff_t nOffset;
5758 :
5759 6 : if( EQUALN(pszFilename,"off:",4) )
5760 : {
5761 1 : bAbsolute = TRUE;
5762 1 : pszFilename += 4;
5763 : }
5764 :
5765 6 : nOffset = atol(pszFilename);
5766 6 : pszFilename += 1;
5767 :
5768 20 : while( *pszFilename != '\0' && pszFilename[-1] != ':' )
5769 8 : pszFilename++;
5770 :
5771 6 : if( *pszFilename == '\0' || nOffset == 0 )
5772 : {
5773 : CPLError( CE_Failure, CPLE_OpenFailed,
5774 : "Unable to extract offset or filename, should take the form\n"
5775 0 : "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename" );
5776 0 : return NULL;
5777 : }
5778 :
5779 : /* -------------------------------------------------------------------- */
5780 : /* Try opening the dataset. */
5781 : /* -------------------------------------------------------------------- */
5782 : TIFF *hTIFF;
5783 :
5784 6 : if (!GTiffOneTimeInit())
5785 0 : return NULL;
5786 :
5787 6 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
5788 6 : if( hTIFF == NULL )
5789 0 : return( NULL );
5790 :
5791 : /* -------------------------------------------------------------------- */
5792 : /* If a directory was requested by index, advance to it now. */
5793 : /* -------------------------------------------------------------------- */
5794 6 : if( !bAbsolute )
5795 : {
5796 12 : while( nOffset > 1 )
5797 : {
5798 2 : if( TIFFReadDirectory( hTIFF ) == 0 )
5799 : {
5800 0 : XTIFFClose( hTIFF );
5801 : CPLError( CE_Failure, CPLE_OpenFailed,
5802 0 : "Requested directory %lu not found.", (long unsigned int)nOffset );
5803 0 : return NULL;
5804 : }
5805 2 : nOffset--;
5806 : }
5807 :
5808 5 : nOffset = TIFFCurrentDirOffset( hTIFF );
5809 : }
5810 :
5811 : /* -------------------------------------------------------------------- */
5812 : /* Create a corresponding GDALDataset. */
5813 : /* -------------------------------------------------------------------- */
5814 : GTiffDataset *poDS;
5815 :
5816 6 : poDS = new GTiffDataset();
5817 6 : poDS->SetDescription( poOpenInfo->pszFilename );
5818 12 : poDS->osFilename = poOpenInfo->pszFilename;
5819 6 : poDS->poActiveDS = poDS;
5820 :
5821 12 : if( !EQUAL(pszFilename,poOpenInfo->pszFilename)
5822 : && !EQUALN(poOpenInfo->pszFilename,"GTIFF_RAW:",10) )
5823 : {
5824 6 : poDS->SetPhysicalFilename( pszFilename );
5825 6 : poDS->SetSubdatasetName( poOpenInfo->pszFilename );
5826 6 : poDS->osFilename = pszFilename;
5827 : }
5828 :
5829 6 : if (poOpenInfo->eAccess == GA_Update)
5830 : {
5831 : CPLError( CE_Warning, CPLE_AppDefined,
5832 0 : "Opening a specific TIFF directory is not supported in update mode. Switching to read-only" );
5833 : }
5834 :
5835 6 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
5836 : nOffset, FALSE, GA_ReadOnly,
5837 : bAllowRGBAInterface, TRUE,
5838 : poOpenInfo->papszSiblingFiles ) != CE_None )
5839 : {
5840 0 : delete poDS;
5841 0 : return NULL;
5842 : }
5843 : else
5844 : {
5845 6 : poDS->bCloseTIFFHandle = TRUE;
5846 6 : return poDS;
5847 : }
5848 : }
5849 :
5850 : /************************************************************************/
5851 : /* OpenOffset() */
5852 : /* */
5853 : /* Initialize the GTiffDataset based on a passed in file */
5854 : /* handle, and directory offset to utilize. This is called for */
5855 : /* full res, and overview pages. */
5856 : /************************************************************************/
5857 :
5858 4077 : CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
5859 : GTiffDataset **ppoActiveDSRef,
5860 : toff_t nDirOffsetIn,
5861 : int bBaseIn, GDALAccess eAccess,
5862 : int bAllowRGBAInterface,
5863 : int bReadGeoTransform,
5864 : char** papszSiblingFiles )
5865 :
5866 : {
5867 : uint32 nXSize, nYSize;
5868 4077 : int bTreatAsBitmap = FALSE;
5869 4077 : int bTreatAsOdd = FALSE;
5870 :
5871 4077 : this->eAccess = eAccess;
5872 :
5873 4077 : hTIFF = hTIFFIn;
5874 4077 : this->ppoActiveDSRef = ppoActiveDSRef;
5875 :
5876 4077 : nDirOffset = nDirOffsetIn;
5877 :
5878 4077 : if (!SetDirectory( nDirOffsetIn ))
5879 0 : return CE_Failure;
5880 :
5881 4077 : bBase = bBaseIn;
5882 :
5883 4077 : this->eAccess = eAccess;
5884 :
5885 : /* -------------------------------------------------------------------- */
5886 : /* Capture some information from the file that is of interest. */
5887 : /* -------------------------------------------------------------------- */
5888 4077 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
5889 4077 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
5890 4077 : nRasterXSize = nXSize;
5891 4077 : nRasterYSize = nYSize;
5892 :
5893 4077 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel ) )
5894 0 : nBands = 1;
5895 : else
5896 4077 : nBands = nSamplesPerPixel;
5897 :
5898 4077 : if( !TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)) )
5899 0 : nBitsPerSample = 1;
5900 :
5901 4077 : if( !TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(nPlanarConfig) ) )
5902 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
5903 :
5904 4077 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
5905 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
5906 :
5907 4077 : if( !TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(nSampleFormat) ) )
5908 28 : nSampleFormat = SAMPLEFORMAT_UINT;
5909 :
5910 4077 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
5911 0 : nCompression = COMPRESSION_NONE;
5912 :
5913 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
5914 4077 : if (nCompression != COMPRESSION_NONE &&
5915 : !TIFFIsCODECConfigured(nCompression))
5916 : {
5917 : CPLError( CE_Failure, CPLE_AppDefined,
5918 0 : "Cannot open TIFF file due to missing codec." );
5919 0 : return CE_Failure;
5920 : }
5921 : #endif
5922 :
5923 : /* -------------------------------------------------------------------- */
5924 : /* YCbCr JPEG compressed images should be translated on the fly */
5925 : /* to RGB by libtiff/libjpeg unless specifically requested */
5926 : /* otherwise. */
5927 : /* -------------------------------------------------------------------- */
5928 4077 : if( nCompression == COMPRESSION_JPEG
5929 : && nPhotometric == PHOTOMETRIC_YCBCR
5930 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
5931 : "YES") ) )
5932 : {
5933 : int nColorMode;
5934 :
5935 112 : SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
5936 112 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
5937 : nColorMode != JPEGCOLORMODE_RGB )
5938 94 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
5939 : }
5940 :
5941 : /* -------------------------------------------------------------------- */
5942 : /* Get strip/tile layout. */
5943 : /* -------------------------------------------------------------------- */
5944 4077 : if( TIFFIsTiled(hTIFF) )
5945 : {
5946 677 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(nBlockXSize) );
5947 677 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(nBlockYSize) );
5948 : }
5949 : else
5950 : {
5951 3400 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
5952 : &(nRowsPerStrip) ) )
5953 : {
5954 : CPLError( CE_Warning, CPLE_AppDefined,
5955 0 : "RowsPerStrip not defined ... assuming all one strip." );
5956 0 : nRowsPerStrip = nYSize; /* dummy value */
5957 : }
5958 :
5959 3400 : nBlockXSize = nRasterXSize;
5960 3400 : nBlockYSize = MIN(nRowsPerStrip,nYSize);
5961 : }
5962 :
5963 : nBlocksPerBand =
5964 : ((nYSize + nBlockYSize - 1) / nBlockYSize)
5965 4077 : * ((nXSize + nBlockXSize - 1) / nBlockXSize);
5966 :
5967 : /* -------------------------------------------------------------------- */
5968 : /* Should we handle this using the GTiffBitmapBand? */
5969 : /* -------------------------------------------------------------------- */
5970 4077 : if( nBitsPerSample == 1 && nBands == 1 )
5971 : {
5972 128 : bTreatAsBitmap = TRUE;
5973 :
5974 : // Lets treat large "one row" bitmaps using the scanline api.
5975 128 : if( !TIFFIsTiled(hTIFF)
5976 : && nBlockYSize == nYSize
5977 : && nYSize > 2000
5978 : && bAllowRGBAInterface )
5979 4 : bTreatAsSplitBitmap = TRUE;
5980 : }
5981 :
5982 : /* -------------------------------------------------------------------- */
5983 : /* Should we treat this via the RGBA interface? */
5984 : /* -------------------------------------------------------------------- */
5985 4077 : if( bAllowRGBAInterface &&
5986 : !bTreatAsBitmap && !(nBitsPerSample > 8)
5987 : && (nPhotometric == PHOTOMETRIC_CIELAB ||
5988 : nPhotometric == PHOTOMETRIC_LOGL ||
5989 : nPhotometric == PHOTOMETRIC_LOGLUV ||
5990 : nPhotometric == PHOTOMETRIC_SEPARATED ||
5991 : ( nPhotometric == PHOTOMETRIC_YCBCR
5992 : && nCompression != COMPRESSION_JPEG )) )
5993 : {
5994 : char szMessage[1024];
5995 :
5996 5 : if( TIFFRGBAImageOK( hTIFF, szMessage ) == 1 )
5997 : {
5998 5 : const char* pszSourceColorSpace = NULL;
5999 5 : switch (nPhotometric)
6000 : {
6001 : case PHOTOMETRIC_CIELAB:
6002 1 : pszSourceColorSpace = "CIELAB";
6003 1 : break;
6004 : case PHOTOMETRIC_LOGL:
6005 0 : pszSourceColorSpace = "LOGL";
6006 0 : break;
6007 : case PHOTOMETRIC_LOGLUV:
6008 0 : pszSourceColorSpace = "LOGLUV";
6009 0 : break;
6010 : case PHOTOMETRIC_SEPARATED:
6011 3 : pszSourceColorSpace = "CMYK";
6012 3 : break;
6013 : case PHOTOMETRIC_YCBCR:
6014 1 : pszSourceColorSpace = "YCbCr";
6015 : break;
6016 : }
6017 5 : if (pszSourceColorSpace)
6018 5 : SetMetadataItem( "SOURCE_COLOR_SPACE", pszSourceColorSpace, "IMAGE_STRUCTURE" );
6019 5 : bTreatAsRGBA = TRUE;
6020 5 : nBands = 4;
6021 : }
6022 : else
6023 : {
6024 0 : CPLDebug( "GTiff", "TIFFRGBAImageOK says:\n%s", szMessage );
6025 : }
6026 : }
6027 :
6028 : /* -------------------------------------------------------------------- */
6029 : /* Should we treat this via the split interface? */
6030 : /* -------------------------------------------------------------------- */
6031 4077 : if( !TIFFIsTiled(hTIFF)
6032 : && nBitsPerSample == 8
6033 : && nBlockYSize == nYSize
6034 : && nYSize > 2000
6035 : && !bTreatAsRGBA
6036 : && CSLTestBoolean(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
6037 : {
6038 : /* libtiff 3.9.2 (20091104) and older, libtiff 4.0.0beta5 (also 20091104) */
6039 : /* and older will crash when trying to open a all-in-one-strip */
6040 : /* YCbCr JPEG compressed TIFF (see #3259). */
6041 : #if (TIFFLIB_VERSION <= 20091104 && !defined(BIGTIFF_SUPPORT)) || \
6042 : (TIFFLIB_VERSION <= 20091104 && defined(BIGTIFF_SUPPORT))
6043 : if (nPhotometric == PHOTOMETRIC_YCBCR &&
6044 : nCompression == COMPRESSION_JPEG)
6045 : {
6046 : CPLDebug("GTiff", "Avoid using split band to open all-in-one-strip "
6047 : "YCbCr JPEG compressed TIFF because of older libtiff");
6048 : }
6049 : else
6050 : #endif
6051 9 : bTreatAsSplit = TRUE;
6052 : }
6053 :
6054 : /* -------------------------------------------------------------------- */
6055 : /* Should we treat this via the odd bits interface? */
6056 : /* -------------------------------------------------------------------- */
6057 4077 : if ( nSampleFormat == SAMPLEFORMAT_IEEEFP )
6058 : {
6059 485 : if ( nBitsPerSample == 16 || nBitsPerSample == 24 )
6060 2 : bTreatAsOdd = TRUE;
6061 : }
6062 3592 : else if ( !bTreatAsRGBA && !bTreatAsBitmap
6063 : && nBitsPerSample != 8
6064 : && nBitsPerSample != 16
6065 : && nBitsPerSample != 32
6066 : && nBitsPerSample != 64
6067 : && nBitsPerSample != 128 )
6068 115 : bTreatAsOdd = TRUE;
6069 :
6070 4077 : int bMinIsWhite = nPhotometric == PHOTOMETRIC_MINISWHITE;
6071 :
6072 : /* -------------------------------------------------------------------- */
6073 : /* Capture the color table if there is one. */
6074 : /* -------------------------------------------------------------------- */
6075 : unsigned short *panRed, *panGreen, *panBlue;
6076 :
6077 4077 : if( bTreatAsRGBA
6078 : || TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
6079 : &panRed, &panGreen, &panBlue) == 0 )
6080 : {
6081 : // Build inverted palette if we have inverted photometric.
6082 : // Pixel values remains unchanged. Avoid doing this for *deep*
6083 : // data types (per #1882)
6084 4006 : if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
6085 : {
6086 : GDALColorEntry oEntry;
6087 : int iColor, nColorCount;
6088 :
6089 7 : poColorTable = new GDALColorTable();
6090 7 : nColorCount = 1 << nBitsPerSample;
6091 :
6092 21 : for ( iColor = 0; iColor < nColorCount; iColor++ )
6093 : {
6094 : oEntry.c1 = oEntry.c2 = oEntry.c3 = (short)
6095 14 : ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
6096 14 : oEntry.c4 = 255;
6097 14 : poColorTable->SetColorEntry( iColor, &oEntry );
6098 : }
6099 :
6100 7 : nPhotometric = PHOTOMETRIC_PALETTE;
6101 : }
6102 : else
6103 3992 : poColorTable = NULL;
6104 : }
6105 : else
6106 : {
6107 78 : int nColorCount, nMaxColor = 0;
6108 : GDALColorEntry oEntry;
6109 :
6110 78 : poColorTable = new GDALColorTable();
6111 :
6112 78 : nColorCount = 1 << nBitsPerSample;
6113 :
6114 343906 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6115 : {
6116 343828 : oEntry.c1 = panRed[iColor] / 256;
6117 343828 : oEntry.c2 = panGreen[iColor] / 256;
6118 343828 : oEntry.c3 = panBlue[iColor] / 256;
6119 343828 : oEntry.c4 = 255;
6120 :
6121 343828 : poColorTable->SetColorEntry( iColor, &oEntry );
6122 :
6123 343828 : nMaxColor = MAX(nMaxColor,panRed[iColor]);
6124 343828 : nMaxColor = MAX(nMaxColor,panGreen[iColor]);
6125 343828 : nMaxColor = MAX(nMaxColor,panBlue[iColor]);
6126 : }
6127 :
6128 : // Bug 1384 - Some TIFF files are generated with color map entry
6129 : // values in range 0-255 instead of 0-65535 - try to handle these
6130 : // gracefully.
6131 78 : if( nMaxColor > 0 && nMaxColor < 256 )
6132 : {
6133 0 : CPLDebug( "GTiff", "TIFF ColorTable seems to be improperly scaled, fixing up." );
6134 :
6135 0 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6136 : {
6137 0 : oEntry.c1 = panRed[iColor];
6138 0 : oEntry.c2 = panGreen[iColor];
6139 0 : oEntry.c3 = panBlue[iColor];
6140 0 : oEntry.c4 = 255;
6141 :
6142 0 : poColorTable->SetColorEntry( iColor, &oEntry );
6143 : }
6144 : }
6145 : }
6146 :
6147 : /* -------------------------------------------------------------------- */
6148 : /* Create band information objects. */
6149 : /* -------------------------------------------------------------------- */
6150 271567 : for( int iBand = 0; iBand < nBands; iBand++ )
6151 : {
6152 267490 : if( bTreatAsRGBA )
6153 20 : SetBand( iBand+1, new GTiffRGBABand( this, iBand+1 ) );
6154 267470 : else if( bTreatAsSplitBitmap )
6155 4 : SetBand( iBand+1, new GTiffSplitBitmapBand( this, iBand+1 ) );
6156 267466 : else if( bTreatAsSplit )
6157 27 : SetBand( iBand+1, new GTiffSplitBand( this, iBand+1 ) );
6158 267439 : else if( bTreatAsBitmap )
6159 124 : SetBand( iBand+1, new GTiffBitmapBand( this, iBand+1 ) );
6160 267315 : else if( bTreatAsOdd )
6161 231 : SetBand( iBand+1, new GTiffOddBitsBand( this, iBand+1 ) );
6162 : else
6163 267084 : SetBand( iBand+1, new GTiffRasterBand( this, iBand+1 ) );
6164 : }
6165 :
6166 4077 : if( GetRasterBand(1)->GetRasterDataType() == GDT_Unknown )
6167 : {
6168 : CPLError( CE_Failure, CPLE_NotSupported,
6169 0 : "Unsupported TIFF configuration." );
6170 0 : return CE_Failure;
6171 : }
6172 :
6173 : /* -------------------------------------------------------------------- */
6174 : /* Get the transform or gcps from the GeoTIFF file. */
6175 : /* -------------------------------------------------------------------- */
6176 4077 : if( bReadGeoTransform )
6177 : {
6178 3714 : char *pszTabWKT = NULL;
6179 : double *padfTiePoints, *padfScale, *padfMatrix;
6180 : uint16 nCount;
6181 3714 : bool bPixelIsPoint = false;
6182 : short nRasterType;
6183 : GTIF *psGTIF;
6184 3714 : int bPointGeoIgnore = FALSE;
6185 :
6186 3714 : psGTIF = GTIFNew( hTIFF ); // I wonder how expensive this is?
6187 :
6188 3714 : if( psGTIF )
6189 : {
6190 3713 : if( GTIFKeyGet(psGTIF, GTRasterTypeGeoKey, &nRasterType,
6191 : 0, 1 ) == 1
6192 : && nRasterType == (short) RasterPixelIsPoint )
6193 : {
6194 31 : bPixelIsPoint = true;
6195 : bPointGeoIgnore =
6196 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
6197 31 : "FALSE") );
6198 : }
6199 :
6200 3713 : GTIFFree( psGTIF );
6201 : }
6202 :
6203 3714 : adfGeoTransform[0] = 0.0;
6204 3714 : adfGeoTransform[1] = 1.0;
6205 3714 : adfGeoTransform[2] = 0.0;
6206 3714 : adfGeoTransform[3] = 0.0;
6207 3714 : adfGeoTransform[4] = 0.0;
6208 3714 : adfGeoTransform[5] = 1.0;
6209 :
6210 9020 : if( TIFFGetField(hTIFF,TIFFTAG_GEOPIXELSCALE,&nCount,&padfScale )
6211 : && nCount >= 2
6212 5306 : && padfScale[0] != 0.0 && padfScale[1] != 0.0 )
6213 : {
6214 2653 : adfGeoTransform[1] = padfScale[0];
6215 2653 : adfGeoTransform[5] = - ABS(padfScale[1]);
6216 :
6217 2653 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
6218 : && nCount >= 6 )
6219 : {
6220 : adfGeoTransform[0] =
6221 2653 : padfTiePoints[3] - padfTiePoints[0] * adfGeoTransform[1];
6222 : adfGeoTransform[3] =
6223 2653 : padfTiePoints[4] - padfTiePoints[1] * adfGeoTransform[5];
6224 :
6225 2653 : if( bPixelIsPoint && !bPointGeoIgnore )
6226 : {
6227 15 : adfGeoTransform[0] -= (adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5);
6228 15 : adfGeoTransform[3] -= (adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5);
6229 : }
6230 :
6231 2653 : bGeoTransformValid = TRUE;
6232 : }
6233 : }
6234 :
6235 1061 : else if( TIFFGetField(hTIFF,TIFFTAG_GEOTRANSMATRIX,&nCount,&padfMatrix )
6236 : && nCount == 16 )
6237 : {
6238 14 : adfGeoTransform[0] = padfMatrix[3];
6239 14 : adfGeoTransform[1] = padfMatrix[0];
6240 14 : adfGeoTransform[2] = padfMatrix[1];
6241 14 : adfGeoTransform[3] = padfMatrix[7];
6242 14 : adfGeoTransform[4] = padfMatrix[4];
6243 14 : adfGeoTransform[5] = padfMatrix[5];
6244 :
6245 14 : if( bPixelIsPoint && !bPointGeoIgnore )
6246 : {
6247 4 : adfGeoTransform[0] -= (adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5);
6248 4 : adfGeoTransform[3] -= (adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5);
6249 : }
6250 :
6251 14 : bGeoTransformValid = TRUE;
6252 : }
6253 :
6254 : /* -------------------------------------------------------------------- */
6255 : /* Otherwise try looking for a .tfw, .tifw or .wld file. */
6256 : /* -------------------------------------------------------------------- */
6257 : else
6258 : {
6259 1047 : char* pszWldFilename = NULL;
6260 :
6261 : bGeoTransformValid =
6262 : GDALReadWorldFile2( osFilename, NULL, adfGeoTransform,
6263 1047 : papszSiblingFiles, &pszWldFilename);
6264 :
6265 1047 : if( !bGeoTransformValid )
6266 : {
6267 : bGeoTransformValid =
6268 : GDALReadWorldFile2( osFilename, "wld", adfGeoTransform,
6269 1042 : papszSiblingFiles, &pszWldFilename);
6270 : }
6271 :
6272 1047 : if( !bGeoTransformValid )
6273 : {
6274 : int bTabFileOK =
6275 : GDALReadTabFile2( osFilename, adfGeoTransform,
6276 : &pszTabWKT, &nGCPCount, &pasGCPList,
6277 1037 : papszSiblingFiles, &pszWldFilename );
6278 :
6279 1037 : if( bTabFileOK && nGCPCount == 0 )
6280 2 : bGeoTransformValid = TRUE;
6281 : }
6282 :
6283 1047 : if (pszWldFilename)
6284 : {
6285 12 : osWldFilename = pszWldFilename;
6286 12 : CPLFree(pszWldFilename);
6287 : }
6288 : }
6289 :
6290 : /* -------------------------------------------------------------------- */
6291 : /* Check for GCPs. Note, we will allow there to be GCPs and a */
6292 : /* transform in some circumstances. */
6293 : /* -------------------------------------------------------------------- */
6294 3714 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
6295 : && !bGeoTransformValid )
6296 : {
6297 25 : nGCPCount = nCount / 6;
6298 25 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPCount);
6299 :
6300 129 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
6301 : {
6302 : char szID[32];
6303 :
6304 104 : sprintf( szID, "%d", iGCP+1 );
6305 104 : pasGCPList[iGCP].pszId = CPLStrdup( szID );
6306 104 : pasGCPList[iGCP].pszInfo = CPLStrdup("");
6307 104 : pasGCPList[iGCP].dfGCPPixel = padfTiePoints[iGCP*6+0];
6308 104 : pasGCPList[iGCP].dfGCPLine = padfTiePoints[iGCP*6+1];
6309 104 : pasGCPList[iGCP].dfGCPX = padfTiePoints[iGCP*6+3];
6310 104 : pasGCPList[iGCP].dfGCPY = padfTiePoints[iGCP*6+4];
6311 104 : pasGCPList[iGCP].dfGCPZ = padfTiePoints[iGCP*6+5];
6312 :
6313 104 : if( bPixelIsPoint && !bPointGeoIgnore )
6314 : {
6315 0 : pasGCPList[iGCP].dfGCPPixel -= 0.5;
6316 0 : pasGCPList[iGCP].dfGCPLine -= 0.5;
6317 : }
6318 : }
6319 : }
6320 :
6321 : /* -------------------------------------------------------------------- */
6322 : /* Did we find a tab file? If so we will use it's coordinate */
6323 : /* system and give it precidence. */
6324 : /* -------------------------------------------------------------------- */
6325 3716 : if( pszTabWKT != NULL
6326 2 : && (pszProjection == NULL || pszProjection[0] == '\0') )
6327 : {
6328 2 : CPLFree( pszProjection );
6329 2 : pszProjection = pszTabWKT;
6330 2 : pszTabWKT = NULL;
6331 2 : bLookedForProjection = TRUE;
6332 : }
6333 :
6334 3714 : CPLFree( pszTabWKT );
6335 3714 : bGeoTIFFInfoChanged = FALSE;
6336 : }
6337 :
6338 : /* -------------------------------------------------------------------- */
6339 : /* Capture some other potentially interesting information. */
6340 : /* -------------------------------------------------------------------- */
6341 : char *pszText, szWorkMDI[200];
6342 : float fResolution;
6343 : uint16 nShort;
6344 :
6345 4077 : if( TIFFGetField( hTIFF, TIFFTAG_DOCUMENTNAME, &pszText ) )
6346 18 : SetMetadataItem( "TIFFTAG_DOCUMENTNAME", pszText );
6347 :
6348 4077 : if( TIFFGetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, &pszText ) )
6349 3 : SetMetadataItem( "TIFFTAG_IMAGEDESCRIPTION", pszText );
6350 :
6351 4077 : if( TIFFGetField( hTIFF, TIFFTAG_SOFTWARE, &pszText ) )
6352 10 : SetMetadataItem( "TIFFTAG_SOFTWARE", pszText );
6353 :
6354 4077 : if( TIFFGetField( hTIFF, TIFFTAG_DATETIME, &pszText ) )
6355 5 : SetMetadataItem( "TIFFTAG_DATETIME", pszText );
6356 :
6357 4077 : if( TIFFGetField( hTIFF, TIFFTAG_ARTIST, &pszText ) )
6358 2 : SetMetadataItem( "TIFFTAG_ARTIST", pszText );
6359 :
6360 4077 : if( TIFFGetField( hTIFF, TIFFTAG_HOSTCOMPUTER, &pszText ) )
6361 2 : SetMetadataItem( "TIFFTAG_HOSTCOMPUTER", pszText );
6362 :
6363 4077 : if( TIFFGetField( hTIFF, TIFFTAG_COPYRIGHT, &pszText ) )
6364 2 : SetMetadataItem( "TIFFTAG_COPYRIGHT", pszText );
6365 :
6366 4077 : if( TIFFGetField( hTIFF, TIFFTAG_XRESOLUTION, &fResolution ) )
6367 : {
6368 41 : sprintf( szWorkMDI, "%.8g", fResolution );
6369 41 : SetMetadataItem( "TIFFTAG_XRESOLUTION", szWorkMDI );
6370 : }
6371 :
6372 4077 : if( TIFFGetField( hTIFF, TIFFTAG_YRESOLUTION, &fResolution ) )
6373 : {
6374 41 : sprintf( szWorkMDI, "%.8g", fResolution );
6375 41 : SetMetadataItem( "TIFFTAG_YRESOLUTION", szWorkMDI );
6376 : }
6377 :
6378 4077 : if( TIFFGetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, &nShort ) )
6379 : {
6380 0 : sprintf( szWorkMDI, "%d", nShort );
6381 0 : SetMetadataItem( "TIFFTAG_MINSAMPLEVALUE", szWorkMDI );
6382 : }
6383 :
6384 4077 : if( TIFFGetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, &nShort ) )
6385 : {
6386 0 : sprintf( szWorkMDI, "%d", nShort );
6387 0 : SetMetadataItem( "TIFFTAG_MAXSAMPLEVALUE", szWorkMDI );
6388 : }
6389 :
6390 4077 : if( TIFFGetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort ) )
6391 : {
6392 41 : if( nShort == RESUNIT_NONE )
6393 16 : sprintf( szWorkMDI, "%d (unitless)", nShort );
6394 25 : else if( nShort == RESUNIT_INCH )
6395 25 : sprintf( szWorkMDI, "%d (pixels/inch)", nShort );
6396 0 : else if( nShort == RESUNIT_CENTIMETER )
6397 0 : sprintf( szWorkMDI, "%d (pixels/cm)", nShort );
6398 : else
6399 0 : sprintf( szWorkMDI, "%d", nShort );
6400 41 : SetMetadataItem( "TIFFTAG_RESOLUTIONUNIT", szWorkMDI );
6401 : }
6402 :
6403 : int nTagSize;
6404 : void* pData;
6405 4077 : if( TIFFGetField( hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData ) )
6406 : {
6407 2 : char* pszXMP = (char*)VSIMalloc(nTagSize + 1);
6408 2 : if (pszXMP)
6409 : {
6410 2 : memcpy(pszXMP, pData, nTagSize);
6411 2 : pszXMP[nTagSize] = '\0';
6412 :
6413 : char *apszMDList[2];
6414 2 : apszMDList[0] = pszXMP;
6415 2 : apszMDList[1] = NULL;
6416 2 : SetMetadata(apszMDList, "xml:XMP");
6417 :
6418 2 : CPLFree(pszXMP);
6419 : }
6420 : }
6421 :
6422 4077 : if( nCompression == COMPRESSION_NONE )
6423 : /* no compression tag */;
6424 402 : else if( nCompression == COMPRESSION_CCITTRLE )
6425 0 : SetMetadataItem( "COMPRESSION", "CCITTRLE", "IMAGE_STRUCTURE" );
6426 402 : else if( nCompression == COMPRESSION_CCITTFAX3 )
6427 0 : SetMetadataItem( "COMPRESSION", "CCITTFAX3", "IMAGE_STRUCTURE" );
6428 402 : else if( nCompression == COMPRESSION_CCITTFAX4 )
6429 9 : SetMetadataItem( "COMPRESSION", "CCITTFAX4", "IMAGE_STRUCTURE" );
6430 393 : else if( nCompression == COMPRESSION_LZW )
6431 42 : SetMetadataItem( "COMPRESSION", "LZW", "IMAGE_STRUCTURE" );
6432 351 : else if( nCompression == COMPRESSION_OJPEG )
6433 1 : SetMetadataItem( "COMPRESSION", "OJPEG", "IMAGE_STRUCTURE" );
6434 350 : else if( nCompression == COMPRESSION_JPEG )
6435 : {
6436 133 : if ( nPhotometric == PHOTOMETRIC_YCBCR )
6437 112 : SetMetadataItem( "COMPRESSION", "YCbCr JPEG", "IMAGE_STRUCTURE" );
6438 : else
6439 21 : SetMetadataItem( "COMPRESSION", "JPEG", "IMAGE_STRUCTURE" );
6440 : }
6441 217 : else if( nCompression == COMPRESSION_NEXT )
6442 0 : SetMetadataItem( "COMPRESSION", "NEXT", "IMAGE_STRUCTURE" );
6443 217 : else if( nCompression == COMPRESSION_CCITTRLEW )
6444 0 : SetMetadataItem( "COMPRESSION", "CCITTRLEW", "IMAGE_STRUCTURE" );
6445 217 : else if( nCompression == COMPRESSION_PACKBITS )
6446 10 : SetMetadataItem( "COMPRESSION", "PACKBITS", "IMAGE_STRUCTURE" );
6447 207 : else if( nCompression == COMPRESSION_THUNDERSCAN )
6448 0 : SetMetadataItem( "COMPRESSION", "THUNDERSCAN", "IMAGE_STRUCTURE" );
6449 207 : else if( nCompression == COMPRESSION_PIXARFILM )
6450 0 : SetMetadataItem( "COMPRESSION", "PIXARFILM", "IMAGE_STRUCTURE" );
6451 207 : else if( nCompression == COMPRESSION_PIXARLOG )
6452 0 : SetMetadataItem( "COMPRESSION", "PIXARLOG", "IMAGE_STRUCTURE" );
6453 207 : else if( nCompression == COMPRESSION_DEFLATE )
6454 64 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
6455 143 : else if( nCompression == COMPRESSION_ADOBE_DEFLATE )
6456 143 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
6457 0 : else if( nCompression == COMPRESSION_DCS )
6458 0 : SetMetadataItem( "COMPRESSION", "DCS", "IMAGE_STRUCTURE" );
6459 0 : else if( nCompression == COMPRESSION_JBIG )
6460 0 : SetMetadataItem( "COMPRESSION", "JBIG", "IMAGE_STRUCTURE" );
6461 0 : else if( nCompression == COMPRESSION_SGILOG )
6462 0 : SetMetadataItem( "COMPRESSION", "SGILOG", "IMAGE_STRUCTURE" );
6463 0 : else if( nCompression == COMPRESSION_SGILOG24 )
6464 0 : SetMetadataItem( "COMPRESSION", "SGILOG24", "IMAGE_STRUCTURE" );
6465 0 : else if( nCompression == COMPRESSION_JP2000 )
6466 0 : SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
6467 0 : else if( nCompression == COMPRESSION_LZMA )
6468 0 : SetMetadataItem( "COMPRESSION", "LZMA", "IMAGE_STRUCTURE" );
6469 :
6470 : else
6471 : {
6472 0 : CPLString oComp;
6473 : SetMetadataItem( "COMPRESSION",
6474 0 : (const char *) oComp.Printf( "%d", nCompression));
6475 : }
6476 :
6477 4554 : if( nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1 )
6478 477 : SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
6479 : else
6480 3600 : SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
6481 :
6482 4077 : if( (GetRasterBand(1)->GetRasterDataType() == GDT_Byte && nBitsPerSample != 8 ) ||
6483 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 && nBitsPerSample != 16) ||
6484 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 && nBitsPerSample != 32) )
6485 : {
6486 1200 : for (int i = 0; i < nBands; ++i)
6487 : GetRasterBand(i+1)->SetMetadataItem( "NBITS",
6488 : CPLString().Printf( "%d", (int)nBitsPerSample ),
6489 357 : "IMAGE_STRUCTURE" );
6490 : }
6491 :
6492 4077 : if( bMinIsWhite )
6493 8 : SetMetadataItem( "MINISWHITE", "YES", "IMAGE_STRUCTURE" );
6494 :
6495 4077 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
6496 : {
6497 193 : CPLXMLNode *psRoot = CPLParseXMLString( pszText );
6498 193 : CPLXMLNode *psItem = NULL;
6499 :
6500 193 : if( psRoot != NULL && psRoot->eType == CXT_Element
6501 : && EQUAL(psRoot->pszValue,"GDALMetadata") )
6502 193 : psItem = psRoot->psChild;
6503 :
6504 940 : for( ; psItem != NULL; psItem = psItem->psNext )
6505 : {
6506 : const char *pszKey, *pszValue, *pszRole, *pszDomain;
6507 : char *pszUnescapedValue;
6508 747 : int nBand, bIsXML = FALSE;
6509 :
6510 747 : if( psItem->eType != CXT_Element
6511 : || !EQUAL(psItem->pszValue,"Item") )
6512 0 : continue;
6513 :
6514 747 : pszKey = CPLGetXMLValue( psItem, "name", NULL );
6515 747 : pszValue = CPLGetXMLValue( psItem, NULL, NULL );
6516 747 : nBand = atoi(CPLGetXMLValue( psItem, "sample", "-1" )) + 1;
6517 747 : pszRole = CPLGetXMLValue( psItem, "role", "" );
6518 747 : pszDomain = CPLGetXMLValue( psItem, "domain", "" );
6519 :
6520 747 : if( pszKey == NULL || pszValue == NULL )
6521 25 : continue;
6522 :
6523 722 : if( EQUALN(pszDomain,"xml:",4) )
6524 2 : bIsXML = TRUE;
6525 :
6526 : pszUnescapedValue = CPLUnescapeString( pszValue, NULL,
6527 722 : CPLES_XML );
6528 722 : if( nBand == 0 )
6529 : {
6530 548 : if( bIsXML )
6531 : {
6532 2 : char *apszMD[2] = { pszUnescapedValue, NULL };
6533 2 : SetMetadata( apszMD, pszDomain );
6534 : }
6535 : else
6536 546 : SetMetadataItem( pszKey, pszUnescapedValue, pszDomain );
6537 : }
6538 : else
6539 : {
6540 174 : GDALRasterBand *poBand = GetRasterBand(nBand);
6541 174 : if( poBand != NULL )
6542 : {
6543 174 : if( EQUAL(pszRole,"scale") )
6544 6 : poBand->SetScale( CPLAtofM(pszUnescapedValue) );
6545 168 : else if( EQUAL(pszRole,"offset") )
6546 6 : poBand->SetOffset( CPLAtofM(pszUnescapedValue) );
6547 162 : else if( EQUAL(pszRole,"unittype") )
6548 13 : poBand->SetUnitType( pszUnescapedValue );
6549 : else
6550 : {
6551 149 : if( bIsXML )
6552 : {
6553 0 : char *apszMD[2] = { pszUnescapedValue, NULL };
6554 0 : poBand->SetMetadata( apszMD, pszDomain );
6555 : }
6556 : else
6557 : poBand->SetMetadataItem(pszKey,pszUnescapedValue,
6558 149 : pszDomain );
6559 : }
6560 : }
6561 : }
6562 722 : CPLFree( pszUnescapedValue );
6563 : }
6564 :
6565 193 : CPLDestroyXMLNode( psRoot );
6566 : }
6567 :
6568 4077 : bMetadataChanged = FALSE;
6569 :
6570 : /* -------------------------------------------------------------------- */
6571 : /* Check for NODATA */
6572 : /* -------------------------------------------------------------------- */
6573 4077 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) )
6574 : {
6575 161 : bNoDataSet = TRUE;
6576 161 : dfNoDataValue = CPLAtofM( pszText );
6577 : }
6578 :
6579 : /* -------------------------------------------------------------------- */
6580 : /* If this is a "base" raster, we should scan for any */
6581 : /* associated overviews, internal mask bands and subdatasets. */
6582 : /* -------------------------------------------------------------------- */
6583 4077 : if( bBase )
6584 : {
6585 : //ScanDirectories();
6586 : }
6587 :
6588 4077 : return( CE_None );
6589 : }
6590 :
6591 : /************************************************************************/
6592 : /* ScanDirectories() */
6593 : /* */
6594 : /* Scan through all the directories finding overviews, masks */
6595 : /* and subdatasets. */
6596 : /************************************************************************/
6597 :
6598 307803 : void GTiffDataset::ScanDirectories()
6599 :
6600 : {
6601 : /* -------------------------------------------------------------------- */
6602 : /* We only scan once. We do not scan for non-base datasets. */
6603 : /* -------------------------------------------------------------------- */
6604 307803 : if( !bScanDeferred )
6605 306520 : return;
6606 :
6607 1283 : bScanDeferred = FALSE;
6608 :
6609 1283 : if( !bBase )
6610 57 : return;
6611 :
6612 1226 : if( TIFFLastDirectory( hTIFF ) )
6613 1094 : return;
6614 :
6615 132 : CPLDebug( "GTiff", "ScanDirectories()" );
6616 :
6617 : /* ==================================================================== */
6618 : /* Scan all directories. */
6619 : /* ==================================================================== */
6620 132 : char **papszSubdatasets = NULL;
6621 132 : int iDirIndex = 0;
6622 :
6623 132 : FlushDirectory();
6624 601 : while( !TIFFLastDirectory( hTIFF )
6625 : && (iDirIndex == 0 || TIFFReadDirectory( hTIFF ) != 0) )
6626 : {
6627 337 : toff_t nThisDir = TIFFCurrentDirOffset(hTIFF);
6628 337 : uint32 nSubType = 0;
6629 :
6630 337 : *ppoActiveDSRef = NULL; // our directory no longer matches this ds
6631 :
6632 337 : iDirIndex++;
6633 :
6634 337 : if( !TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType) )
6635 72 : nSubType = 0;
6636 :
6637 : /* Embedded overview of the main image */
6638 470 : if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
6639 : (nSubType & FILETYPE_MASK) == 0 &&
6640 : iDirIndex != 1 )
6641 : {
6642 : GTiffDataset *poODS;
6643 :
6644 133 : poODS = new GTiffDataset();
6645 266 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
6646 : eAccess ) != CE_None
6647 : || poODS->GetRasterCount() != GetRasterCount() )
6648 : {
6649 0 : delete poODS;
6650 : }
6651 : else
6652 : {
6653 : CPLDebug( "GTiff", "Opened %dx%d overview.\n",
6654 133 : poODS->GetRasterXSize(), poODS->GetRasterYSize());
6655 133 : nOverviewCount++;
6656 : papoOverviewDS = (GTiffDataset **)
6657 : CPLRealloc(papoOverviewDS,
6658 133 : nOverviewCount * (sizeof(void*)));
6659 133 : papoOverviewDS[nOverviewCount-1] = poODS;
6660 133 : poODS->poBaseDS = this;
6661 : }
6662 : }
6663 :
6664 : /* Embedded mask of the main image */
6665 243 : else if ((nSubType & FILETYPE_MASK) != 0 &&
6666 : (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
6667 : poMaskDS == NULL )
6668 : {
6669 39 : poMaskDS = new GTiffDataset();
6670 :
6671 : /* The TIFF6 specification - page 37 - only allows 1 SamplesPerPixel and 1 BitsPerSample
6672 : Here we support either 1 or 8 bit per sample
6673 : and we support either 1 sample per pixel or as many samples as in the main image
6674 : We don't check the value of the PhotometricInterpretation tag, which should be
6675 : set to "Transparency mask" (4) according to the specification (page 36)
6676 : ... But the TIFF6 specification allows image masks to have a higher resolution than
6677 : the main image, what we don't support here
6678 : */
6679 :
6680 78 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir,
6681 : FALSE, eAccess ) != CE_None
6682 : || poMaskDS->GetRasterCount() == 0
6683 : || !(poMaskDS->GetRasterCount() == 1 || poMaskDS->GetRasterCount() == GetRasterCount())
6684 : || poMaskDS->GetRasterXSize() != GetRasterXSize()
6685 : || poMaskDS->GetRasterYSize() != GetRasterYSize()
6686 : || poMaskDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
6687 : {
6688 0 : delete poMaskDS;
6689 0 : poMaskDS = NULL;
6690 : }
6691 : else
6692 : {
6693 39 : CPLDebug( "GTiff", "Opened band mask.\n");
6694 39 : poMaskDS->poBaseDS = this;
6695 :
6696 39 : poMaskDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
6697 : }
6698 : }
6699 :
6700 : /* Embedded mask of an overview */
6701 : /* The TIFF6 specification allows the combination of the FILETYPE_xxxx masks */
6702 197 : else if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
6703 : (nSubType & FILETYPE_MASK) != 0)
6704 : {
6705 32 : GTiffDataset* poDS = new GTiffDataset();
6706 64 : if( poDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
6707 : eAccess ) != CE_None
6708 : || poDS->GetRasterCount() == 0
6709 : || poDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
6710 : {
6711 0 : delete poDS;
6712 : }
6713 : else
6714 : {
6715 : int i;
6716 47 : for(i=0;i<nOverviewCount;i++)
6717 : {
6718 111 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS == NULL &&
6719 32 : poDS->GetRasterXSize() == papoOverviewDS[i]->GetRasterXSize() &&
6720 32 : poDS->GetRasterYSize() == papoOverviewDS[i]->GetRasterYSize() &&
6721 : (poDS->GetRasterCount() == 1 || poDS->GetRasterCount() == GetRasterCount()))
6722 : {
6723 : CPLDebug( "GTiff", "Opened band mask for %dx%d overview.\n",
6724 32 : poDS->GetRasterXSize(), poDS->GetRasterYSize());
6725 32 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS = poDS;
6726 32 : poDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
6727 32 : poDS->poBaseDS = this;
6728 32 : break;
6729 : }
6730 : }
6731 32 : if (i == nOverviewCount)
6732 : {
6733 0 : delete poDS;
6734 : }
6735 : }
6736 : }
6737 133 : else if( nSubType == 0 || nSubType == FILETYPE_PAGE ) {
6738 72 : CPLString osName, osDesc;
6739 : uint32 nXSize, nYSize;
6740 : uint16 nSPP;
6741 :
6742 72 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
6743 72 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
6744 72 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP ) )
6745 0 : nSPP = 1;
6746 :
6747 : osName.Printf( "SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
6748 72 : iDirIndex, iDirIndex, osFilename.c_str() );
6749 : osDesc.Printf( "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
6750 : iDirIndex, iDirIndex,
6751 72 : (int)nXSize, (int)nYSize, nSPP );
6752 :
6753 : papszSubdatasets =
6754 72 : CSLAddString( papszSubdatasets, osName );
6755 : papszSubdatasets =
6756 72 : CSLAddString( papszSubdatasets, osDesc );
6757 : }
6758 :
6759 : // Make sure we are stepping from the expected directory regardless
6760 : // of churn done processing the above.
6761 337 : if( TIFFCurrentDirOffset(hTIFF) != nThisDir )
6762 0 : TIFFSetSubDirectory( hTIFF, nThisDir );
6763 337 : *ppoActiveDSRef = NULL;
6764 : }
6765 :
6766 : /* If we have a mask for the main image, loop over the overviews, and if they */
6767 : /* have a mask, let's set this mask as an overview of the main mask... */
6768 132 : if (poMaskDS != NULL)
6769 : {
6770 : int i;
6771 71 : for(i=0;i<nOverviewCount;i++)
6772 : {
6773 32 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS != NULL)
6774 : {
6775 32 : poMaskDS->nOverviewCount++;
6776 : poMaskDS->papoOverviewDS = (GTiffDataset **)
6777 : CPLRealloc(poMaskDS->papoOverviewDS,
6778 32 : poMaskDS->nOverviewCount * (sizeof(void*)));
6779 32 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] =
6780 32 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS;
6781 : }
6782 : }
6783 : }
6784 :
6785 : /* -------------------------------------------------------------------- */
6786 : /* Only keep track of subdatasets if we have more than one */
6787 : /* subdataset (pair). */
6788 : /* -------------------------------------------------------------------- */
6789 132 : if( CSLCount(papszSubdatasets) > 2 )
6790 : {
6791 1 : oGTiffMDMD.SetMetadata( papszSubdatasets, "SUBDATASETS" );
6792 : }
6793 132 : CSLDestroy( papszSubdatasets );
6794 :
6795 : }
6796 :
6797 :
6798 2287 : static int GTiffGetLZMAPreset(char** papszOptions)
6799 : {
6800 2287 : int nLZMAPreset = -1;
6801 2287 : const char* pszValue = CSLFetchNameValue( papszOptions, "LZMA_PRESET" );
6802 2287 : if( pszValue != NULL )
6803 : {
6804 0 : nLZMAPreset = atoi( pszValue );
6805 0 : if (!(nLZMAPreset >= 0 && nLZMAPreset <= 9))
6806 : {
6807 : CPLError( CE_Warning, CPLE_IllegalArg,
6808 : "LZMA_PRESET=%s value not recognised, ignoring.",
6809 0 : pszValue );
6810 0 : nLZMAPreset = -1;
6811 : }
6812 : }
6813 2287 : return nLZMAPreset;
6814 : }
6815 :
6816 :
6817 2287 : static int GTiffGetZLevel(char** papszOptions)
6818 : {
6819 2287 : int nZLevel = -1;
6820 2287 : const char* pszValue = CSLFetchNameValue( papszOptions, "ZLEVEL" );
6821 2287 : if( pszValue != NULL )
6822 : {
6823 0 : nZLevel = atoi( pszValue );
6824 0 : if (!(nZLevel >= 1 && nZLevel <= 9))
6825 : {
6826 : CPLError( CE_Warning, CPLE_IllegalArg,
6827 : "ZLEVEL=%s value not recognised, ignoring.",
6828 0 : pszValue );
6829 0 : nZLevel = -1;
6830 : }
6831 : }
6832 2287 : return nZLevel;
6833 : }
6834 :
6835 2287 : static int GTiffGetJpegQuality(char** papszOptions)
6836 : {
6837 2287 : int nJpegQuality = -1;
6838 2287 : const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
6839 2287 : if( pszValue != NULL )
6840 : {
6841 28 : nJpegQuality = atoi( pszValue );
6842 28 : if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
6843 : {
6844 : CPLError( CE_Warning, CPLE_IllegalArg,
6845 : "JPEG_QUALITY=%s value not recognised, ignoring.",
6846 0 : pszValue );
6847 0 : nJpegQuality = -1;
6848 : }
6849 : }
6850 2287 : return nJpegQuality;
6851 : }
6852 :
6853 : /************************************************************************/
6854 : /* GTiffCreate() */
6855 : /* */
6856 : /* Shared functionality between GTiffDataset::Create() and */
6857 : /* GTiffCreateCopy() for creating TIFF file based on a set of */
6858 : /* options and a configuration. */
6859 : /************************************************************************/
6860 :
6861 1146 : TIFF *GTiffDataset::CreateLL( const char * pszFilename,
6862 : int nXSize, int nYSize, int nBands,
6863 : GDALDataType eType,
6864 : double dfExtraSpaceForOverviews,
6865 : char **papszParmList )
6866 :
6867 : {
6868 : TIFF *hTIFF;
6869 1146 : int nBlockXSize = 0, nBlockYSize = 0;
6870 1146 : int bTiled = FALSE;
6871 1146 : int nCompression = COMPRESSION_NONE;
6872 1146 : int nPredictor = PREDICTOR_NONE, nJpegQuality = -1, nZLevel = -1,
6873 1146 : nLZMAPreset = -1;
6874 : uint16 nSampleFormat;
6875 : int nPlanar;
6876 : const char *pszValue;
6877 : const char *pszProfile;
6878 1146 : int bCreateBigTIFF = FALSE;
6879 :
6880 1146 : if (!GTiffOneTimeInit())
6881 0 : return NULL;
6882 :
6883 : /* -------------------------------------------------------------------- */
6884 : /* Blow on a few errors. */
6885 : /* -------------------------------------------------------------------- */
6886 1146 : if( nXSize < 1 || nYSize < 1 || nBands < 1 )
6887 : {
6888 : CPLError( CE_Failure, CPLE_AppDefined,
6889 : "Attempt to create %dx%dx%d TIFF file, but width, height and bands\n"
6890 : "must be positive.",
6891 1 : nXSize, nYSize, nBands );
6892 :
6893 1 : return NULL;
6894 : }
6895 :
6896 1145 : if (nBands > 65535)
6897 : {
6898 : CPLError( CE_Failure, CPLE_AppDefined,
6899 : "Attempt to create %dx%dx%d TIFF file, but bands\n"
6900 : "must be lesser or equal to 65535.",
6901 0 : nXSize, nYSize, nBands );
6902 :
6903 0 : return NULL;
6904 : }
6905 :
6906 : /* -------------------------------------------------------------------- */
6907 : /* Setup values based on options. */
6908 : /* -------------------------------------------------------------------- */
6909 1145 : pszProfile = CSLFetchNameValue(papszParmList,"PROFILE");
6910 1145 : if( pszProfile == NULL )
6911 1132 : pszProfile = "GDALGeoTIFF";
6912 :
6913 1145 : if( CSLFetchBoolean( papszParmList, "TILED", FALSE ) )
6914 25 : bTiled = TRUE;
6915 :
6916 1145 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
6917 1145 : if( pszValue != NULL )
6918 12 : nBlockXSize = atoi( pszValue );
6919 :
6920 1145 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
6921 1145 : if( pszValue != NULL )
6922 16 : nBlockYSize = atoi( pszValue );
6923 :
6924 1145 : pszValue = CSLFetchNameValue(papszParmList,"INTERLEAVE");
6925 1145 : if( pszValue != NULL )
6926 : {
6927 25 : if( EQUAL( pszValue, "PIXEL" ) )
6928 13 : nPlanar = PLANARCONFIG_CONTIG;
6929 12 : else if( EQUAL( pszValue, "BAND" ) )
6930 12 : nPlanar = PLANARCONFIG_SEPARATE;
6931 : else
6932 : {
6933 : CPLError( CE_Failure, CPLE_AppDefined,
6934 : "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
6935 0 : pszValue );
6936 0 : return NULL;
6937 : }
6938 : }
6939 : else
6940 : {
6941 1120 : nPlanar = PLANARCONFIG_CONTIG;
6942 : }
6943 :
6944 1145 : pszValue = CSLFetchNameValue( papszParmList, "COMPRESS" );
6945 1145 : if( pszValue != NULL )
6946 : {
6947 54 : nCompression = GTIFFGetCompressionMethod(pszValue, "COMPRESS");
6948 54 : if (nCompression < 0)
6949 0 : return NULL;
6950 : }
6951 :
6952 1145 : pszValue = CSLFetchNameValue( papszParmList, "PREDICTOR" );
6953 1145 : if( pszValue != NULL )
6954 4 : nPredictor = atoi( pszValue );
6955 :
6956 1145 : nZLevel = GTiffGetZLevel(papszParmList);
6957 1145 : nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
6958 1145 : nJpegQuality = GTiffGetJpegQuality(papszParmList);
6959 :
6960 : /* -------------------------------------------------------------------- */
6961 : /* Compute the uncompressed size. */
6962 : /* -------------------------------------------------------------------- */
6963 : double dfUncompressedImageSize;
6964 :
6965 : dfUncompressedImageSize =
6966 1145 : nXSize * ((double)nYSize) * nBands * (GDALGetDataTypeSize(eType)/8);
6967 1145 : dfUncompressedImageSize += dfExtraSpaceForOverviews;
6968 :
6969 1145 : if( nCompression == COMPRESSION_NONE
6970 : && dfUncompressedImageSize > 4200000000.0 )
6971 : {
6972 : #ifndef BIGTIFF_SUPPORT
6973 : CPLError( CE_Failure, CPLE_NotSupported,
6974 : "A %d pixels x %d lines x %d bands %s image would be larger than 4GB\n"
6975 : "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
6976 : "Creation failed.",
6977 : nXSize, nYSize, nBands, GDALGetDataTypeName(eType) );
6978 : return NULL;
6979 : #endif
6980 : }
6981 :
6982 : /* -------------------------------------------------------------------- */
6983 : /* Should the file be created as a bigtiff file? */
6984 : /* -------------------------------------------------------------------- */
6985 1145 : const char *pszBIGTIFF = CSLFetchNameValue(papszParmList, "BIGTIFF");
6986 :
6987 1145 : if( pszBIGTIFF == NULL )
6988 1138 : pszBIGTIFF = "IF_NEEDED";
6989 :
6990 1145 : if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
6991 : {
6992 1139 : if( nCompression == COMPRESSION_NONE
6993 : && dfUncompressedImageSize > 4200000000.0 )
6994 10 : bCreateBigTIFF = TRUE;
6995 : }
6996 6 : else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
6997 : {
6998 4 : if( dfUncompressedImageSize > 2000000000.0 )
6999 1 : bCreateBigTIFF = TRUE;
7000 : }
7001 :
7002 : else
7003 : {
7004 2 : bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
7005 2 : if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE &&
7006 : dfUncompressedImageSize > 4200000000.0 )
7007 : {
7008 : CPLError( CE_Failure, CPLE_NotSupported,
7009 : "The TIFF file will be larger than 4GB, so BigTIFF is necessary.\n"
7010 1 : "Creation failed.");
7011 1 : return NULL;
7012 : }
7013 : }
7014 :
7015 : #ifndef BIGTIFF_SUPPORT
7016 : if( bCreateBigTIFF )
7017 : {
7018 : CPLError( CE_Warning, CPLE_NotSupported,
7019 : "BigTIFF requested, but GDAL built without BigTIFF\n"
7020 : "enabled libtiff, request ignored." );
7021 : bCreateBigTIFF = FALSE;
7022 : }
7023 : #endif
7024 :
7025 1144 : if( bCreateBigTIFF )
7026 12 : CPLDebug( "GTiff", "File being created as a BigTIFF." );
7027 :
7028 : /* -------------------------------------------------------------------- */
7029 : /* Check if the user wishes a particular endianness */
7030 : /* -------------------------------------------------------------------- */
7031 :
7032 1144 : int eEndianness = ENDIANNESS_NATIVE;
7033 1144 : pszValue = CSLFetchNameValue(papszParmList, "ENDIANNESS");
7034 1144 : if ( pszValue == NULL )
7035 1138 : pszValue = CPLGetConfigOption( "GDAL_TIFF_ENDIANNESS", NULL );
7036 1144 : if ( pszValue != NULL )
7037 : {
7038 755 : if (EQUAL(pszValue, "LITTLE"))
7039 6 : eEndianness = ENDIANNESS_LITTLE;
7040 749 : else if (EQUAL(pszValue, "BIG"))
7041 0 : eEndianness = ENDIANNESS_BIG;
7042 749 : else if (EQUAL(pszValue, "INVERTED"))
7043 : {
7044 : #ifdef CPL_LSB
7045 26 : eEndianness = ENDIANNESS_BIG;
7046 : #else
7047 : eEndianness = ENDIANNESS_LITTLE;
7048 : #endif
7049 : }
7050 723 : else if (!EQUAL(pszValue, "NATIVE"))
7051 : {
7052 : CPLError( CE_Warning, CPLE_NotSupported,
7053 0 : "ENDIANNESS=%s not supported. Defaulting to NATIVE", pszValue );
7054 : }
7055 : }
7056 :
7057 : /* -------------------------------------------------------------------- */
7058 : /* Try opening the dataset. */
7059 : /* -------------------------------------------------------------------- */
7060 :
7061 : char szOpeningFlag[5];
7062 1144 : strcpy(szOpeningFlag, "w+");
7063 1144 : if (bCreateBigTIFF)
7064 12 : strcat(szOpeningFlag, "8");
7065 1144 : if (eEndianness == ENDIANNESS_BIG)
7066 26 : strcat(szOpeningFlag, "b");
7067 1118 : else if (eEndianness == ENDIANNESS_LITTLE)
7068 6 : strcat(szOpeningFlag, "l");
7069 1144 : hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag );
7070 1144 : if( hTIFF == NULL )
7071 : {
7072 2 : if( CPLGetLastErrorNo() == 0 )
7073 : CPLError( CE_Failure, CPLE_OpenFailed,
7074 : "Attempt to create new tiff file `%s'\n"
7075 : "failed in XTIFFOpen().\n",
7076 0 : pszFilename );
7077 2 : return NULL;
7078 : }
7079 :
7080 : /* -------------------------------------------------------------------- */
7081 : /* How many bits per sample? We have a special case if NBITS */
7082 : /* specified for GDT_Byte, GDT_UInt16, GDT_UInt32. */
7083 : /* -------------------------------------------------------------------- */
7084 1142 : int nBitsPerSample = GDALGetDataTypeSize(eType);
7085 1142 : if (CSLFetchNameValue(papszParmList, "NBITS") != NULL)
7086 : {
7087 38 : int nMinBits = 0, nMaxBits = 0;
7088 38 : nBitsPerSample = atoi(CSLFetchNameValue(papszParmList, "NBITS"));
7089 38 : if( eType == GDT_Byte )
7090 : {
7091 13 : nMinBits = 1;
7092 13 : nMaxBits = 8;
7093 : }
7094 25 : else if( eType == GDT_UInt16 )
7095 : {
7096 13 : nMinBits = 9;
7097 13 : nMaxBits = 16;
7098 : }
7099 12 : else if( eType == GDT_UInt32 )
7100 : {
7101 12 : nMinBits = 17;
7102 12 : nMaxBits = 32;
7103 : }
7104 : else
7105 : {
7106 : CPLError(CE_Warning, CPLE_NotSupported,
7107 : "NBITS is not supported for data type %s",
7108 0 : GDALGetDataTypeName(eType));
7109 0 : nBitsPerSample = GDALGetDataTypeSize(eType);
7110 : }
7111 :
7112 38 : if (nMinBits != 0)
7113 : {
7114 38 : if (nBitsPerSample < nMinBits)
7115 : {
7116 : CPLError(CE_Warning, CPLE_AppDefined,
7117 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
7118 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMinBits);
7119 0 : nBitsPerSample = nMinBits;
7120 : }
7121 38 : else if (nBitsPerSample > nMaxBits)
7122 : {
7123 : CPLError(CE_Warning, CPLE_AppDefined,
7124 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
7125 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMaxBits);
7126 0 : nBitsPerSample = nMaxBits;
7127 : }
7128 : }
7129 : }
7130 :
7131 : /* -------------------------------------------------------------------- */
7132 : /* Do we have a custom pixel type (just used for signed byte now). */
7133 : /* -------------------------------------------------------------------- */
7134 1142 : const char *pszPixelType = CSLFetchNameValue( papszParmList, "PIXELTYPE" );
7135 1142 : if( pszPixelType == NULL )
7136 1140 : pszPixelType = "";
7137 :
7138 : /* -------------------------------------------------------------------- */
7139 : /* Setup some standard flags. */
7140 : /* -------------------------------------------------------------------- */
7141 1142 : TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
7142 1142 : TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
7143 1142 : TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerSample );
7144 :
7145 1265 : if( (eType == GDT_Byte && EQUAL(pszPixelType,"SIGNEDBYTE"))
7146 : || eType == GDT_Int16 || eType == GDT_Int32 )
7147 123 : nSampleFormat = SAMPLEFORMAT_INT;
7148 1121 : else if( eType == GDT_CInt16 || eType == GDT_CInt32 )
7149 102 : nSampleFormat = SAMPLEFORMAT_COMPLEXINT;
7150 1051 : else if( eType == GDT_Float32 || eType == GDT_Float64 )
7151 134 : nSampleFormat = SAMPLEFORMAT_IEEEFP;
7152 891 : else if( eType == GDT_CFloat32 || eType == GDT_CFloat64 )
7153 108 : nSampleFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
7154 : else
7155 675 : nSampleFormat = SAMPLEFORMAT_UINT;
7156 :
7157 1142 : TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
7158 1142 : TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nBands );
7159 1142 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanar );
7160 :
7161 : /* -------------------------------------------------------------------- */
7162 : /* Setup Photometric Interpretation. Take this value from the user */
7163 : /* passed option or guess correct value otherwise. */
7164 : /* -------------------------------------------------------------------- */
7165 1142 : int nSamplesAccountedFor = 1;
7166 1142 : int bForceColorTable = FALSE;
7167 :
7168 1142 : pszValue = CSLFetchNameValue(papszParmList,"PHOTOMETRIC");
7169 1142 : if( pszValue != NULL )
7170 : {
7171 28 : if( EQUAL( pszValue, "MINISBLACK" ) )
7172 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7173 28 : else if( EQUAL( pszValue, "MINISWHITE" ) )
7174 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE );
7175 26 : else if( EQUAL( pszValue, "PALETTE" ))
7176 : {
7177 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
7178 3 : nSamplesAccountedFor = 1;
7179 3 : bForceColorTable = TRUE;
7180 : }
7181 23 : else if( EQUAL( pszValue, "RGB" ))
7182 : {
7183 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7184 2 : nSamplesAccountedFor = 3;
7185 : }
7186 21 : else if( EQUAL( pszValue, "CMYK" ))
7187 : {
7188 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED );
7189 2 : nSamplesAccountedFor = 4;
7190 : }
7191 19 : else if( EQUAL( pszValue, "YCBCR" ))
7192 : {
7193 : /* Because of subsampling, setting YCBCR without JPEG compression leads */
7194 : /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
7195 : /* aware of subsampling so that it doesn't overrun buffer size returned */
7196 : /* by libtiff */
7197 19 : if ( nCompression != COMPRESSION_JPEG )
7198 : {
7199 : CPLError(CE_Failure, CPLE_NotSupported,
7200 0 : "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
7201 0 : XTIFFClose(hTIFF);
7202 0 : return NULL;
7203 : }
7204 :
7205 19 : if ( nPlanar == PLANARCONFIG_SEPARATE )
7206 : {
7207 : CPLError(CE_Failure, CPLE_NotSupported,
7208 0 : "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
7209 0 : XTIFFClose(hTIFF);
7210 0 : return NULL;
7211 : }
7212 :
7213 : /* YCBCR strictly requires 3 bands. Not less, not more */
7214 : /* Issue an explicit error message as libtiff one is a bit cryptic : */
7215 : /* TIFFVStripSize64:Invalid td_samplesperpixel value */
7216 19 : if ( nBands != 3 )
7217 : {
7218 : CPLError(CE_Failure, CPLE_NotSupported,
7219 0 : "PHOTOMETRIC=YCBCR requires a source raster with only 3 bands (RGB)");
7220 0 : XTIFFClose(hTIFF);
7221 0 : return NULL;
7222 : }
7223 :
7224 19 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR );
7225 19 : nSamplesAccountedFor = 3;
7226 : }
7227 0 : else if( EQUAL( pszValue, "CIELAB" ))
7228 : {
7229 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
7230 0 : nSamplesAccountedFor = 3;
7231 : }
7232 0 : else if( EQUAL( pszValue, "ICCLAB" ))
7233 : {
7234 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ICCLAB );
7235 0 : nSamplesAccountedFor = 3;
7236 : }
7237 0 : else if( EQUAL( pszValue, "ITULAB" ))
7238 : {
7239 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB );
7240 0 : nSamplesAccountedFor = 3;
7241 : }
7242 : else
7243 : {
7244 : CPLError( CE_Warning, CPLE_IllegalArg,
7245 : "PHOTOMETRIC=%s value not recognised, ignoring.\n"
7246 : "Set the Photometric Interpretation as MINISBLACK.",
7247 0 : pszValue );
7248 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7249 : }
7250 :
7251 28 : if ( nBands < nSamplesAccountedFor )
7252 : {
7253 : CPLError( CE_Warning, CPLE_IllegalArg,
7254 : "PHOTOMETRIC=%s value does not correspond to number "
7255 : "of bands (%d), ignoring.\n"
7256 : "Set the Photometric Interpretation as MINISBLACK.",
7257 0 : pszValue, nBands );
7258 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7259 : }
7260 : }
7261 : else
7262 : {
7263 : /*
7264 : * If image contains 3 or 4 bands and datatype is Byte then we will
7265 : * assume it is RGB. In all other cases assume it is MINISBLACK.
7266 : */
7267 1166 : if( nBands == 3 && eType == GDT_Byte )
7268 : {
7269 52 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7270 52 : nSamplesAccountedFor = 3;
7271 : }
7272 1089 : else if( nBands == 4 && eType == GDT_Byte )
7273 : {
7274 : uint16 v[1];
7275 :
7276 27 : v[0] = EXTRASAMPLE_ASSOCALPHA;
7277 27 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
7278 27 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7279 27 : nSamplesAccountedFor = 4;
7280 : }
7281 : else
7282 : {
7283 1035 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7284 1035 : nSamplesAccountedFor = 1;
7285 : }
7286 : }
7287 :
7288 : /* -------------------------------------------------------------------- */
7289 : /* If there are extra samples, we need to mark them with an */
7290 : /* appropriate extrasamples definition here. */
7291 : /* -------------------------------------------------------------------- */
7292 1142 : if( nBands > nSamplesAccountedFor )
7293 : {
7294 : uint16 *v;
7295 : int i;
7296 64 : int nExtraSamples = nBands - nSamplesAccountedFor;
7297 :
7298 64 : v = (uint16 *) CPLMalloc( sizeof(uint16) * nExtraSamples );
7299 :
7300 64 : if( CSLFetchBoolean(papszParmList,"ALPHA",FALSE) )
7301 1 : v[0] = EXTRASAMPLE_ASSOCALPHA;
7302 : else
7303 63 : v[0] = EXTRASAMPLE_UNSPECIFIED;
7304 :
7305 131176 : for( i = 1; i < nExtraSamples; i++ )
7306 131112 : v[i] = EXTRASAMPLE_UNSPECIFIED;
7307 :
7308 64 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, v );
7309 :
7310 64 : CPLFree(v);
7311 : }
7312 :
7313 : /* Set the compression method before asking the default strip size */
7314 : /* This is usefull when translating to a JPEG-In-TIFF file where */
7315 : /* the default strip size is 8 or 16 depending on the photometric value */
7316 1142 : TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompression );
7317 :
7318 : /* -------------------------------------------------------------------- */
7319 : /* Setup tiling/stripping flags. */
7320 : /* -------------------------------------------------------------------- */
7321 1142 : if( bTiled )
7322 : {
7323 25 : if( nBlockXSize == 0 )
7324 13 : nBlockXSize = 256;
7325 :
7326 25 : if( nBlockYSize == 0 )
7327 13 : nBlockYSize = 256;
7328 :
7329 25 : if (!TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ) ||
7330 : !TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ))
7331 : {
7332 0 : XTIFFClose(hTIFF);
7333 0 : return NULL;
7334 : }
7335 : }
7336 : else
7337 : {
7338 : uint32 nRowsPerStrip;
7339 :
7340 1117 : if( nBlockYSize == 0 )
7341 1113 : nRowsPerStrip = MIN(nYSize, (int)TIFFDefaultStripSize(hTIFF,0));
7342 : else
7343 4 : nRowsPerStrip = nBlockYSize;
7344 :
7345 1117 : TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nRowsPerStrip );
7346 : }
7347 :
7348 : /* -------------------------------------------------------------------- */
7349 : /* Set compression related tags. */
7350 : /* -------------------------------------------------------------------- */
7351 1142 : if ( nCompression == COMPRESSION_LZW ||
7352 : nCompression == COMPRESSION_ADOBE_DEFLATE )
7353 26 : TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor );
7354 1142 : if (nCompression == COMPRESSION_ADOBE_DEFLATE
7355 : && nZLevel != -1)
7356 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
7357 1156 : else if( nCompression == COMPRESSION_JPEG
7358 : && nJpegQuality != -1 )
7359 14 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
7360 1128 : else if( nCompression == COMPRESSION_LZMA && nLZMAPreset != -1)
7361 0 : TIFFSetField( hTIFF, TIFFTAG_LZMAPRESET, nLZMAPreset );
7362 :
7363 : /* -------------------------------------------------------------------- */
7364 : /* If we forced production of a file with photometric=palette, */
7365 : /* we need to push out a default color table. */
7366 : /* -------------------------------------------------------------------- */
7367 1142 : if( bForceColorTable )
7368 : {
7369 : int nColors;
7370 :
7371 3 : if( eType == GDT_Byte )
7372 3 : nColors = 256;
7373 : else
7374 0 : nColors = 65536;
7375 :
7376 : unsigned short *panTRed, *panTGreen, *panTBlue;
7377 :
7378 3 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7379 3 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7380 3 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7381 :
7382 771 : for( int iColor = 0; iColor < nColors; iColor++ )
7383 : {
7384 768 : if( eType == GDT_Byte )
7385 : {
7386 768 : panTRed[iColor] = (unsigned short) (257 * iColor);
7387 768 : panTGreen[iColor] = (unsigned short) (257 * iColor);
7388 768 : panTBlue[iColor] = (unsigned short) (257 * iColor);
7389 : }
7390 : else
7391 : {
7392 0 : panTRed[iColor] = (unsigned short) iColor;
7393 0 : panTGreen[iColor] = (unsigned short) iColor;
7394 0 : panTBlue[iColor] = (unsigned short) iColor;
7395 : }
7396 : }
7397 :
7398 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
7399 3 : panTRed, panTGreen, panTBlue );
7400 :
7401 3 : CPLFree( panTRed );
7402 3 : CPLFree( panTGreen );
7403 3 : CPLFree( panTBlue );
7404 : }
7405 :
7406 1142 : return( hTIFF );
7407 : }
7408 :
7409 : /************************************************************************/
7410 : /* Create() */
7411 : /* */
7412 : /* Create a new GeoTIFF or TIFF file. */
7413 : /************************************************************************/
7414 :
7415 946 : GDALDataset *GTiffDataset::Create( const char * pszFilename,
7416 : int nXSize, int nYSize, int nBands,
7417 : GDALDataType eType,
7418 : char **papszParmList )
7419 :
7420 : {
7421 : GTiffDataset * poDS;
7422 : TIFF *hTIFF;
7423 :
7424 : /* -------------------------------------------------------------------- */
7425 : /* Create the underlying TIFF file. */
7426 : /* -------------------------------------------------------------------- */
7427 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
7428 946 : eType, 0, papszParmList );
7429 :
7430 946 : if( hTIFF == NULL )
7431 2 : return NULL;
7432 :
7433 : /* -------------------------------------------------------------------- */
7434 : /* Create the new GTiffDataset object. */
7435 : /* -------------------------------------------------------------------- */
7436 944 : poDS = new GTiffDataset();
7437 944 : poDS->hTIFF = hTIFF;
7438 944 : poDS->poActiveDS = poDS;
7439 944 : poDS->ppoActiveDSRef = &(poDS->poActiveDS);
7440 :
7441 944 : poDS->nRasterXSize = nXSize;
7442 944 : poDS->nRasterYSize = nYSize;
7443 944 : poDS->eAccess = GA_Update;
7444 944 : poDS->bCrystalized = FALSE;
7445 944 : poDS->nSamplesPerPixel = (uint16) nBands;
7446 1888 : poDS->osFilename = pszFilename;
7447 :
7448 : /* Avoid premature crystalization that will cause directory re-writting */
7449 : /* if GetProjectionRef() or GetGeoTransform() are called on the newly created GeoTIFF */
7450 944 : poDS->bLookedForProjection = TRUE;
7451 :
7452 944 : TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->nSampleFormat) );
7453 944 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->nPlanarConfig) );
7454 944 : TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) );
7455 944 : TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->nBitsPerSample) );
7456 944 : TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(poDS->nCompression) );
7457 :
7458 944 : if( TIFFIsTiled(hTIFF) )
7459 : {
7460 20 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(poDS->nBlockXSize) );
7461 20 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(poDS->nBlockYSize) );
7462 : }
7463 : else
7464 : {
7465 924 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
7466 : &(poDS->nRowsPerStrip) ) )
7467 0 : poDS->nRowsPerStrip = 1; /* dummy value */
7468 :
7469 924 : poDS->nBlockXSize = nXSize;
7470 924 : poDS->nBlockYSize = MIN((int)poDS->nRowsPerStrip,nYSize);
7471 : }
7472 :
7473 : poDS->nBlocksPerBand =
7474 : ((nYSize + poDS->nBlockYSize - 1) / poDS->nBlockYSize)
7475 944 : * ((nXSize + poDS->nBlockXSize - 1) / poDS->nBlockXSize);
7476 :
7477 944 : if( CSLFetchNameValue( papszParmList, "PROFILE" ) != NULL )
7478 4 : poDS->osProfile = CSLFetchNameValue( papszParmList, "PROFILE" );
7479 :
7480 : /* -------------------------------------------------------------------- */
7481 : /* YCbCr JPEG compressed images should be translated on the fly */
7482 : /* to RGB by libtiff/libjpeg unless specifically requested */
7483 : /* otherwise. */
7484 : /* -------------------------------------------------------------------- */
7485 944 : if( poDS->nCompression == COMPRESSION_JPEG
7486 : && poDS->nPhotometric == PHOTOMETRIC_YCBCR
7487 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
7488 : "YES") ) )
7489 : {
7490 : int nColorMode;
7491 :
7492 13 : poDS->SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
7493 13 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
7494 : nColorMode != JPEGCOLORMODE_RGB )
7495 13 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
7496 : }
7497 :
7498 : /* -------------------------------------------------------------------- */
7499 : /* Read palette back as a color table if it has one. */
7500 : /* -------------------------------------------------------------------- */
7501 : unsigned short *panRed, *panGreen, *panBlue;
7502 :
7503 944 : if( poDS->nPhotometric == PHOTOMETRIC_PALETTE
7504 : && TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
7505 : &panRed, &panGreen, &panBlue) )
7506 : {
7507 : int nColorCount;
7508 : GDALColorEntry oEntry;
7509 :
7510 3 : poDS->poColorTable = new GDALColorTable();
7511 :
7512 3 : nColorCount = 1 << poDS->nBitsPerSample;
7513 :
7514 771 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
7515 : {
7516 768 : oEntry.c1 = panRed[iColor] / 256;
7517 768 : oEntry.c2 = panGreen[iColor] / 256;
7518 768 : oEntry.c3 = panBlue[iColor] / 256;
7519 768 : oEntry.c4 = 255;
7520 :
7521 768 : poDS->poColorTable->SetColorEntry( iColor, &oEntry );
7522 : }
7523 : }
7524 :
7525 : /* -------------------------------------------------------------------- */
7526 : /* Do we want to ensure all blocks get written out on close to */
7527 : /* avoid sparse files? */
7528 : /* -------------------------------------------------------------------- */
7529 944 : if( !CSLFetchBoolean( papszParmList, "SPARSE_OK", FALSE ) )
7530 926 : poDS->bFillEmptyTiles = TRUE;
7531 :
7532 : /* -------------------------------------------------------------------- */
7533 : /* Preserve creation options for consulting later (for instance */
7534 : /* to decide if a TFW file should be written). */
7535 : /* -------------------------------------------------------------------- */
7536 944 : poDS->papszCreationOptions = CSLDuplicate( papszParmList );
7537 :
7538 944 : poDS->nZLevel = GTiffGetZLevel(papszParmList);
7539 944 : poDS->nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
7540 944 : poDS->nJpegQuality = GTiffGetJpegQuality(papszParmList);
7541 :
7542 : /* -------------------------------------------------------------------- */
7543 : /* If we are writing jpeg compression we need to write some */
7544 : /* imagery to force the jpegtables to get created. This is, */
7545 : /* likely only needed with libtiff >= 3.9.3 (#3633) */
7546 : /* -------------------------------------------------------------------- */
7547 944 : if( poDS->nCompression == COMPRESSION_JPEG
7548 : && strstr(TIFFLIB_VERSION_STR, "Version 3.9") != NULL )
7549 : {
7550 : CPLDebug( "GDAL",
7551 0 : "Writing zero block to force creation of JPEG tables." );
7552 0 : if( TIFFIsTiled( hTIFF ) )
7553 : {
7554 0 : int cc = TIFFTileSize( hTIFF );
7555 0 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
7556 0 : TIFFWriteEncodedTile(hTIFF, 0, pabyZeros, cc);
7557 0 : CPLFree( pabyZeros );
7558 : }
7559 : else
7560 : {
7561 0 : int cc = TIFFStripSize( hTIFF );
7562 0 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
7563 0 : TIFFWriteEncodedStrip(hTIFF, 0, pabyZeros, cc);
7564 0 : CPLFree( pabyZeros );
7565 : }
7566 0 : poDS->bDontReloadFirstBlock = TRUE;
7567 : }
7568 :
7569 : /* -------------------------------------------------------------------- */
7570 : /* Create band information objects. */
7571 : /* -------------------------------------------------------------------- */
7572 : int iBand;
7573 :
7574 133184 : for( iBand = 0; iBand < nBands; iBand++ )
7575 : {
7576 264457 : if( poDS->nBitsPerSample == 8 ||
7577 : poDS->nBitsPerSample == 16 ||
7578 : poDS->nBitsPerSample == 32 ||
7579 : poDS->nBitsPerSample == 64 ||
7580 : poDS->nBitsPerSample == 128)
7581 132217 : poDS->SetBand( iBand+1, new GTiffRasterBand( poDS, iBand+1 ) );
7582 : else
7583 : {
7584 23 : poDS->SetBand( iBand+1, new GTiffOddBitsBand( poDS, iBand+1 ) );
7585 : poDS->GetRasterBand( iBand+1 )->
7586 : SetMetadataItem( "NBITS",
7587 : CPLString().Printf("%d",poDS->nBitsPerSample),
7588 46 : "IMAGE_STRUCTURE" );
7589 : }
7590 : }
7591 :
7592 944 : poDS->oOvManager.Initialize( poDS, pszFilename );
7593 :
7594 944 : return( poDS );
7595 : }
7596 :
7597 : /************************************************************************/
7598 : /* CreateCopy() */
7599 : /************************************************************************/
7600 :
7601 : GDALDataset *
7602 201 : GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
7603 : int bStrict, char ** papszOptions,
7604 : GDALProgressFunc pfnProgress, void * pProgressData )
7605 :
7606 : {
7607 : TIFF *hTIFF;
7608 201 : int nXSize = poSrcDS->GetRasterXSize();
7609 201 : int nYSize = poSrcDS->GetRasterYSize();
7610 201 : int nBands = poSrcDS->GetRasterCount();
7611 : int iBand;
7612 201 : CPLErr eErr = CE_None;
7613 : uint16 nPlanarConfig;
7614 : uint16 nBitsPerSample;
7615 : GDALRasterBand *poPBand;
7616 :
7617 201 : if( poSrcDS->GetRasterCount() == 0 )
7618 : {
7619 : CPLError( CE_Failure, CPLE_AppDefined,
7620 1 : "Unable to export GeoTIFF files with zero bands." );
7621 1 : return NULL;
7622 : }
7623 :
7624 200 : poPBand = poSrcDS->GetRasterBand(1);
7625 200 : GDALDataType eType = poPBand->GetRasterDataType();
7626 :
7627 : /* -------------------------------------------------------------------- */
7628 : /* Check, whether all bands in input dataset has the same type. */
7629 : /* -------------------------------------------------------------------- */
7630 313 : for ( iBand = 2; iBand <= nBands; iBand++ )
7631 : {
7632 113 : if ( eType != poSrcDS->GetRasterBand(iBand)->GetRasterDataType() )
7633 : {
7634 0 : if ( bStrict )
7635 : {
7636 : CPLError( CE_Failure, CPLE_AppDefined,
7637 : "Unable to export GeoTIFF file with different datatypes per\n"
7638 0 : "different bands. All bands should have the same types in TIFF." );
7639 0 : return NULL;
7640 : }
7641 : else
7642 : {
7643 : CPLError( CE_Warning, CPLE_AppDefined,
7644 : "Unable to export GeoTIFF file with different datatypes per\n"
7645 0 : "different bands. All bands should have the same types in TIFF." );
7646 : }
7647 : }
7648 : }
7649 :
7650 200 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
7651 0 : return NULL;
7652 :
7653 : /* -------------------------------------------------------------------- */
7654 : /* Capture the profile. */
7655 : /* -------------------------------------------------------------------- */
7656 : const char *pszProfile;
7657 : int bGeoTIFF;
7658 :
7659 200 : pszProfile = CSLFetchNameValue(papszOptions,"PROFILE");
7660 200 : if( pszProfile == NULL )
7661 191 : pszProfile = "GDALGeoTIFF";
7662 :
7663 200 : if( !EQUAL(pszProfile,"BASELINE")
7664 : && !EQUAL(pszProfile,"GeoTIFF")
7665 : && !EQUAL(pszProfile,"GDALGeoTIFF") )
7666 : {
7667 : CPLError( CE_Failure, CPLE_AppDefined,
7668 : "PROFILE=%s not supported in GTIFF driver.",
7669 0 : pszProfile );
7670 0 : return NULL;
7671 : }
7672 :
7673 200 : if( EQUAL(pszProfile,"BASELINE") )
7674 6 : bGeoTIFF = FALSE;
7675 : else
7676 194 : bGeoTIFF = TRUE;
7677 :
7678 : /* -------------------------------------------------------------------- */
7679 : /* Special handling for NBITS. Copy from band metadata if found. */
7680 : /* -------------------------------------------------------------------- */
7681 200 : char **papszCreateOptions = CSLDuplicate( papszOptions );
7682 :
7683 205 : if( poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
7684 5 : && atoi(poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) > 0
7685 : && CSLFetchNameValue( papszCreateOptions, "NBITS") == NULL )
7686 : {
7687 : papszCreateOptions =
7688 : CSLSetNameValue( papszCreateOptions, "NBITS",
7689 : poPBand->GetMetadataItem( "NBITS",
7690 3 : "IMAGE_STRUCTURE" ) );
7691 : }
7692 :
7693 325 : if( CSLFetchNameValue( papszOptions, "PIXELTYPE" ) == NULL
7694 : && eType == GDT_Byte
7695 125 : && poPBand->GetMetadataItem( "PIXELTYPE", "IMAGE_STRUCTURE" ) )
7696 : {
7697 : papszCreateOptions =
7698 : CSLSetNameValue( papszCreateOptions, "PIXELTYPE",
7699 : poPBand->GetMetadataItem(
7700 0 : "PIXELTYPE", "IMAGE_STRUCTURE" ) );
7701 : }
7702 :
7703 200 : int nSrcOverviews = poSrcDS->GetRasterBand(1)->GetOverviewCount();
7704 200 : double dfExtraSpaceForOverviews = 0;
7705 200 : if (nSrcOverviews != 0 &&
7706 : CSLFetchBoolean(papszOptions, "COPY_SRC_OVERVIEWS", FALSE))
7707 : {
7708 : int i;
7709 18 : for(i=0;i<nSrcOverviews;i++)
7710 : {
7711 13 : dfExtraSpaceForOverviews += ((double)poSrcDS->GetRasterBand(1)->GetOverview(i)->GetXSize()) *
7712 26 : poSrcDS->GetRasterBand(1)->GetOverview(i)->GetYSize();
7713 : }
7714 5 : dfExtraSpaceForOverviews *= nBands * (GDALGetDataTypeSize(eType) / 8);
7715 : }
7716 :
7717 : /* -------------------------------------------------------------------- */
7718 : /* Create the file. */
7719 : /* -------------------------------------------------------------------- */
7720 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
7721 200 : eType, dfExtraSpaceForOverviews, papszCreateOptions );
7722 :
7723 200 : CSLDestroy( papszCreateOptions );
7724 :
7725 200 : if( hTIFF == NULL )
7726 2 : return NULL;
7727 :
7728 198 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
7729 198 : TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample );
7730 :
7731 : /* -------------------------------------------------------------------- */
7732 : /* Are we really producing an RGBA image? If so, set the */
7733 : /* associated alpha information. */
7734 : /* -------------------------------------------------------------------- */
7735 : int bForcePhotometric =
7736 198 : CSLFetchNameValue(papszOptions,"PHOTOMETRIC") != NULL;
7737 :
7738 203 : if( nBands == 4 && !bForcePhotometric
7739 5 : && poSrcDS->GetRasterBand(4)->GetColorInterpretation()==GCI_AlphaBand)
7740 : {
7741 : uint16 v[1];
7742 :
7743 3 : v[0] = EXTRASAMPLE_ASSOCALPHA;
7744 3 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
7745 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7746 : }
7747 :
7748 : /* -------------------------------------------------------------------- */
7749 : /* If the output is jpeg compressed, and the input is RGB make */
7750 : /* sure we note that. */
7751 : /* -------------------------------------------------------------------- */
7752 : uint16 nCompression;
7753 :
7754 198 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
7755 0 : nCompression = COMPRESSION_NONE;
7756 :
7757 198 : if( nCompression == COMPRESSION_JPEG )
7758 : {
7759 17 : if( nBands >= 3
7760 8 : && (poSrcDS->GetRasterBand(1)->GetColorInterpretation()
7761 : == GCI_YCbCr_YBand)
7762 0 : && (poSrcDS->GetRasterBand(2)->GetColorInterpretation()
7763 : == GCI_YCbCr_CbBand)
7764 0 : && (poSrcDS->GetRasterBand(3)->GetColorInterpretation()
7765 : == GCI_YCbCr_CrBand) )
7766 : {
7767 : /* do nothing ... */
7768 : }
7769 : else
7770 : {
7771 : /* we assume RGB if it isn't explicitly YCbCr */
7772 9 : CPLDebug( "GTiff", "Setting JPEGCOLORMODE_RGB" );
7773 9 : TIFFSetField( hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
7774 : }
7775 : }
7776 :
7777 : /* -------------------------------------------------------------------- */
7778 : /* Does the source image consist of one band, with a palette? */
7779 : /* If so, copy over. */
7780 : /* -------------------------------------------------------------------- */
7781 198 : if( (nBands == 1 || nBands == 2) && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
7782 : && eType == GDT_Byte )
7783 : {
7784 : unsigned short anTRed[256], anTGreen[256], anTBlue[256];
7785 : GDALColorTable *poCT;
7786 :
7787 4 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
7788 :
7789 1028 : for( int iColor = 0; iColor < 256; iColor++ )
7790 : {
7791 1024 : if( iColor < poCT->GetColorEntryCount() )
7792 : {
7793 : GDALColorEntry sRGB;
7794 :
7795 477 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
7796 :
7797 477 : anTRed[iColor] = (unsigned short) (257 * sRGB.c1);
7798 477 : anTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
7799 477 : anTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
7800 : }
7801 : else
7802 : {
7803 547 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
7804 : }
7805 : }
7806 :
7807 4 : if( !bForcePhotometric )
7808 4 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
7809 4 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, anTRed, anTGreen, anTBlue );
7810 : }
7811 340 : else if( (nBands == 1 || nBands == 2)
7812 146 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
7813 : && eType == GDT_UInt16 )
7814 : {
7815 : unsigned short *panTRed, *panTGreen, *panTBlue;
7816 : GDALColorTable *poCT;
7817 :
7818 1 : panTRed = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
7819 1 : panTGreen = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
7820 1 : panTBlue = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
7821 :
7822 1 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
7823 :
7824 65537 : for( int iColor = 0; iColor < 65536; iColor++ )
7825 : {
7826 65536 : if( iColor < poCT->GetColorEntryCount() )
7827 : {
7828 : GDALColorEntry sRGB;
7829 :
7830 65536 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
7831 :
7832 65536 : panTRed[iColor] = (unsigned short) (256 * sRGB.c1);
7833 65536 : panTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
7834 65536 : panTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
7835 : }
7836 : else
7837 : {
7838 0 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
7839 : }
7840 : }
7841 :
7842 1 : if( !bForcePhotometric )
7843 1 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
7844 1 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue );
7845 :
7846 1 : CPLFree( panTRed );
7847 1 : CPLFree( panTGreen );
7848 1 : CPLFree( panTBlue );
7849 : }
7850 193 : else if( poSrcDS->GetRasterBand(1)->GetColorTable() != NULL )
7851 : CPLError( CE_Warning, CPLE_AppDefined,
7852 : "Unable to export color table to GeoTIFF file. Color tables\n"
7853 0 : "can only be written to 1 band or 2 bands Byte or UInt16 GeoTIFF files." );
7854 :
7855 204 : if( nBands == 2
7856 6 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
7857 : && (eType == GDT_Byte || eType == GDT_UInt16) )
7858 : {
7859 1 : uint16 v[1] = { EXTRASAMPLE_UNASSALPHA };
7860 :
7861 1 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v );
7862 : }
7863 :
7864 : /* -------------------------------------------------------------------- */
7865 : /* Transfer some TIFF specific metadata, if available. */
7866 : /* The return value will tell us if we need to try again later with*/
7867 : /* PAM because the profile doesn't allow to write some metadata */
7868 : /* as TIFF tag */
7869 : /* -------------------------------------------------------------------- */
7870 : int bHasWrittenMDInGeotiffTAG =
7871 : GTiffDataset::WriteMetadata( poSrcDS, hTIFF, FALSE, pszProfile,
7872 198 : pszFilename, papszOptions );
7873 :
7874 : /* -------------------------------------------------------------------- */
7875 : /* Write NoData value, if exist. */
7876 : /* -------------------------------------------------------------------- */
7877 198 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
7878 : {
7879 : int bSuccess;
7880 : double dfNoData;
7881 :
7882 190 : dfNoData = poSrcDS->GetRasterBand(1)->GetNoDataValue( &bSuccess );
7883 190 : if ( bSuccess )
7884 21 : GTiffDataset::WriteNoDataValue( hTIFF, dfNoData );
7885 : }
7886 :
7887 : /* -------------------------------------------------------------------- */
7888 : /* Are we addressing PixelIsPoint mode? */
7889 : /* -------------------------------------------------------------------- */
7890 198 : bool bPixelIsPoint = false;
7891 198 : int bPointGeoIgnore = FALSE;
7892 :
7893 306 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
7894 108 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
7895 : GDALMD_AOP_POINT) )
7896 : {
7897 6 : bPixelIsPoint = true;
7898 : bPointGeoIgnore =
7899 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
7900 6 : "FALSE") );
7901 : }
7902 :
7903 : /* -------------------------------------------------------------------- */
7904 : /* Write affine transform if it is meaningful. */
7905 : /* -------------------------------------------------------------------- */
7906 198 : const char *pszProjection = NULL;
7907 : double adfGeoTransform[6];
7908 :
7909 335 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
7910 137 : && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
7911 0 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
7912 0 : || adfGeoTransform[4] != 0.0 || adfGeoTransform[5] != 1.0 ))
7913 : {
7914 137 : if( bGeoTIFF )
7915 : {
7916 395 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
7917 131 : && adfGeoTransform[5] < 0.0 )
7918 : {
7919 :
7920 : double adfPixelScale[3], adfTiePoints[6];
7921 :
7922 131 : adfPixelScale[0] = adfGeoTransform[1];
7923 131 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
7924 131 : adfPixelScale[2] = 0.0;
7925 :
7926 131 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
7927 :
7928 131 : adfTiePoints[0] = 0.0;
7929 131 : adfTiePoints[1] = 0.0;
7930 131 : adfTiePoints[2] = 0.0;
7931 131 : adfTiePoints[3] = adfGeoTransform[0];
7932 131 : adfTiePoints[4] = adfGeoTransform[3];
7933 131 : adfTiePoints[5] = 0.0;
7934 :
7935 131 : if( bPixelIsPoint && !bPointGeoIgnore )
7936 : {
7937 4 : adfTiePoints[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
7938 4 : adfTiePoints[4] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
7939 : }
7940 :
7941 131 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
7942 : }
7943 : else
7944 : {
7945 : double adfMatrix[16];
7946 :
7947 2 : memset(adfMatrix,0,sizeof(double) * 16);
7948 :
7949 2 : adfMatrix[0] = adfGeoTransform[1];
7950 2 : adfMatrix[1] = adfGeoTransform[2];
7951 2 : adfMatrix[3] = adfGeoTransform[0];
7952 2 : adfMatrix[4] = adfGeoTransform[4];
7953 2 : adfMatrix[5] = adfGeoTransform[5];
7954 2 : adfMatrix[7] = adfGeoTransform[3];
7955 2 : adfMatrix[15] = 1.0;
7956 :
7957 2 : if( bPixelIsPoint && !bPointGeoIgnore )
7958 : {
7959 0 : adfMatrix[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
7960 0 : adfMatrix[7] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
7961 : }
7962 :
7963 2 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
7964 : }
7965 :
7966 133 : pszProjection = poSrcDS->GetProjectionRef();
7967 : }
7968 :
7969 : /* -------------------------------------------------------------------- */
7970 : /* Do we need a TFW file? */
7971 : /* -------------------------------------------------------------------- */
7972 137 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE ) )
7973 1 : GDALWriteWorldFile( pszFilename, "tfw", adfGeoTransform );
7974 136 : else if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
7975 1 : GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
7976 : }
7977 :
7978 : /* -------------------------------------------------------------------- */
7979 : /* Otherwise write tiepoints if they are available. */
7980 : /* -------------------------------------------------------------------- */
7981 61 : else if( poSrcDS->GetGCPCount() > 0 && bGeoTIFF )
7982 : {
7983 3 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
7984 : double *padfTiePoints;
7985 :
7986 : padfTiePoints = (double *)
7987 3 : CPLMalloc(6*sizeof(double)*poSrcDS->GetGCPCount());
7988 :
7989 15 : for( int iGCP = 0; iGCP < poSrcDS->GetGCPCount(); iGCP++ )
7990 : {
7991 :
7992 12 : padfTiePoints[iGCP*6+0] = pasGCPs[iGCP].dfGCPPixel;
7993 12 : padfTiePoints[iGCP*6+1] = pasGCPs[iGCP].dfGCPLine;
7994 12 : padfTiePoints[iGCP*6+2] = 0;
7995 12 : padfTiePoints[iGCP*6+3] = pasGCPs[iGCP].dfGCPX;
7996 12 : padfTiePoints[iGCP*6+4] = pasGCPs[iGCP].dfGCPY;
7997 12 : padfTiePoints[iGCP*6+5] = pasGCPs[iGCP].dfGCPZ;
7998 :
7999 12 : if( bPixelIsPoint && !bPointGeoIgnore )
8000 : {
8001 0 : padfTiePoints[iGCP*6+0] += 0.5;
8002 0 : padfTiePoints[iGCP*6+1] += 0.5;
8003 : }
8004 : }
8005 :
8006 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
8007 3 : 6*poSrcDS->GetGCPCount(), padfTiePoints );
8008 3 : CPLFree( padfTiePoints );
8009 :
8010 3 : pszProjection = poSrcDS->GetGCPProjection();
8011 :
8012 3 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE )
8013 : || CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
8014 : {
8015 : CPLError(CE_Warning, CPLE_AppDefined,
8016 0 : "TFW=ON or WORLDFILE=ON creation options are ignored when GCPs are available");
8017 : }
8018 : }
8019 :
8020 : else
8021 58 : pszProjection = poSrcDS->GetProjectionRef();
8022 :
8023 : /* -------------------------------------------------------------------- */
8024 : /* Write the projection information, if possible. */
8025 : /* -------------------------------------------------------------------- */
8026 198 : if( pszProjection != NULL && strlen(pszProjection) > 0 && bGeoTIFF )
8027 : {
8028 : GTIF *psGTIF;
8029 :
8030 134 : psGTIF = GTIFNew( hTIFF );
8031 134 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
8032 :
8033 239 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
8034 105 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
8035 : GDALMD_AOP_POINT) )
8036 : {
8037 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
8038 6 : RasterPixelIsPoint);
8039 : }
8040 :
8041 134 : GTIFWriteKeys( psGTIF );
8042 134 : GTIFFree( psGTIF );
8043 : }
8044 :
8045 : /* -------------------------------------------------------------------- */
8046 : /* If we are writing jpeg compression we need to write some */
8047 : /* imagery to force the jpegtables to get created. This is, */
8048 : /* likely only needed with libtiff >= 3.9.3 (#3633) */
8049 : /* -------------------------------------------------------------------- */
8050 198 : int bDontReloadFirstBlock = FALSE;
8051 198 : if( nCompression == COMPRESSION_JPEG
8052 : && strstr(TIFFLIB_VERSION_STR, "Version 3.9") != NULL )
8053 : {
8054 : CPLDebug( "GDAL",
8055 0 : "Writing zero block to force creation of JPEG tables." );
8056 0 : if( TIFFIsTiled( hTIFF ) )
8057 : {
8058 0 : int cc = TIFFTileSize( hTIFF );
8059 0 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
8060 0 : TIFFWriteEncodedTile(hTIFF, 0, pabyZeros, cc);
8061 0 : CPLFree( pabyZeros );
8062 : }
8063 : else
8064 : {
8065 0 : int cc = TIFFStripSize( hTIFF );
8066 0 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
8067 0 : TIFFWriteEncodedStrip(hTIFF, 0, pabyZeros, cc);
8068 0 : CPLFree( pabyZeros );
8069 : }
8070 0 : bDontReloadFirstBlock = TRUE;
8071 : }
8072 :
8073 : /* -------------------------------------------------------------------- */
8074 : /* Cleanup */
8075 : /* -------------------------------------------------------------------- */
8076 :
8077 198 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffCreateCopy()");
8078 198 : TIFFWriteDirectory( hTIFF );
8079 198 : TIFFFlush( hTIFF );
8080 198 : XTIFFClose( hTIFF );
8081 198 : hTIFF = NULL;
8082 :
8083 198 : if( eErr != CE_None )
8084 : {
8085 0 : VSIUnlink( pszFilename );
8086 0 : return NULL;
8087 : }
8088 :
8089 : /* -------------------------------------------------------------------- */
8090 : /* Re-open as a dataset and copy over missing metadata using */
8091 : /* PAM facilities. */
8092 : /* -------------------------------------------------------------------- */
8093 : GTiffDataset *poDS;
8094 198 : CPLString osFileName("GTIFF_RAW:");
8095 :
8096 198 : osFileName += pszFilename;
8097 :
8098 198 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_Update );
8099 198 : if( poDS == NULL )
8100 0 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_ReadOnly );
8101 :
8102 198 : if ( poDS == NULL )
8103 : {
8104 0 : VSIUnlink( pszFilename );
8105 0 : return NULL;
8106 : }
8107 :
8108 198 : poDS->osProfile = pszProfile;
8109 198 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & ~GCIF_MASK );
8110 198 : poDS->papszCreationOptions = CSLDuplicate( papszOptions );
8111 198 : poDS->bDontReloadFirstBlock = bDontReloadFirstBlock;
8112 :
8113 : /* -------------------------------------------------------------------- */
8114 : /* CloneInfo() doesn't merge metadata, it just replaces it totally */
8115 : /* So we have to merge it */
8116 : /* -------------------------------------------------------------------- */
8117 :
8118 198 : char **papszSRC_MD = poSrcDS->GetMetadata();
8119 198 : char **papszDST_MD = CSLDuplicate(poDS->GetMetadata());
8120 :
8121 198 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
8122 :
8123 198 : poDS->SetMetadata( papszDST_MD );
8124 198 : CSLDestroy( papszDST_MD );
8125 :
8126 : /* Depending on the PHOTOMETRIC tag, the TIFF file may not have */
8127 : /* the same band count as the source. Will fail later in GDALDatasetCopyWholeRaster anyway... */
8128 509 : for( int nBand = 1;
8129 : nBand <= MIN(poDS->GetRasterCount(), poSrcDS->GetRasterCount()) ;
8130 : nBand++ )
8131 : {
8132 311 : GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(nBand);
8133 311 : GDALRasterBand* poDstBand = poDS->GetRasterBand(nBand);
8134 311 : char **papszSRC_MD = poSrcBand->GetMetadata();
8135 311 : char **papszDST_MD = CSLDuplicate(poDstBand->GetMetadata());
8136 :
8137 311 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
8138 :
8139 311 : poDstBand->SetMetadata( papszDST_MD );
8140 311 : CSLDestroy( papszDST_MD );
8141 :
8142 : char** papszCatNames;
8143 311 : papszCatNames = poSrcBand->GetCategoryNames();
8144 311 : if (NULL != papszCatNames)
8145 0 : poDstBand->SetCategoryNames( papszCatNames );
8146 : }
8147 :
8148 198 : hTIFF = (TIFF*) poDS->GetInternalHandle(NULL);
8149 :
8150 : /* -------------------------------------------------------------------- */
8151 : /* Handle forcing xml:ESRI data to be written to PAM. */
8152 : /* -------------------------------------------------------------------- */
8153 198 : if( CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
8154 : {
8155 1 : char **papszESRIMD = poSrcDS->GetMetadata("xml:ESRI");
8156 1 : if( papszESRIMD )
8157 : {
8158 1 : poDS->SetMetadata( papszESRIMD, "xml:ESRI");
8159 : }
8160 : }
8161 :
8162 : /* -------------------------------------------------------------------- */
8163 : /* Second chance : now that we have a PAM dataset, it is possible */
8164 : /* to write metadata that we couldn't be writen as TIFF tag */
8165 : /* -------------------------------------------------------------------- */
8166 198 : if (!bHasWrittenMDInGeotiffTAG)
8167 : GTiffDataset::WriteMetadata( poDS, hTIFF, TRUE, pszProfile,
8168 4 : pszFilename, papszOptions, TRUE /* don't write RPC and IMD file again */);
8169 :
8170 : /* To avoid unnecessary directory rewriting */
8171 198 : poDS->bMetadataChanged = FALSE;
8172 198 : poDS->bGeoTIFFInfoChanged = FALSE;
8173 :
8174 : /* We must re-set the compression level at this point, since it has */
8175 : /* been lost a few lines above when closing the newly create TIFF file */
8176 : /* The TIFFTAG_ZIPQUALITY & TIFFTAG_JPEGQUALITY are not store in the TIFF file. */
8177 : /* They are just TIFF session parameters */
8178 :
8179 198 : poDS->nZLevel = GTiffGetZLevel(papszOptions);
8180 198 : poDS->nLZMAPreset = GTiffGetLZMAPreset(papszOptions);
8181 198 : poDS->nJpegQuality = GTiffGetJpegQuality(papszOptions);
8182 :
8183 198 : if (nCompression == COMPRESSION_ADOBE_DEFLATE)
8184 : {
8185 4 : if (poDS->nZLevel != -1)
8186 : {
8187 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, poDS->nZLevel );
8188 : }
8189 : }
8190 194 : else if( nCompression == COMPRESSION_JPEG)
8191 : {
8192 9 : if (poDS->nJpegQuality != -1)
8193 : {
8194 3 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, poDS->nJpegQuality );
8195 : }
8196 : }
8197 185 : else if( nCompression == COMPRESSION_LZMA)
8198 : {
8199 0 : if (poDS->nLZMAPreset != -1)
8200 : {
8201 0 : TIFFSetField( hTIFF, TIFFTAG_LZMAPRESET, poDS->nLZMAPreset );
8202 : }
8203 : }
8204 :
8205 : /* Precreate (internal) mask, so that the IBuildOverviews() below */
8206 : /* has a chance to create also the overviews of the mask */
8207 198 : int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
8208 198 : if( eErr == CE_None
8209 : && !(nMaskFlags & (GMF_ALL_VALID|GMF_ALPHA|GMF_NODATA) )
8210 : && (nMaskFlags & GMF_PER_DATASET) )
8211 : {
8212 3 : eErr = poDS->CreateMaskBand( nMaskFlags );
8213 : }
8214 :
8215 : /* -------------------------------------------------------------------- */
8216 : /* Create and then copy existing overviews if requested */
8217 : /* We do it such that all the IFDs are at the beginning of the file, */
8218 : /* and that the imagery data for the smallest overview is written */
8219 : /* first, that way the file is more usable when embedded in a */
8220 : /* compressed stream. */
8221 : /* -------------------------------------------------------------------- */
8222 :
8223 : /* For scaled progress due to overview copying */
8224 198 : double dfTotalPixels = ((double)nXSize) * nYSize;
8225 198 : double dfCurPixels = 0;
8226 :
8227 198 : if (eErr == CE_None &&
8228 : nSrcOverviews != 0 &&
8229 : CSLFetchBoolean(papszOptions, "COPY_SRC_OVERVIEWS", FALSE))
8230 : {
8231 5 : eErr = poDS->CreateOverviewsFromSrcOverviews(poSrcDS);
8232 :
8233 5 : if (poDS->nOverviewCount != nSrcOverviews)
8234 : {
8235 : CPLError(CE_Failure, CPLE_AppDefined,
8236 : "Did only manage to instanciate %d overview levels, whereas source contains %d",
8237 0 : poDS->nOverviewCount, nSrcOverviews);
8238 0 : eErr = CE_Failure;
8239 : }
8240 :
8241 : int i;
8242 18 : for(i=0;i<nSrcOverviews;i++)
8243 : {
8244 13 : GDALRasterBand* poOvrBand = poSrcDS->GetRasterBand(1)->GetOverview(i);
8245 : dfTotalPixels += ((double)poOvrBand->GetXSize()) *
8246 13 : poOvrBand->GetYSize();
8247 : }
8248 :
8249 5 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
8250 5 : if (nCompression != COMPRESSION_NONE)
8251 0 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
8252 : /* Now copy the imagery */
8253 17 : for(i=0;eErr == CE_None && i<nSrcOverviews;i++)
8254 : {
8255 : /* Begin with the smallest overview */
8256 12 : int iOvrLevel = nSrcOverviews-1-i;
8257 :
8258 : /* Create a fake dataset with the source overview level so that */
8259 : /* GDALDatasetCopyWholeRaster can cope with it */
8260 12 : GDALDataset* poSrcOvrDS = new GDALOverviewDS(poSrcDS, iOvrLevel);
8261 :
8262 : GDALRasterBand* poOvrBand =
8263 24 : poSrcDS->GetRasterBand(1)->GetOverview(iOvrLevel);
8264 : double dfNextCurPixels = dfCurPixels +
8265 12 : ((double)poOvrBand->GetXSize()) * poOvrBand->GetYSize();
8266 :
8267 : void* pScaledData = GDALCreateScaledProgress( dfCurPixels / dfTotalPixels,
8268 : dfNextCurPixels / dfTotalPixels,
8269 12 : pfnProgress, pProgressData);
8270 :
8271 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcOvrDS,
8272 12 : (GDALDatasetH) poDS->papoOverviewDS[iOvrLevel],
8273 : papszCopyWholeRasterOptions,
8274 24 : GDALScaledProgress, pScaledData );
8275 :
8276 12 : dfCurPixels = dfNextCurPixels;
8277 12 : GDALDestroyScaledProgress(pScaledData);
8278 :
8279 12 : delete poSrcOvrDS;
8280 12 : poDS->papoOverviewDS[iOvrLevel]->FlushCache();
8281 :
8282 : /* Copy mask of the overview */
8283 12 : if (eErr == CE_None && poDS->poMaskDS != NULL)
8284 : {
8285 2 : eErr = GDALRasterBandCopyWholeRaster( poOvrBand->GetMaskBand(),
8286 2 : poDS->papoOverviewDS[iOvrLevel]->poMaskDS->GetRasterBand(1),
8287 : papszCopyWholeRasterOptions,
8288 4 : GDALDummyProgress, NULL);
8289 2 : poDS->papoOverviewDS[iOvrLevel]->poMaskDS->FlushCache();
8290 : }
8291 : }
8292 : }
8293 :
8294 : /* -------------------------------------------------------------------- */
8295 : /* Copy actual imagery. */
8296 : /* -------------------------------------------------------------------- */
8297 : void* pScaledData = GDALCreateScaledProgress( dfCurPixels / dfTotalPixels,
8298 : 1.0,
8299 198 : pfnProgress, pProgressData);
8300 :
8301 201 : if (poDS->bTreatAsSplit || poDS->bTreatAsSplitBitmap)
8302 : {
8303 : /* For split bands, we use TIFFWriteScanline() interface */
8304 3 : CPLAssert(poDS->nBitsPerSample == 8 || poDS->nBitsPerSample == 1);
8305 :
8306 5 : if (poDS->nPlanarConfig == PLANARCONFIG_CONTIG && poDS->nBands > 1)
8307 : {
8308 : int j;
8309 2 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
8310 7050 : for(j=0;j<nYSize && eErr == CE_None;j++)
8311 : {
8312 : eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1,
8313 : pabyScanline, nXSize, 1,
8314 7048 : GDT_Byte, nBands, NULL, poDS->nBands, 0, 1);
8315 7048 : if (eErr == CE_None &&
8316 : TIFFWriteScanline( hTIFF, pabyScanline, j, 0) == -1)
8317 : {
8318 : CPLError( CE_Failure, CPLE_AppDefined,
8319 0 : "TIFFWriteScanline() failed." );
8320 0 : eErr = CE_Failure;
8321 : }
8322 7048 : if( !GDALScaledProgress( (j+1) * 1.0 / nYSize, NULL, pScaledData ) )
8323 0 : eErr = CE_Failure;
8324 : }
8325 2 : CPLFree(pabyScanline);
8326 : }
8327 : else
8328 : {
8329 : int iBand, j;
8330 1 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
8331 1 : eErr = CE_None;
8332 4 : for(iBand=1;iBand<=nBands && eErr == CE_None;iBand++)
8333 : {
8334 15003 : for(j=0;j<nYSize && eErr == CE_None;j++)
8335 : {
8336 : eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
8337 : GF_Read, 0, j, nXSize, 1,
8338 : pabyScanline, nXSize, 1,
8339 15000 : GDT_Byte, 0, 0);
8340 15000 : if (poDS->bTreatAsSplitBitmap)
8341 : {
8342 0 : for(int i=0;i<nXSize;i++)
8343 : {
8344 0 : GByte byVal = pabyScanline[i];
8345 0 : if ((i & 0x7) == 0)
8346 0 : pabyScanline[i >> 3] = 0;
8347 0 : if (byVal)
8348 0 : pabyScanline[i >> 3] |= (0x80 >> (i & 0x7));
8349 : }
8350 : }
8351 15000 : if (eErr == CE_None &&
8352 : TIFFWriteScanline( hTIFF, pabyScanline, j, (uint16) (iBand-1)) == -1)
8353 : {
8354 : CPLError( CE_Failure, CPLE_AppDefined,
8355 0 : "TIFFWriteScanline() failed." );
8356 0 : eErr = CE_Failure;
8357 : }
8358 15000 : if( !GDALScaledProgress( (j+1 + (iBand - 1) * nYSize) * 1.0 /
8359 : (nBands * nYSize), NULL, pScaledData ) )
8360 0 : eErr = CE_Failure;
8361 : }
8362 : }
8363 1 : CPLFree(pabyScanline);
8364 : }
8365 :
8366 : /* Necessary to be able to read the file without re-opening */
8367 : #if defined(HAVE_TIFFGETSIZEPROC)
8368 3 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
8369 :
8370 3 : TIFFFlushData( hTIFF );
8371 :
8372 3 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
8373 3 : if( (nNewDirOffset % 2) == 1 )
8374 3 : nNewDirOffset++;
8375 : #endif
8376 :
8377 3 : TIFFFlush( hTIFF );
8378 :
8379 : #if defined(HAVE_TIFFGETSIZEPROC)
8380 3 : if( poDS->nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
8381 : {
8382 1 : poDS->nDirOffset = nNewDirOffset;
8383 1 : CPLDebug( "GTiff", "directory moved during flush." );
8384 : }
8385 : #endif
8386 : }
8387 195 : else if (eErr == CE_None)
8388 : {
8389 194 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
8390 194 : if (nCompression != COMPRESSION_NONE)
8391 17 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
8392 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
8393 : (GDALDatasetH) poDS,
8394 : papszCopyWholeRasterOptions,
8395 194 : GDALScaledProgress, pScaledData );
8396 : }
8397 :
8398 198 : GDALDestroyScaledProgress(pScaledData);
8399 :
8400 198 : if (eErr == CE_None)
8401 : {
8402 197 : if (poDS->poMaskDS)
8403 : {
8404 3 : const char* papszOptions[2] = { "COMPRESSED=YES", NULL };
8405 : eErr = GDALRasterBandCopyWholeRaster(
8406 3 : poSrcDS->GetRasterBand(1)->GetMaskBand(),
8407 3 : poDS->GetRasterBand(1)->GetMaskBand(),
8408 : (char**)papszOptions,
8409 9 : GDALDummyProgress, NULL);
8410 : }
8411 : else
8412 194 : eErr = GDALDriver::DefaultCopyMasks( poSrcDS, poDS, bStrict );
8413 : }
8414 :
8415 198 : if( eErr == CE_Failure )
8416 : {
8417 1 : delete poDS;
8418 1 : poDS = NULL;
8419 :
8420 1 : if (CSLTestBoolean(CPLGetConfigOption("GTIFF_DELETE_ON_ERROR", "YES")))
8421 0 : VSIUnlink( pszFilename ); // should really delete more carefully.
8422 : }
8423 :
8424 198 : return poDS;
8425 : }
8426 :
8427 : /************************************************************************/
8428 : /* GetProjectionRef() */
8429 : /************************************************************************/
8430 :
8431 3221 : const char *GTiffDataset::GetProjectionRef()
8432 :
8433 : {
8434 3221 : if( nGCPCount == 0 )
8435 : {
8436 3191 : LookForProjection();
8437 :
8438 3191 : if( EQUAL(pszProjection,"") )
8439 90 : return GDALPamDataset::GetProjectionRef();
8440 : else
8441 3101 : return( pszProjection );
8442 : }
8443 : else
8444 30 : return "";
8445 : }
8446 :
8447 : /************************************************************************/
8448 : /* SetProjection() */
8449 : /************************************************************************/
8450 :
8451 726 : CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
8452 :
8453 : {
8454 726 : LookForProjection();
8455 :
8456 726 : if( !EQUALN(pszNewProjection,"GEOGCS",6)
8457 : && !EQUALN(pszNewProjection,"PROJCS",6)
8458 : && !EQUALN(pszNewProjection,"LOCAL_CS",8)
8459 : && !EQUALN(pszNewProjection,"COMPD_CS",8)
8460 : && !EQUALN(pszNewProjection,"GEOCCS",6)
8461 : && !EQUAL(pszNewProjection,"") )
8462 : {
8463 : CPLError( CE_Failure, CPLE_AppDefined,
8464 : "Only OGC WKT Projections supported for writing to GeoTIFF.\n"
8465 : "%s not supported.",
8466 0 : pszNewProjection );
8467 :
8468 0 : return CE_Failure;
8469 : }
8470 :
8471 726 : CPLFree( pszProjection );
8472 726 : pszProjection = CPLStrdup( pszNewProjection );
8473 :
8474 726 : bGeoTIFFInfoChanged = TRUE;
8475 :
8476 726 : return CE_None;
8477 : }
8478 :
8479 : /************************************************************************/
8480 : /* GetGeoTransform() */
8481 : /************************************************************************/
8482 :
8483 2076 : CPLErr GTiffDataset::GetGeoTransform( double * padfTransform )
8484 :
8485 : {
8486 2076 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
8487 :
8488 2076 : if( !bGeoTransformValid )
8489 92 : return CE_Failure;
8490 : else
8491 1984 : return CE_None;
8492 : }
8493 :
8494 : /************************************************************************/
8495 : /* SetGeoTransform() */
8496 : /************************************************************************/
8497 :
8498 693 : CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
8499 :
8500 : {
8501 693 : if( GetAccess() == GA_Update )
8502 : {
8503 693 : memcpy( adfGeoTransform, padfTransform, sizeof(double)*6 );
8504 693 : bGeoTransformValid = TRUE;
8505 693 : bGeoTIFFInfoChanged = TRUE;
8506 :
8507 693 : return( CE_None );
8508 : }
8509 : else
8510 : {
8511 : CPLError( CE_Failure, CPLE_NotSupported,
8512 0 : "Attempt to call SetGeoTransform() on a read-only GeoTIFF file." );
8513 0 : return CE_Failure;
8514 : }
8515 : }
8516 :
8517 : /************************************************************************/
8518 : /* GetGCPCount() */
8519 : /************************************************************************/
8520 :
8521 1115 : int GTiffDataset::GetGCPCount()
8522 :
8523 : {
8524 1115 : return nGCPCount;
8525 : }
8526 :
8527 : /************************************************************************/
8528 : /* GetGCPProjection() */
8529 : /************************************************************************/
8530 :
8531 64 : const char *GTiffDataset::GetGCPProjection()
8532 :
8533 : {
8534 64 : if( nGCPCount > 0 )
8535 : {
8536 63 : LookForProjection();
8537 : }
8538 64 : if (pszProjection != NULL)
8539 64 : return pszProjection;
8540 : else
8541 0 : return "";
8542 : }
8543 :
8544 : /************************************************************************/
8545 : /* GetGCPs() */
8546 : /************************************************************************/
8547 :
8548 32 : const GDAL_GCP *GTiffDataset::GetGCPs()
8549 :
8550 : {
8551 32 : return pasGCPList;
8552 : }
8553 :
8554 : /************************************************************************/
8555 : /* SetGCPs() */
8556 : /************************************************************************/
8557 :
8558 2 : CPLErr GTiffDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
8559 : const char *pszGCPProjection )
8560 : {
8561 2 : if( GetAccess() == GA_Update )
8562 : {
8563 2 : bLookedForProjection = TRUE;
8564 :
8565 2 : if( this->nGCPCount > 0 )
8566 : {
8567 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
8568 0 : CPLFree( this->pasGCPList );
8569 : }
8570 :
8571 2 : this->nGCPCount = nGCPCount;
8572 2 : this->pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPList);
8573 :
8574 2 : CPLFree( this->pszProjection );
8575 2 : this->pszProjection = CPLStrdup( pszGCPProjection );
8576 2 : bGeoTIFFInfoChanged = TRUE;
8577 :
8578 2 : return CE_None;
8579 : }
8580 : else
8581 : {
8582 : CPLError( CE_Failure, CPLE_NotSupported,
8583 0 : "SetGCPs() is only supported on newly created GeoTIFF files." );
8584 0 : return CE_Failure;
8585 : }
8586 : }
8587 :
8588 : /************************************************************************/
8589 : /* GetMetadata() */
8590 : /************************************************************************/
8591 :
8592 5456 : char **GTiffDataset::GetMetadata( const char * pszDomain )
8593 :
8594 : {
8595 5456 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
8596 0 : return GDALPamDataset::GetMetadata( pszDomain );
8597 :
8598 7232 : else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
8599 1776 : LoadRPCRPB();
8600 :
8601 4827 : else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
8602 1147 : LoadIMD();
8603 :
8604 2533 : else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
8605 169 : ScanDirectories();
8606 :
8607 : /* FIXME ? Should we call LookForProjection() to load GDALMD_AREA_OR_POINT ? */
8608 : /* This can impact performances */
8609 :
8610 5456 : return oGTiffMDMD.GetMetadata( pszDomain );
8611 : }
8612 :
8613 : /************************************************************************/
8614 : /* SetMetadata() */
8615 : /************************************************************************/
8616 245 : CPLErr GTiffDataset::SetMetadata( char ** papszMD, const char *pszDomain )
8617 :
8618 : {
8619 245 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
8620 245 : bMetadataChanged = TRUE;
8621 :
8622 245 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
8623 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT) != NULL )
8624 : {
8625 : const char* pszPrevValue =
8626 136 : GetMetadataItem(GDALMD_AREA_OR_POINT);
8627 : const char* pszNewValue =
8628 136 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT);
8629 136 : if (pszPrevValue == NULL || pszNewValue == NULL ||
8630 : !EQUAL(pszPrevValue, pszNewValue))
8631 : {
8632 7 : LookForProjection();
8633 7 : bGeoTIFFInfoChanged = TRUE;
8634 : }
8635 : }
8636 :
8637 245 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
8638 : }
8639 :
8640 : /************************************************************************/
8641 : /* GetMetadataItem() */
8642 : /************************************************************************/
8643 :
8644 21559 : const char *GTiffDataset::GetMetadataItem( const char * pszName,
8645 : const char * pszDomain )
8646 :
8647 : {
8648 21559 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
8649 3 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
8650 :
8651 21558 : else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
8652 2 : LoadRPCRPB();
8653 :
8654 21556 : else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
8655 2 : LoadIMD();
8656 :
8657 21552 : else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
8658 0 : ScanDirectories();
8659 :
8660 21552 : else if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
8661 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
8662 : {
8663 1432 : LookForProjection();
8664 : }
8665 :
8666 21556 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
8667 : }
8668 :
8669 : /************************************************************************/
8670 : /* SetMetadataItem() */
8671 : /************************************************************************/
8672 :
8673 5349 : CPLErr GTiffDataset::SetMetadataItem( const char *pszName,
8674 : const char *pszValue,
8675 : const char *pszDomain )
8676 :
8677 : {
8678 5349 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
8679 5349 : bMetadataChanged = TRUE;
8680 :
8681 5349 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
8682 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
8683 : {
8684 8 : LookForProjection();
8685 8 : bGeoTIFFInfoChanged = TRUE;
8686 : }
8687 :
8688 5349 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
8689 : }
8690 :
8691 : /************************************************************************/
8692 : /* GetInternalHandle() */
8693 : /************************************************************************/
8694 :
8695 273 : void *GTiffDataset::GetInternalHandle( const char * /* pszHandleName */ )
8696 :
8697 : {
8698 273 : return hTIFF;
8699 : }
8700 :
8701 :
8702 : /************************************************************************/
8703 : /* FindRPBFile() */
8704 : /************************************************************************/
8705 :
8706 2189 : int GTiffDataset::FindRPBFile()
8707 : {
8708 : osRPBFile = GDALFindAssociatedFile( osFilename, "RPB",
8709 2189 : oOvManager.GetSiblingFiles(), 0 );
8710 :
8711 2189 : return osRPBFile != "";
8712 : }
8713 :
8714 : /************************************************************************/
8715 : /* FindIMDFile() */
8716 : /************************************************************************/
8717 :
8718 2025 : int GTiffDataset::FindIMDFile()
8719 : {
8720 : osIMDFile = GDALFindAssociatedFile( osFilename, "IMD",
8721 2025 : oOvManager.GetSiblingFiles(), 0 );
8722 :
8723 2025 : return osIMDFile != "";
8724 : }
8725 :
8726 : /************************************************************************/
8727 : /* FindRPCFile() */
8728 : /************************************************************************/
8729 :
8730 2181 : int GTiffDataset::FindRPCFile()
8731 : {
8732 2181 : CPLString osSrcPath = osFilename;
8733 2181 : CPLString soPt(".");
8734 2181 : size_t found = osSrcPath.rfind(soPt);
8735 2181 : if (found == CPLString::npos)
8736 40 : return FALSE;
8737 2141 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
8738 2141 : CPLString osTarget = osSrcPath;
8739 :
8740 2141 : char** papszSiblingFiles = oOvManager.GetSiblingFiles();
8741 2141 : if( papszSiblingFiles == NULL )
8742 : {
8743 : VSIStatBufL sStatBuf;
8744 :
8745 918 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
8746 : {
8747 918 : osSrcPath = osFilename;
8748 918 : osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
8749 918 : osTarget = osSrcPath;
8750 :
8751 918 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
8752 : {
8753 918 : osSrcPath = osFilename;
8754 918 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
8755 918 : osTarget = osSrcPath;
8756 :
8757 918 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
8758 : {
8759 918 : return FALSE;
8760 : }
8761 : }
8762 : }
8763 : }
8764 : else
8765 : {
8766 : int iSibling = CSLFindString( papszSiblingFiles,
8767 1223 : CPLGetFilename(osTarget) );
8768 1223 : if( iSibling < 0 )
8769 1222 : return FALSE;
8770 :
8771 1 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
8772 1 : osTarget += papszSiblingFiles[iSibling];
8773 : }
8774 :
8775 1 : osRPCFile = osTarget;
8776 1 : return TRUE;
8777 : }
8778 :
8779 : /************************************************************************/
8780 : /* LoadRPCRPB() */
8781 : /************************************************************************/
8782 :
8783 2743 : void GTiffDataset::LoadRPCRPB()
8784 : {
8785 2743 : if (bHasSearchedRPC)
8786 554 : return;
8787 :
8788 2189 : bHasSearchedRPC = TRUE;
8789 :
8790 2189 : char **papszRPCMD = NULL;
8791 : /* Read Digital Globe .RPB file */
8792 2189 : if (FindRPBFile())
8793 8 : papszRPCMD = GDALLoadRPBFile( osRPBFile.c_str(), NULL );
8794 :
8795 : /* Read GeoEye _rpc.txt file */
8796 2189 : if(papszRPCMD == NULL && FindRPCFile())
8797 1 : papszRPCMD = GDALLoadRPCFile( osRPCFile.c_str(), NULL );
8798 :
8799 2189 : if( papszRPCMD != NULL )
8800 : {
8801 9 : oGTiffMDMD.SetMetadata( papszRPCMD, "RPC" );
8802 9 : CSLDestroy( papszRPCMD );
8803 : }
8804 : else
8805 2180 : ReadRPCTag();
8806 : }
8807 :
8808 : /************************************************************************/
8809 : /* LoadIMD() */
8810 : /************************************************************************/
8811 :
8812 2114 : void GTiffDataset::LoadIMD()
8813 : {
8814 2114 : if (bHasSearchedIMD)
8815 89 : return;
8816 :
8817 2025 : bHasSearchedIMD = TRUE;
8818 :
8819 2025 : if (FindIMDFile())
8820 : {
8821 8 : char **papszIMDMD = GDALLoadIMDFile( osIMDFile.c_str(), NULL );
8822 :
8823 8 : if( papszIMDMD != NULL )
8824 : {
8825 8 : oGTiffMDMD.SetMetadata( papszIMDMD, "IMD" );
8826 8 : CSLDestroy( papszIMDMD );
8827 : }
8828 : }
8829 : }
8830 :
8831 : /************************************************************************/
8832 : /* GetFileList() */
8833 : /************************************************************************/
8834 :
8835 965 : char **GTiffDataset::GetFileList()
8836 :
8837 : {
8838 965 : char **papszFileList = GDALPamDataset::GetFileList();
8839 :
8840 965 : LoadRPCRPB();
8841 965 : LoadIMD();
8842 :
8843 965 : if (osIMDFile.size() != 0)
8844 4 : papszFileList = CSLAddString( papszFileList, osIMDFile );
8845 965 : if (osRPBFile.size() != 0)
8846 2 : papszFileList = CSLAddString( papszFileList, osRPBFile );
8847 965 : if (osRPCFile.size() != 0)
8848 0 : papszFileList = CSLAddString( papszFileList, osRPCFile );
8849 :
8850 965 : if (osWldFilename.size() != 0 &&
8851 : CSLFindString(papszFileList, osWldFilename) == -1)
8852 : {
8853 3 : papszFileList = CSLAddString( papszFileList, osWldFilename );
8854 : }
8855 :
8856 965 : return papszFileList;
8857 : }
8858 :
8859 : /************************************************************************/
8860 : /* CreateMaskBand() */
8861 : /************************************************************************/
8862 :
8863 33 : CPLErr GTiffDataset::CreateMaskBand(int nFlags)
8864 : {
8865 33 : ScanDirectories();
8866 :
8867 33 : if (poMaskDS != NULL)
8868 : {
8869 : CPLError(CE_Failure, CPLE_AppDefined,
8870 0 : "This TIFF dataset has already an internal mask band");
8871 0 : return CE_Failure;
8872 : }
8873 33 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
8874 : {
8875 : toff_t nOffset;
8876 : int bIsTiled;
8877 29 : int bIsOverview = FALSE;
8878 : uint32 nSubType;
8879 : int nCompression;
8880 :
8881 29 : if (nFlags != GMF_PER_DATASET)
8882 : {
8883 : CPLError(CE_Failure, CPLE_AppDefined,
8884 0 : "The only flag value supported for internal mask is GMF_PER_DATASET");
8885 0 : return CE_Failure;
8886 : }
8887 :
8888 29 : if( strstr(GDALGetMetadataItem(GDALGetDriverByName( "GTiff" ),
8889 : GDAL_DMD_CREATIONOPTIONLIST, NULL ),
8890 : "<Value>DEFLATE</Value>") != NULL )
8891 29 : nCompression = COMPRESSION_ADOBE_DEFLATE;
8892 : else
8893 0 : nCompression = COMPRESSION_PACKBITS;
8894 :
8895 : /* -------------------------------------------------------------------- */
8896 : /* If we don't have read access, then create the mask externally. */
8897 : /* -------------------------------------------------------------------- */
8898 29 : if( GetAccess() != GA_Update )
8899 : {
8900 : CPLError( CE_Warning, CPLE_AppDefined,
8901 : "File open for read-only accessing, "
8902 0 : "creating mask externally." );
8903 :
8904 0 : return GDALPamDataset::CreateMaskBand(nFlags);
8905 : }
8906 :
8907 29 : if (poBaseDS)
8908 : {
8909 12 : if (!poBaseDS->SetDirectory())
8910 0 : return CE_Failure;
8911 : }
8912 29 : if (!SetDirectory())
8913 0 : return CE_Failure;
8914 :
8915 29 : if( TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
8916 : {
8917 12 : bIsOverview = (nSubType & FILETYPE_REDUCEDIMAGE) != 0;
8918 :
8919 12 : if ((nSubType & FILETYPE_MASK) != 0)
8920 : {
8921 : CPLError( CE_Failure, CPLE_AppDefined,
8922 0 : "Cannot create a mask on a TIFF mask IFD !" );
8923 0 : return CE_Failure;
8924 : }
8925 : }
8926 :
8927 29 : bIsTiled = TIFFIsTiled(hTIFF);
8928 :
8929 29 : FlushDirectory();
8930 :
8931 : nOffset = GTIFFWriteDirectory(hTIFF,
8932 : (bIsOverview) ? FILETYPE_REDUCEDIMAGE | FILETYPE_MASK : FILETYPE_MASK,
8933 : nRasterXSize, nRasterYSize,
8934 : 1, PLANARCONFIG_CONTIG, 1,
8935 : nBlockXSize, nBlockYSize,
8936 : bIsTiled, nCompression,
8937 : PHOTOMETRIC_MASK, PREDICTOR_NONE,
8938 29 : SAMPLEFORMAT_UINT, NULL, NULL, NULL, 0, NULL, "");
8939 29 : if (nOffset == 0)
8940 0 : return CE_Failure;
8941 :
8942 29 : poMaskDS = new GTiffDataset();
8943 29 : poMaskDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
8944 29 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nOffset,
8945 : FALSE, GA_Update ) != CE_None)
8946 : {
8947 0 : delete poMaskDS;
8948 0 : poMaskDS = NULL;
8949 0 : return CE_Failure;
8950 : }
8951 :
8952 29 : return CE_None;
8953 : }
8954 : else
8955 : {
8956 4 : return GDALPamDataset::CreateMaskBand(nFlags);
8957 : }
8958 : }
8959 :
8960 : /************************************************************************/
8961 : /* CreateMaskBand() */
8962 : /************************************************************************/
8963 :
8964 12 : CPLErr GTiffRasterBand::CreateMaskBand(int nFlags)
8965 : {
8966 12 : poGDS->ScanDirectories();
8967 :
8968 12 : if (poGDS->poMaskDS != NULL)
8969 : {
8970 : CPLError(CE_Failure, CPLE_AppDefined,
8971 0 : "This TIFF dataset has already an internal mask band");
8972 0 : return CE_Failure;
8973 : }
8974 12 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
8975 : {
8976 12 : return poGDS->CreateMaskBand(nFlags);
8977 : }
8978 : else
8979 : {
8980 0 : return GDALPamRasterBand::CreateMaskBand(nFlags);
8981 : }
8982 : }
8983 :
8984 : /************************************************************************/
8985 : /* PrepareTIFFErrorFormat() */
8986 : /* */
8987 : /* sometimes the "module" has stuff in it that has special */
8988 : /* meaning in a printf() style format, so we try to escape it. */
8989 : /* For now we hope the only thing we have to escape is %'s. */
8990 : /************************************************************************/
8991 :
8992 9 : static char *PrepareTIFFErrorFormat( const char *module, const char *fmt )
8993 :
8994 : {
8995 : char *pszModFmt;
8996 : int iIn, iOut;
8997 :
8998 9 : pszModFmt = (char *) CPLMalloc( strlen(module)*2 + strlen(fmt) + 2 );
8999 125 : for( iOut = 0, iIn = 0; module[iIn] != '\0'; iIn++ )
9000 : {
9001 116 : if( module[iIn] == '%' )
9002 : {
9003 0 : pszModFmt[iOut++] = '%';
9004 0 : pszModFmt[iOut++] = '%';
9005 : }
9006 : else
9007 116 : pszModFmt[iOut++] = module[iIn];
9008 : }
9009 9 : pszModFmt[iOut] = '\0';
9010 9 : strcat( pszModFmt, ":" );
9011 9 : strcat( pszModFmt, fmt );
9012 :
9013 9 : return pszModFmt;
9014 : }
9015 :
9016 : /************************************************************************/
9017 : /* GTiffWarningHandler() */
9018 : /************************************************************************/
9019 : void
9020 3 : GTiffWarningHandler(const char* module, const char* fmt, va_list ap )
9021 : {
9022 : char *pszModFmt;
9023 :
9024 3 : if( strstr(fmt,"nknown field") != NULL )
9025 0 : return;
9026 :
9027 3 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
9028 3 : if( strstr(fmt, "does not end in null byte") != NULL )
9029 : {
9030 1 : CPLString osMsg;
9031 1 : osMsg.vPrintf(pszModFmt, ap);
9032 1 : CPLDebug( "GTiff", "%s", osMsg.c_str() );
9033 : }
9034 : else
9035 2 : CPLErrorV( CE_Warning, CPLE_AppDefined, pszModFmt, ap );
9036 3 : CPLFree( pszModFmt );
9037 : }
9038 :
9039 : /************************************************************************/
9040 : /* GTiffErrorHandler() */
9041 : /************************************************************************/
9042 : void
9043 6 : GTiffErrorHandler(const char* module, const char* fmt, va_list ap )
9044 : {
9045 : char *pszModFmt;
9046 :
9047 6 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
9048 6 : CPLErrorV( CE_Failure, CPLE_AppDefined, pszModFmt, ap );
9049 6 : CPLFree( pszModFmt );
9050 6 : }
9051 :
9052 : /************************************************************************/
9053 : /* GTiffTagExtender() */
9054 : /* */
9055 : /* Install tags specially known to GDAL. */
9056 : /************************************************************************/
9057 :
9058 : static TIFFExtendProc _ParentExtender = NULL;
9059 :
9060 9932 : static void GTiffTagExtender(TIFF *tif)
9061 :
9062 : {
9063 : static const TIFFFieldInfo xtiffFieldInfo[] = {
9064 : { TIFFTAG_GDAL_METADATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
9065 : TRUE, FALSE, (char*) "GDALMetadata" },
9066 : { TIFFTAG_GDAL_NODATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
9067 : TRUE, FALSE, (char*) "GDALNoDataValue" },
9068 : { TIFFTAG_RPCCOEFFICIENT, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
9069 : TRUE, TRUE, (char*) "RPCCoefficient" }
9070 : };
9071 :
9072 9932 : if (_ParentExtender)
9073 0 : (*_ParentExtender)(tif);
9074 :
9075 : TIFFMergeFieldInfo( tif, xtiffFieldInfo,
9076 9932 : sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]) );
9077 9932 : }
9078 :
9079 : /************************************************************************/
9080 : /* GTiffOneTimeInit() */
9081 : /* */
9082 : /* This is stuff that is initialized for the TIFF library just */
9083 : /* once. We deliberately defer the initialization till the */
9084 : /* first time we are likely to call into libtiff to avoid */
9085 : /* unnecessary paging in of the library for GDAL apps that */
9086 : /* don't use it. */
9087 : /************************************************************************/
9088 : #if defined(HAVE_DLFCN_H) && !defined(WIN32)
9089 : #include <dlfcn.h>
9090 : #endif
9091 :
9092 4938 : int GTiffOneTimeInit()
9093 :
9094 : {
9095 : static int bInitIsOk = TRUE;
9096 : static int bOneTimeInitDone = FALSE;
9097 : static void* hMutex = NULL;
9098 4938 : CPLMutexHolder oHolder( &hMutex);
9099 4938 : if( bOneTimeInitDone )
9100 4510 : return bInitIsOk;
9101 :
9102 428 : bOneTimeInitDone = TRUE;
9103 :
9104 : /* This is a frequent configuration error that is difficult to track down */
9105 : /* for people unaware of the issue : GDAL built against internal libtiff (4.X) */
9106 : /* but used by an application that links with external libtiff (3.X) */
9107 : /* Note: on my conf, the order that cause GDAL to crash - and that is detected */
9108 : /* by the following code - is "-ltiff -lgdal". "-lgdal -ltiff" works for the */
9109 : /* GTiff driver but probably breaks the application that believes it uses libtiff 3.X */
9110 : /* but we cannot detect that... */
9111 : #if defined(BIGTIFF_SUPPORT) && !defined(RENAME_INTERNAL_LIBTIFF_SYMBOLS)
9112 : #if defined(HAVE_DLFCN_H) && !defined(WIN32)
9113 : const char* (*pfnVersion)(void);
9114 : pfnVersion = (const char* (*)(void)) dlsym(RTLD_DEFAULT, "TIFFGetVersion");
9115 : if (pfnVersion)
9116 : {
9117 : const char* pszVersion = pfnVersion();
9118 : if (pszVersion && strstr(pszVersion, "Version 3.") != NULL)
9119 : {
9120 : CPLError(CE_Warning, CPLE_AppDefined,
9121 : "libtiff version mismatch : You're linking against libtiff 3.X, but GDAL has been compiled against libtiff >= 4.0.0");
9122 : }
9123 : }
9124 : #endif
9125 : #endif
9126 :
9127 428 : _ParentExtender = TIFFSetTagExtender(GTiffTagExtender);
9128 :
9129 428 : TIFFSetWarningHandler( GTiffWarningHandler );
9130 428 : TIFFSetErrorHandler( GTiffErrorHandler );
9131 :
9132 : // This only really needed if we are linked to an external libgeotiff
9133 : // with its own (lame) file searching logic.
9134 428 : SetCSVFilenameHook( GDALDefaultCSVFilename );
9135 :
9136 428 : return TRUE;
9137 : }
9138 :
9139 : /************************************************************************/
9140 : /* GDALDeregister_GTiff() */
9141 : /************************************************************************/
9142 :
9143 522 : void GDALDeregister_GTiff( GDALDriver * )
9144 :
9145 : {
9146 522 : CSVDeaccess( NULL );
9147 :
9148 : #if defined(LIBGEOTIFF_VERSION) && LIBGEOTIFF_VERSION > 1150
9149 522 : GTIFDeaccessCSV();
9150 : #endif
9151 522 : }
9152 :
9153 : /************************************************************************/
9154 : /* GTIFFGetCompressionMethod() */
9155 : /************************************************************************/
9156 :
9157 66 : int GTIFFGetCompressionMethod(const char* pszValue, const char* pszVariableName)
9158 : {
9159 66 : int nCompression = COMPRESSION_NONE;
9160 66 : if( EQUAL( pszValue, "NONE" ) )
9161 1 : nCompression = COMPRESSION_NONE;
9162 65 : else if( EQUAL( pszValue, "JPEG" ) )
9163 31 : nCompression = COMPRESSION_JPEG;
9164 34 : else if( EQUAL( pszValue, "LZW" ) )
9165 17 : nCompression = COMPRESSION_LZW;
9166 17 : else if( EQUAL( pszValue, "PACKBITS" ))
9167 2 : nCompression = COMPRESSION_PACKBITS;
9168 28 : else if( EQUAL( pszValue, "DEFLATE" ) || EQUAL( pszValue, "ZIP" ))
9169 13 : nCompression = COMPRESSION_ADOBE_DEFLATE;
9170 2 : else if( EQUAL( pszValue, "FAX3" )
9171 : || EQUAL( pszValue, "CCITTFAX3" ))
9172 0 : nCompression = COMPRESSION_CCITTFAX3;
9173 4 : else if( EQUAL( pszValue, "FAX4" )
9174 : || EQUAL( pszValue, "CCITTFAX4" ))
9175 2 : nCompression = COMPRESSION_CCITTFAX4;
9176 0 : else if( EQUAL( pszValue, "CCITTRLE" ) )
9177 0 : nCompression = COMPRESSION_CCITTRLE;
9178 0 : else if( EQUAL( pszValue, "LZMA" ) )
9179 0 : nCompression = COMPRESSION_LZMA;
9180 : else
9181 : CPLError( CE_Warning, CPLE_IllegalArg,
9182 : "%s=%s value not recognised, ignoring.",
9183 0 : pszVariableName,pszValue );
9184 :
9185 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
9186 66 : if (nCompression != COMPRESSION_NONE &&
9187 : !TIFFIsCODECConfigured((uint16) nCompression))
9188 : {
9189 : CPLError( CE_Failure, CPLE_AppDefined,
9190 0 : "Cannot create TIFF file due to missing codec for %s.", pszValue );
9191 0 : return -1;
9192 : }
9193 : #endif
9194 :
9195 66 : return nCompression;
9196 : }
9197 : /************************************************************************/
9198 : /* GDALRegister_GTiff() */
9199 : /************************************************************************/
9200 :
9201 558 : void GDALRegister_GTiff()
9202 :
9203 : {
9204 558 : if( GDALGetDriverByName( "GTiff" ) == NULL )
9205 : {
9206 : GDALDriver *poDriver;
9207 : char szCreateOptions[3072];
9208 : char szOptionalCompressItems[500];
9209 537 : int bHasJPEG = FALSE, bHasLZW = FALSE, bHasDEFLATE = FALSE, bHasLZMA = FALSE;
9210 :
9211 537 : poDriver = new GDALDriver();
9212 :
9213 : /* -------------------------------------------------------------------- */
9214 : /* Determine which compression codecs are available that we */
9215 : /* want to advertise. If we are using an old libtiff we won't */
9216 : /* be able to find out so we just assume all are available. */
9217 : /* -------------------------------------------------------------------- */
9218 : strcpy( szOptionalCompressItems,
9219 537 : " <Value>NONE</Value>" );
9220 :
9221 : #if TIFFLIB_VERSION <= 20040919
9222 : strcat( szOptionalCompressItems,
9223 : " <Value>PACKBITS</Value>"
9224 : " <Value>JPEG</Value>"
9225 : " <Value>LZW</Value>"
9226 : " <Value>DEFLATE</Value>" );
9227 : bHasLZW = bHasDEFLATE = TRUE;
9228 : #else
9229 537 : TIFFCodec *c, *codecs = TIFFGetConfiguredCODECs();
9230 :
9231 9666 : for( c = codecs; c->name; c++ )
9232 : {
9233 9129 : if( c->scheme == COMPRESSION_PACKBITS )
9234 : strcat( szOptionalCompressItems,
9235 537 : " <Value>PACKBITS</Value>" );
9236 8592 : else if( c->scheme == COMPRESSION_JPEG )
9237 : {
9238 537 : bHasJPEG = TRUE;
9239 : strcat( szOptionalCompressItems,
9240 537 : " <Value>JPEG</Value>" );
9241 : }
9242 8055 : else if( c->scheme == COMPRESSION_LZW )
9243 : {
9244 537 : bHasLZW = TRUE;
9245 : strcat( szOptionalCompressItems,
9246 537 : " <Value>LZW</Value>" );
9247 : }
9248 7518 : else if( c->scheme == COMPRESSION_ADOBE_DEFLATE )
9249 : {
9250 537 : bHasDEFLATE = TRUE;
9251 : strcat( szOptionalCompressItems,
9252 537 : " <Value>DEFLATE</Value>" );
9253 : }
9254 6981 : else if( c->scheme == COMPRESSION_CCITTRLE )
9255 : strcat( szOptionalCompressItems,
9256 537 : " <Value>CCITTRLE</Value>" );
9257 6444 : else if( c->scheme == COMPRESSION_CCITTFAX3 )
9258 : strcat( szOptionalCompressItems,
9259 537 : " <Value>CCITTFAX3</Value>" );
9260 5907 : else if( c->scheme == COMPRESSION_CCITTFAX4 )
9261 : strcat( szOptionalCompressItems,
9262 537 : " <Value>CCITTFAX4</Value>" );
9263 5370 : else if( c->scheme == COMPRESSION_LZMA )
9264 : {
9265 537 : bHasLZMA = TRUE;
9266 : strcat( szOptionalCompressItems,
9267 537 : " <Value>LZMA</Value>" );
9268 : }
9269 : }
9270 537 : _TIFFfree( codecs );
9271 : #endif
9272 :
9273 : /* -------------------------------------------------------------------- */
9274 : /* Build full creation option list. */
9275 : /* -------------------------------------------------------------------- */
9276 : sprintf( szCreateOptions, "%s%s%s",
9277 : "<CreationOptionList>"
9278 : " <Option name='COMPRESS' type='string-select'>",
9279 : szOptionalCompressItems,
9280 537 : " </Option>");
9281 537 : if (bHasLZW || bHasDEFLATE)
9282 : strcat( szCreateOptions, ""
9283 537 : " <Option name='PREDICTOR' type='int' description='Predictor Type'/>");
9284 537 : if (bHasJPEG)
9285 : strcat( szCreateOptions, ""
9286 537 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>");
9287 537 : if (bHasDEFLATE)
9288 : strcat( szCreateOptions, ""
9289 537 : " <Option name='ZLEVEL' type='int' description='DEFLATE compression level 1-9' default='6'/>");
9290 537 : if (bHasLZMA)
9291 : strcat( szCreateOptions, ""
9292 537 : " <Option name='LZMA_PRESET' type='int' description='LZMA compression level 0(fast)-9(slow)' default='6'/>");
9293 : strcat( szCreateOptions, ""
9294 : " <Option name='NBITS' type='int' description='BITS for sub-byte files (1-7), sub-uint16 (9-15), sub-uint32 (17-31)'/>"
9295 : " <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
9296 : " <Value>BAND</Value>"
9297 : " <Value>PIXEL</Value>"
9298 : " </Option>"
9299 : " <Option name='TILED' type='boolean' description='Switch to tiled format'/>"
9300 : " <Option name='TFW' type='boolean' description='Write out world file'/>"
9301 : " <Option name='RPB' type='boolean' description='Write out .RPB (RPC) file'/>"
9302 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
9303 : " <Option name='BLOCKYSIZE' type='int' description='Tile/Strip Height'/>"
9304 : " <Option name='PHOTOMETRIC' type='string-select'>"
9305 : " <Value>MINISBLACK</Value>"
9306 : " <Value>MINISWHITE</Value>"
9307 : " <Value>PALETTE</Value>"
9308 : " <Value>RGB</Value>"
9309 : " <Value>CMYK</Value>"
9310 : " <Value>YCBCR</Value>"
9311 : " <Value>CIELAB</Value>"
9312 : " <Value>ICCLAB</Value>"
9313 : " <Value>ITULAB</Value>"
9314 : " </Option>"
9315 : " <Option name='SPARSE_OK' type='boolean' description='Can newly created files have missing blocks?' default='FALSE'/>"
9316 : " <Option name='ALPHA' type='boolean' description='Mark first extrasample as being alpha'/>"
9317 : " <Option name='PROFILE' type='string-select' default='GDALGeoTIFF'>"
9318 : " <Value>GDALGeoTIFF</Value>"
9319 : " <Value>GeoTIFF</Value>"
9320 : " <Value>BASELINE</Value>"
9321 : " </Option>"
9322 : " <Option name='PIXELTYPE' type='string-select'>"
9323 : " <Value>DEFAULT</Value>"
9324 : " <Value>SIGNEDBYTE</Value>"
9325 : " </Option>"
9326 : #ifdef BIGTIFF_SUPPORT
9327 : " <Option name='BIGTIFF' type='string-select' description='Force creation of BigTIFF file'>"
9328 : " <Value>YES</Value>"
9329 : " <Value>NO</Value>"
9330 : " <Value>IF_NEEDED</Value>"
9331 : " <Value>IF_SAFER</Value>"
9332 : " </Option>"
9333 : #endif
9334 : " <Option name='ENDIANNESS' type='string-select' default='NATIVE' description='Force endianness of created file. For DEBUG purpose mostly'>"
9335 : " <Value>NATIVE</Value>"
9336 : " <Value>INVERTED</Value>"
9337 : " <Value>LITTLE</Value>"
9338 : " <Value>BIG</Value>"
9339 : " </Option>"
9340 : " <Option name='COPY_SRC_OVERVIEWS' type='boolean' default='NO' description='Force copy of overviews of source dataset (CreateCopy())'/>"
9341 537 : "</CreationOptionList>" );
9342 :
9343 : /* -------------------------------------------------------------------- */
9344 : /* Set the driver details. */
9345 : /* -------------------------------------------------------------------- */
9346 537 : poDriver->SetDescription( "GTiff" );
9347 537 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoTIFF" );
9348 537 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_gtiff.html" );
9349 537 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/tiff" );
9350 537 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "tif" );
9351 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
9352 : "Byte UInt16 Int16 UInt32 Int32 Float32 "
9353 537 : "Float64 CInt16 CInt32 CFloat32 CFloat64" );
9354 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
9355 537 : szCreateOptions );
9356 :
9357 537 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
9358 :
9359 537 : poDriver->pfnOpen = GTiffDataset::Open;
9360 537 : poDriver->pfnCreate = GTiffDataset::Create;
9361 537 : poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
9362 537 : poDriver->pfnUnloadDriver = GDALDeregister_GTiff;
9363 537 : poDriver->pfnIdentify = GTiffDataset::Identify;
9364 :
9365 537 : GetGDALDriverManager()->RegisterDriver( poDriver );
9366 : }
9367 558 : }
|