1 : /******************************************************************************
2 : * $Id: geotiff.cpp 25654 2013-02-16 00:27:17Z rouault $
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 : #include "cplkeywordparser.h"
55 : #include "gt_jpeg_copy.h"
56 :
57 : CPL_CVSID("$Id: geotiff.cpp 25654 2013-02-16 00:27:17Z rouault $");
58 :
59 : /************************************************************************/
60 : /* ==================================================================== */
61 : /* GDALOverviewDS */
62 : /* ==================================================================== */
63 : /************************************************************************/
64 :
65 : /* GDALOverviewDS is not specific to GTiff and could probably be moved */
66 : /* in gcore. It is currently used to generate a fake */
67 : /* dataset from the overview levels of the source dataset that is taken */
68 : /* by CreateCopy() */
69 :
70 : #include "gdal_proxy.h"
71 :
72 : class GDALOverviewBand;
73 :
74 : class GDALOverviewDS : public GDALDataset
75 : {
76 : private:
77 :
78 : friend class GDALOverviewBand;
79 :
80 : GDALDataset* poDS;
81 : GDALDataset* poOvrDS;
82 : int nOvrLevel;
83 :
84 : public:
85 : GDALOverviewDS(GDALDataset* poDS, int nOvrLevel);
86 : virtual ~GDALOverviewDS();
87 :
88 : virtual char **GetMetadata( const char * pszDomain = "" );
89 : virtual const char *GetMetadataItem( const char * pszName,
90 : const char * pszDomain = "" );
91 : };
92 :
93 : class GDALOverviewBand : public GDALProxyRasterBand
94 : {
95 : protected:
96 : GDALRasterBand* poUnderlyingBand;
97 : virtual GDALRasterBand* RefUnderlyingRasterBand();
98 :
99 : public:
100 : GDALOverviewBand(GDALOverviewDS* poDS, int nBand);
101 : virtual ~GDALOverviewBand();
102 : };
103 :
104 12 : GDALOverviewDS::GDALOverviewDS(GDALDataset* poDS, int nOvrLevel)
105 : {
106 12 : this->poDS = poDS;
107 12 : this->nOvrLevel = nOvrLevel;
108 12 : eAccess = poDS->GetAccess();
109 12 : nRasterXSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetXSize();
110 12 : nRasterYSize = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetYSize();
111 12 : poOvrDS = poDS->GetRasterBand(1)->GetOverview(nOvrLevel)->GetDataset();
112 12 : nBands = poDS->GetRasterCount();
113 : int i;
114 26 : for(i=0;i<nBands;i++)
115 14 : SetBand(i+1, new GDALOverviewBand(this, i+1));
116 12 : }
117 :
118 12 : GDALOverviewDS::~GDALOverviewDS()
119 : {
120 12 : FlushCache();
121 12 : }
122 :
123 0 : char **GDALOverviewDS::GetMetadata( const char * pszDomain )
124 : {
125 0 : if (poOvrDS != NULL)
126 0 : return poOvrDS->GetMetadata(pszDomain);
127 :
128 0 : return poDS->GetMetadata(pszDomain);
129 : }
130 :
131 30 : const char *GDALOverviewDS::GetMetadataItem( const char * pszName, const char * pszDomain )
132 : {
133 30 : if (poOvrDS != NULL)
134 30 : return poOvrDS->GetMetadataItem(pszName, pszDomain);
135 :
136 0 : return poDS->GetMetadataItem(pszName, pszDomain);
137 : }
138 :
139 14 : GDALOverviewBand::GDALOverviewBand(GDALOverviewDS* poDS, int nBand)
140 : {
141 14 : this->poDS = poDS;
142 14 : this->nBand = nBand;
143 14 : poUnderlyingBand = poDS->poDS->GetRasterBand(nBand)->GetOverview(poDS->nOvrLevel);
144 14 : nRasterXSize = poDS->nRasterXSize;
145 14 : nRasterYSize = poDS->nRasterYSize;
146 14 : eDataType = poUnderlyingBand->GetRasterDataType();
147 14 : poUnderlyingBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
148 14 : }
149 :
150 14 : GDALOverviewBand::~GDALOverviewBand()
151 : {
152 14 : FlushCache();
153 14 : }
154 :
155 50 : GDALRasterBand* GDALOverviewBand::RefUnderlyingRasterBand()
156 : {
157 50 : return poUnderlyingBand;
158 : }
159 :
160 : /************************************************************************/
161 : /* IsPowerOfTwo() */
162 : /************************************************************************/
163 :
164 164 : static int IsPowerOfTwo(unsigned int i)
165 : {
166 164 : int nBitSet = 0;
167 1644 : while(i != 0)
168 : {
169 1316 : if ((i & 1))
170 164 : nBitSet ++;
171 1316 : i >>= 1;
172 : }
173 164 : return nBitSet == 1;
174 : }
175 :
176 : /************************************************************************/
177 : /* GTIFFGetOverviewBlockSize() */
178 : /************************************************************************/
179 :
180 164 : void GTIFFGetOverviewBlockSize(int* pnBlockXSize, int* pnBlockYSize)
181 : {
182 : static int bHasWarned = FALSE;
183 164 : const char* pszVal = CPLGetConfigOption("GDAL_TIFF_OVR_BLOCKSIZE", "128");
184 164 : int nOvrBlockSize = atoi(pszVal);
185 164 : if (nOvrBlockSize < 64 || nOvrBlockSize > 4096 ||
186 : !IsPowerOfTwo(nOvrBlockSize))
187 : {
188 0 : if (!bHasWarned)
189 : {
190 : CPLError(CE_Warning, CPLE_NotSupported,
191 : "Wrong value for GDAL_TIFF_OVR_BLOCKSIZE : %s. "
192 : "Should be a power of 2 between 64 and 4096. Defaulting to 128",
193 0 : pszVal);
194 0 : bHasWarned = TRUE;
195 : }
196 0 : nOvrBlockSize = 128;
197 : }
198 :
199 164 : *pnBlockXSize = nOvrBlockSize;
200 164 : *pnBlockYSize = nOvrBlockSize;
201 164 : }
202 :
203 : enum
204 : {
205 : ENDIANNESS_NATIVE,
206 : ENDIANNESS_LITTLE,
207 : ENDIANNESS_BIG
208 : };
209 :
210 : /************************************************************************/
211 : /* ==================================================================== */
212 : /* GTiffDataset */
213 : /* ==================================================================== */
214 : /************************************************************************/
215 :
216 : class GTiffRasterBand;
217 : class GTiffRGBABand;
218 : class GTiffBitmapBand;
219 :
220 : class GTiffDataset : public GDALPamDataset
221 : {
222 : friend class GTiffRasterBand;
223 : friend class GTiffSplitBand;
224 : friend class GTiffRGBABand;
225 : friend class GTiffBitmapBand;
226 : friend class GTiffSplitBitmapBand;
227 : friend class GTiffOddBitsBand;
228 :
229 : friend void GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality);
230 :
231 : TIFF *hTIFF;
232 : GTiffDataset **ppoActiveDSRef;
233 : GTiffDataset *poActiveDS; /* only used in actual base */
234 :
235 : int bScanDeferred;
236 : void ScanDirectories();
237 :
238 : toff_t nDirOffset;
239 : int bBase;
240 : int bCloseTIFFHandle; /* usefull for closing TIFF handle opened by GTIFF_DIR: */
241 :
242 : uint16 nPlanarConfig;
243 : uint16 nSamplesPerPixel;
244 : uint16 nBitsPerSample;
245 : uint32 nRowsPerStrip;
246 : uint16 nPhotometric;
247 : uint16 nSampleFormat;
248 : uint16 nCompression;
249 :
250 : int nBlocksPerBand;
251 :
252 : uint32 nBlockXSize;
253 : uint32 nBlockYSize;
254 :
255 : int nLoadedBlock; /* or tile */
256 : int bLoadedBlockDirty;
257 : GByte *pabyBlockBuf;
258 :
259 : CPLErr LoadBlockBuf( int nBlockId, int bReadFromDisk = TRUE );
260 : CPLErr FlushBlockBuf();
261 : int bWriteErrorInFlushBlockBuf;
262 :
263 : char *pszProjection;
264 : int bLookedForProjection;
265 : int bLookedForMDAreaOrPoint;
266 :
267 : void LoadMDAreaOrPoint();
268 : void LookForProjection();
269 : #ifdef ESRI_BUILD
270 : void AdjustLinearUnit( short UOMLength );
271 : #endif
272 :
273 : double adfGeoTransform[6];
274 : int bGeoTransformValid;
275 :
276 : int bTreatAsRGBA;
277 : int bCrystalized;
278 :
279 : void Crystalize();
280 :
281 : GDALColorTable *poColorTable;
282 :
283 : void WriteGeoTIFFInfo();
284 : int SetDirectory( toff_t nDirOffset = 0 );
285 :
286 : int nOverviewCount;
287 : GTiffDataset **papoOverviewDS;
288 :
289 : int nGCPCount;
290 : GDAL_GCP *pasGCPList;
291 :
292 : int IsBlockAvailable( int nBlockId );
293 :
294 : int bGeoTIFFInfoChanged;
295 : int bForceUnsetGT;
296 : int bForceUnsetProjection;
297 : int bNoDataSet;
298 : double dfNoDataValue;
299 :
300 : int bMetadataChanged;
301 :
302 : int bNeedsRewrite;
303 :
304 : void ApplyPamInfo();
305 : void PushMetadataToPam();
306 :
307 : GDALMultiDomainMetadata oGTiffMDMD;
308 :
309 : CPLString osProfile;
310 : char **papszCreationOptions;
311 :
312 : int bLoadingOtherBands;
313 :
314 : static void WriteRPCTag( TIFF *, char ** );
315 : void ReadRPCTag();
316 :
317 : void* pabyTempWriteBuffer;
318 : int nTempWriteBufferSize;
319 : int WriteEncodedTile(uint32 tile, GByte* pabyData, int bPreserveDataBuffer);
320 : int WriteEncodedStrip(uint32 strip, GByte* pabyData, int bPreserveDataBuffer);
321 :
322 : GTiffDataset* poMaskDS;
323 : GTiffDataset* poBaseDS;
324 :
325 : CPLString osFilename;
326 :
327 : int bFillEmptyTiles;
328 : void FillEmptyTiles(void);
329 :
330 : void FlushDirectory();
331 : CPLErr CleanOverviews();
332 :
333 : /* Used for the all-in-on-strip case */
334 : int nLastLineRead;
335 : int nLastBandRead;
336 : int bTreatAsSplit;
337 : int bTreatAsSplitBitmap;
338 :
339 : int bClipWarn;
340 :
341 : CPLString osRPBFile;
342 : int FindRPBFile();
343 : CPLString osRPCFile;
344 : int FindRPCFile();
345 : CPLString osIMDFile;
346 : int FindIMDFile();
347 : CPLString osPVLFile;
348 : int FindPVLFile();
349 : int bHasSearchedRPC;
350 : void LoadRPCRPB();
351 : int bHasSearchedIMD;
352 : int bHasSearchedPVL;
353 : void LoadIMDPVL();
354 :
355 : int bEXIFMetadataLoaded;
356 : void LoadEXIFMetadata();
357 :
358 : int bHasWarnedDisableAggressiveBandCaching;
359 :
360 : int bDontReloadFirstBlock; /* Hack for libtiff 3.X and #3633 */
361 :
362 : int nZLevel;
363 : int nLZMAPreset;
364 : int nJpegQuality;
365 :
366 : int bPromoteTo8Bits;
367 :
368 : int bDebugDontWriteBlocks;
369 :
370 : CPLErr RegisterNewOverviewDataset(toff_t nOverviewOffset);
371 : CPLErr CreateOverviewsFromSrcOverviews(GDALDataset* poSrcDS);
372 : CPLErr CreateInternalMaskOverviews(int nOvrBlockXSize,
373 : int nOvrBlockYSize);
374 :
375 : int bIsFinalized;
376 : int Finalize();
377 :
378 : int bIgnoreReadErrors;
379 :
380 : CPLString osWldFilename;
381 :
382 : int bDirectIO;
383 :
384 : protected:
385 : virtual int CloseDependentDatasets();
386 :
387 : public:
388 : GTiffDataset();
389 : ~GTiffDataset();
390 :
391 : virtual const char *GetProjectionRef(void);
392 : virtual CPLErr SetProjection( const char * );
393 : virtual CPLErr GetGeoTransform( double * );
394 : virtual CPLErr SetGeoTransform( double * );
395 :
396 : virtual int GetGCPCount();
397 : virtual const char *GetGCPProjection();
398 : virtual const GDAL_GCP *GetGCPs();
399 : CPLErr SetGCPs( int, const GDAL_GCP *, const char * );
400 :
401 : virtual char **GetFileList(void);
402 :
403 : virtual CPLErr IBuildOverviews( const char *, int, int *, int, int *,
404 : GDALProgressFunc, void * );
405 :
406 : CPLErr OpenOffset( TIFF *, GTiffDataset **ppoActiveDSRef,
407 : toff_t nDirOffset, int bBaseIn, GDALAccess,
408 : int bAllowRGBAInterface = TRUE, int bReadGeoTransform = FALSE,
409 : char** papszSiblingFiles = NULL);
410 :
411 : static GDALDataset *OpenDir( GDALOpenInfo * );
412 : static GDALDataset *Open( GDALOpenInfo * );
413 : static int Identify( GDALOpenInfo * );
414 : static GDALDataset *Create( const char * pszFilename,
415 : int nXSize, int nYSize, int nBands,
416 : GDALDataType eType, char ** papszParmList );
417 : static GDALDataset *CreateCopy( const char * pszFilename,
418 : GDALDataset *poSrcDS,
419 : int bStrict, char ** papszOptions,
420 : GDALProgressFunc pfnProgress,
421 : void * pProgressData );
422 : virtual void FlushCache( void );
423 :
424 : virtual CPLErr SetMetadata( char **, const char * = "" );
425 : virtual char **GetMetadata( const char * pszDomain = "" );
426 : virtual CPLErr SetMetadataItem( const char*, const char*,
427 : const char* = "" );
428 : virtual const char *GetMetadataItem( const char * pszName,
429 : const char * pszDomain = "" );
430 : virtual void *GetInternalHandle( const char * );
431 :
432 : virtual CPLErr CreateMaskBand( int nFlags );
433 :
434 : // only needed by createcopy and close code.
435 : static int WriteMetadata( GDALDataset *, TIFF *, int, const char *,
436 : const char *, char **, int bExcludeRPBandIMGFileWriting = FALSE );
437 : static void WriteNoDataValue( TIFF *, double );
438 :
439 : static TIFF * CreateLL( const char * pszFilename,
440 : int nXSize, int nYSize, int nBands,
441 : GDALDataType eType,
442 : double dfExtraSpaceForOverviews,
443 : char **papszParmList );
444 :
445 : CPLErr WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data, int bPreserveDataBuffer);
446 : };
447 :
448 : /************************************************************************/
449 : /* GTIFFSetJpegQuality() */
450 : /* Called by GTIFFBuildOverviews() to set the jpeg quality on the IFD */
451 : /* of the .ovr file */
452 : /************************************************************************/
453 :
454 4 : void GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality)
455 : {
456 4 : CPLAssert(EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
457 :
458 4 : GTiffDataset* poDS = (GTiffDataset*)hGTIFFDS;
459 4 : poDS->nJpegQuality = nJpegQuality;
460 :
461 4 : poDS->ScanDirectories();
462 :
463 : int i;
464 7 : for(i=0;i<poDS->nOverviewCount;i++)
465 3 : poDS->papoOverviewDS[i]->nJpegQuality = nJpegQuality;
466 4 : }
467 :
468 : /************************************************************************/
469 : /* ==================================================================== */
470 : /* GTiffRasterBand */
471 : /* ==================================================================== */
472 : /************************************************************************/
473 :
474 : class GTiffRasterBand : public GDALPamRasterBand
475 400149 : {
476 : friend class GTiffDataset;
477 :
478 : GDALColorInterp eBandInterp;
479 :
480 : int bHaveOffsetScale;
481 : double dfOffset;
482 : double dfScale;
483 : CPLString osUnitType;
484 : CPLString osDescription;
485 :
486 : CPLErr DirectIO( GDALRWFlag eRWFlag,
487 : int nXOff, int nYOff, int nXSize, int nYSize,
488 : void * pData, int nBufXSize, int nBufYSize,
489 : GDALDataType eBufType,
490 : int nPixelSpace, int nLineSpace );
491 :
492 : protected:
493 : GTiffDataset *poGDS;
494 : GDALMultiDomainMetadata oGTiffMDMD;
495 :
496 : int bNoDataSet;
497 : double dfNoDataValue;
498 :
499 : void NullBlock( void *pData );
500 : CPLErr FillCacheForOtherBands( int nBlockXOff, int nBlockYOff );
501 :
502 : public:
503 : GTiffRasterBand( GTiffDataset *, int );
504 :
505 : virtual CPLErr IReadBlock( int, int, void * );
506 : virtual CPLErr IWriteBlock( int, int, void * );
507 :
508 : virtual CPLErr IRasterIO( GDALRWFlag eRWFlag,
509 : int nXOff, int nYOff, int nXSize, int nYSize,
510 : void * pData, int nBufXSize, int nBufYSize,
511 : GDALDataType eBufType,
512 : int nPixelSpace, int nLineSpace );
513 :
514 : virtual const char *GetDescription() const;
515 : virtual void SetDescription( const char * );
516 :
517 : virtual GDALColorInterp GetColorInterpretation();
518 : virtual GDALColorTable *GetColorTable();
519 : virtual CPLErr SetColorTable( GDALColorTable * );
520 : virtual double GetNoDataValue( int * );
521 : virtual CPLErr SetNoDataValue( double );
522 :
523 : virtual double GetOffset( int *pbSuccess = NULL );
524 : virtual CPLErr SetOffset( double dfNewValue );
525 : virtual double GetScale( int *pbSuccess = NULL );
526 : virtual CPLErr SetScale( double dfNewValue );
527 : virtual const char* GetUnitType();
528 : virtual CPLErr SetUnitType( const char *pszNewValue );
529 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
530 :
531 : virtual CPLErr SetMetadata( char **, const char * = "" );
532 : virtual char **GetMetadata( const char * pszDomain = "" );
533 : virtual CPLErr SetMetadataItem( const char*, const char*,
534 : const char* = "" );
535 : virtual const char *GetMetadataItem( const char * pszName,
536 : const char * pszDomain = "" );
537 : virtual int GetOverviewCount();
538 : virtual GDALRasterBand *GetOverview( int );
539 :
540 : virtual GDALRasterBand *GetMaskBand();
541 : virtual int GetMaskFlags();
542 : virtual CPLErr CreateMaskBand( int nFlags );
543 : };
544 :
545 : /************************************************************************/
546 : /* GTiffRasterBand() */
547 : /************************************************************************/
548 :
549 400149 : GTiffRasterBand::GTiffRasterBand( GTiffDataset *poDS, int nBand )
550 :
551 : {
552 400149 : poGDS = poDS;
553 :
554 400149 : this->poDS = poDS;
555 400149 : this->nBand = nBand;
556 :
557 400149 : bHaveOffsetScale = FALSE;
558 400149 : dfOffset = 0.0;
559 400149 : dfScale = 1.0;
560 :
561 : /* -------------------------------------------------------------------- */
562 : /* Get the GDAL data type. */
563 : /* -------------------------------------------------------------------- */
564 400149 : uint16 nSampleFormat = poDS->nSampleFormat;
565 :
566 400149 : eDataType = GDT_Unknown;
567 :
568 400149 : if( poDS->nBitsPerSample <= 8 )
569 : {
570 397395 : eDataType = GDT_Byte;
571 397395 : if( nSampleFormat == SAMPLEFORMAT_INT )
572 9 : SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
573 :
574 : }
575 2754 : else if( poDS->nBitsPerSample <= 16 )
576 : {
577 645 : if( nSampleFormat == SAMPLEFORMAT_INT )
578 272 : eDataType = GDT_Int16;
579 : else
580 373 : eDataType = GDT_UInt16;
581 : }
582 2109 : else if( poDS->nBitsPerSample == 32 )
583 : {
584 1162 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
585 190 : eDataType = GDT_CInt16;
586 972 : else if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
587 509 : eDataType = GDT_Float32;
588 463 : else if( nSampleFormat == SAMPLEFORMAT_INT )
589 232 : eDataType = GDT_Int32;
590 : else
591 231 : eDataType = GDT_UInt32;
592 : }
593 947 : else if( poDS->nBitsPerSample == 64 )
594 : {
595 674 : if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
596 282 : eDataType = GDT_Float64;
597 392 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
598 203 : eDataType = GDT_CFloat32;
599 189 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
600 189 : eDataType = GDT_CInt32;
601 : }
602 273 : else if( poDS->nBitsPerSample == 128 )
603 : {
604 205 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
605 205 : eDataType = GDT_CFloat64;
606 : }
607 :
608 : /* -------------------------------------------------------------------- */
609 : /* Try to work out band color interpretation. */
610 : /* -------------------------------------------------------------------- */
611 400149 : int bLookForExtraSamples = FALSE;
612 :
613 400239 : if( poDS->poColorTable != NULL && nBand == 1 )
614 90 : eBandInterp = GCI_PaletteIndex;
615 400059 : else if( poDS->nPhotometric == PHOTOMETRIC_RGB
616 : || (poDS->nPhotometric == PHOTOMETRIC_YCBCR
617 : && poDS->nCompression == COMPRESSION_JPEG
618 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
619 : "YES") )) )
620 : {
621 1798 : if( nBand == 1 )
622 563 : eBandInterp = GCI_RedBand;
623 1235 : else if( nBand == 2 )
624 563 : eBandInterp = GCI_GreenBand;
625 672 : else if( nBand == 3 )
626 563 : eBandInterp = GCI_BlueBand;
627 : else
628 109 : bLookForExtraSamples = TRUE;
629 : }
630 398261 : else if( poDS->nPhotometric == PHOTOMETRIC_YCBCR )
631 : {
632 4 : if( nBand == 1 )
633 1 : eBandInterp = GCI_YCbCr_YBand;
634 3 : else if( nBand == 2 )
635 1 : eBandInterp = GCI_YCbCr_CbBand;
636 2 : else if( nBand == 3 )
637 1 : eBandInterp = GCI_YCbCr_CrBand;
638 : else
639 1 : bLookForExtraSamples = TRUE;
640 : }
641 398257 : else if( poDS->nPhotometric == PHOTOMETRIC_SEPARATED )
642 : {
643 40 : if( nBand == 1 )
644 10 : eBandInterp = GCI_CyanBand;
645 30 : else if( nBand == 2 )
646 10 : eBandInterp = GCI_MagentaBand;
647 20 : else if( nBand == 3 )
648 10 : eBandInterp = GCI_YellowBand;
649 10 : else if( nBand == 4 )
650 10 : eBandInterp = GCI_BlackBand;
651 : else
652 0 : bLookForExtraSamples = TRUE;
653 : }
654 402720 : else if( poDS->nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1 )
655 4503 : eBandInterp = GCI_GrayIndex;
656 : else
657 393714 : bLookForExtraSamples = TRUE;
658 :
659 400149 : if( bLookForExtraSamples )
660 : {
661 : uint16 *v;
662 393824 : uint16 count = 0;
663 :
664 393824 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v ) )
665 : {
666 : int nBaseSamples;
667 393654 : nBaseSamples = poDS->nSamplesPerPixel - count;
668 :
669 1181063 : if( nBand > nBaseSamples
670 393654 : && (v[nBand-nBaseSamples-1] == EXTRASAMPLE_ASSOCALPHA
671 393649 : || v[nBand-nBaseSamples-1] == EXTRASAMPLE_UNASSALPHA) )
672 106 : eBandInterp = GCI_AlphaBand;
673 : else
674 393548 : eBandInterp = GCI_Undefined;
675 : }
676 : else
677 170 : eBandInterp = GCI_Undefined;
678 : }
679 :
680 : /* -------------------------------------------------------------------- */
681 : /* Establish block size for strip or tiles. */
682 : /* -------------------------------------------------------------------- */
683 400149 : nBlockXSize = poDS->nBlockXSize;
684 400149 : nBlockYSize = poDS->nBlockYSize;
685 :
686 400149 : bNoDataSet = FALSE;
687 400149 : dfNoDataValue = -9999.0;
688 400149 : }
689 :
690 : /************************************************************************/
691 : /* DirectIO() */
692 : /************************************************************************/
693 :
694 : /* Reads directly bytes from the file using ReadMultiRange(), and by-pass */
695 : /* block reading. Restricted to simple TIFF configurations (un-tiled, */
696 : /* uncompressed data, standard data types). Particularly usefull to extract */
697 : /* sub-windows of data on a large /vsicurl dataset). */
698 :
699 1 : CPLErr GTiffRasterBand::DirectIO( GDALRWFlag eRWFlag,
700 : int nXOff, int nYOff, int nXSize, int nYSize,
701 : void * pData, int nBufXSize, int nBufYSize,
702 : GDALDataType eBufType,
703 : int nPixelSpace, int nLineSpace )
704 : {
705 1 : if( !(eRWFlag == GF_Read &&
706 : poGDS->nCompression == COMPRESSION_NONE &&
707 : (poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK ||
708 : poGDS->nPhotometric == PHOTOMETRIC_RGB ||
709 : poGDS->nPhotometric == PHOTOMETRIC_PALETTE) &&
710 : (poGDS->nBitsPerSample == 8 || (poGDS->nBitsPerSample == 16) ||
711 : poGDS->nBitsPerSample == 32 || poGDS->nBitsPerSample == 64) &&
712 : poGDS->nBitsPerSample == GDALGetDataTypeSize(eDataType) &&
713 : !TIFFIsTiled( poGDS->hTIFF )) )
714 : {
715 0 : return CE_Failure;
716 : }
717 :
718 : /*CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)",
719 : nXOff, nYOff, nXSize, nYSize,
720 : nBufXSize, nBufYSize);*/
721 :
722 : /* ==================================================================== */
723 : /* Do we have overviews that would be appropriate to satisfy */
724 : /* this request? */
725 : /* ==================================================================== */
726 2 : if( (nBufXSize < nXSize || nBufYSize < nYSize)
727 1 : && GetOverviewCount() > 0 && eRWFlag == GF_Read )
728 : {
729 : int nOverview;
730 :
731 : nOverview =
732 : GDALBandGetBestOverviewLevel(this, nXOff, nYOff, nXSize, nYSize,
733 0 : nBufXSize, nBufYSize);
734 0 : if (nOverview >= 0)
735 : {
736 0 : GDALRasterBand* poOverviewBand = GetOverview(nOverview);
737 0 : if (poOverviewBand == NULL)
738 0 : return CE_Failure;
739 :
740 : return poOverviewBand->RasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
741 : pData, nBufXSize, nBufYSize, eBufType,
742 0 : nPixelSpace, nLineSpace );
743 : }
744 : }
745 :
746 : /* Make sure that TIFFTAG_STRIPOFFSETS is up-to-date */
747 1 : if (poGDS->GetAccess() == GA_Update)
748 0 : poGDS->FlushCache();
749 :
750 : /* Get strip offsets */
751 1 : toff_t *panTIFFOffsets = NULL;
752 1 : if ( !TIFFGetField( poGDS->hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets ) ||
753 : panTIFFOffsets == NULL )
754 : {
755 0 : return CE_Failure;
756 : }
757 :
758 : int iLine;
759 1 : int nReqXSize = nXSize; /* sub-sampling or over-sampling can only be done at last stage */
760 1 : int nReqYSize = MIN(nBufYSize, nYSize); /* we can do sub-sampling at the extraction stage */
761 1 : void** ppData = (void**) VSIMalloc(nReqYSize * sizeof(void*));
762 : vsi_l_offset* panOffsets = (vsi_l_offset*)
763 1 : VSIMalloc(nReqYSize * sizeof(vsi_l_offset));
764 1 : size_t* panSizes = (size_t*) VSIMalloc(nReqYSize * sizeof(size_t));
765 1 : int eDTSize = GDALGetDataTypeSize(eDataType) / 8;
766 1 : void* pTmpBuffer = NULL;
767 1 : CPLErr eErr = CE_None;
768 1 : int nContigBands = ((poGDS->nPlanarConfig == PLANARCONFIG_CONTIG) ? poGDS->nBands : 1);
769 1 : int ePixelSize = eDTSize * nContigBands;
770 :
771 1 : if (ppData == NULL || panOffsets == NULL || panSizes == NULL)
772 0 : eErr = CE_Failure;
773 1 : else if (nXSize != nBufXSize || nYSize != nBufYSize ||
774 : eBufType != eDataType ||
775 : nPixelSpace != GDALGetDataTypeSize(eBufType) / 8 ||
776 : nContigBands > 1)
777 : {
778 : /* We need a temporary buffer for over-sampling/sub-sampling */
779 : /* and/or data type conversion */
780 1 : pTmpBuffer = VSIMalloc(nReqXSize * nReqYSize * ePixelSize);
781 1 : if (pTmpBuffer == NULL)
782 0 : eErr = CE_Failure;
783 : }
784 :
785 : /* Prepare data extraction */
786 129 : for(iLine=0;eErr == CE_None && iLine<nReqYSize;iLine++)
787 : {
788 128 : if (pTmpBuffer == NULL)
789 0 : ppData[iLine] = ((GByte*)pData) + iLine * nLineSpace;
790 : else
791 128 : ppData[iLine] = ((GByte*)pTmpBuffer) + iLine * nReqXSize * ePixelSize;
792 : int nSrcLine;
793 128 : if (nBufYSize < nYSize) /* Sub-sampling in y */
794 128 : nSrcLine = nYOff + (int)((iLine + 0.5) * nYSize / nBufYSize);
795 : else
796 0 : nSrcLine = nYOff + iLine;
797 :
798 128 : int nBlockXOff = 0;
799 128 : int nBlockYOff = nSrcLine / nBlockYSize;
800 128 : int nYOffsetInBlock = nSrcLine % nBlockYSize;
801 128 : int nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
802 128 : int nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
803 128 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
804 : {
805 0 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
806 : }
807 :
808 128 : panOffsets[iLine] = panTIFFOffsets[nBlockId];
809 128 : if (panOffsets[iLine] == 0) /* We don't support sparse files */
810 0 : eErr = CE_Failure;
811 :
812 128 : panOffsets[iLine] += (nXOff + nYOffsetInBlock * nBlockXSize) * ePixelSize;
813 128 : panSizes[iLine] = nReqXSize * ePixelSize;
814 : }
815 :
816 : /* Extract data from the file */
817 1 : if (eErr == CE_None)
818 : {
819 1 : VSILFILE* fp = (VSILFILE*) TIFFClientdata( poGDS->hTIFF );
820 1 : int nRet = VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
821 1 : if (nRet != 0)
822 0 : eErr = CE_Failure;
823 : }
824 :
825 : /* Byte-swap if necessary */
826 1 : if (eErr == CE_None && TIFFIsByteSwapped(poGDS->hTIFF))
827 : {
828 0 : for(iLine=0;iLine<nReqYSize;iLine++)
829 : {
830 0 : GDALSwapWords( ppData[iLine], eDTSize, nReqXSize * nContigBands, eDTSize);
831 : }
832 : }
833 :
834 : /* Over-sampling/sub-sampling and/or data type conversion */
835 1 : if (eErr == CE_None && pTmpBuffer != NULL)
836 : {
837 129 : for(int iY=0;iY<nBufYSize;iY++)
838 : {
839 : int iSrcY = (nBufYSize <= nYSize) ? iY :
840 128 : (int)((iY + 0.5) * nYSize / nBufYSize);
841 128 : if (nBufXSize == nXSize && nContigBands == 1)
842 : {
843 : GDALCopyWords( ppData[iSrcY], eDataType, eDTSize,
844 : ((GByte*)pData) + iY * nLineSpace,
845 : eBufType, nPixelSpace,
846 0 : nReqXSize);
847 : }
848 : else
849 : {
850 128 : GByte* pabySrcData = ((GByte*)ppData[iSrcY]) +
851 128 : ((nContigBands > 1) ? (nBand-1) : 0) * eDTSize;
852 128 : GByte* pabyDstData = ((GByte*)pData) + iY * nLineSpace;
853 16512 : for(int iX=0;iX<nBufXSize;iX++)
854 : {
855 : int iSrcX = (nBufXSize == nXSize) ? iX :
856 16384 : (int)((iX+0.5) * nXSize / nBufXSize);
857 : GDALCopyWords( pabySrcData + iSrcX * ePixelSize,
858 : eDataType, 0,
859 : pabyDstData + iX * nPixelSpace,
860 16384 : eBufType, 0, 1);
861 : }
862 : }
863 : }
864 : }
865 :
866 : /* Cleanup */
867 1 : CPLFree(pTmpBuffer);
868 1 : CPLFree(ppData);
869 1 : CPLFree(panOffsets);
870 1 : CPLFree(panSizes);
871 :
872 1 : return eErr;
873 : }
874 :
875 : /************************************************************************/
876 : /* IRasterIO() */
877 : /************************************************************************/
878 :
879 742670 : CPLErr GTiffRasterBand::IRasterIO( GDALRWFlag eRWFlag,
880 : int nXOff, int nYOff, int nXSize, int nYSize,
881 : void * pData, int nBufXSize, int nBufYSize,
882 : GDALDataType eBufType,
883 : int nPixelSpace, int nLineSpace )
884 : {
885 : CPLErr eErr;
886 :
887 : //CPLDebug("GTiff", "RasterIO(%d, %d, %d, %d, %d, %d)",
888 : // nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize);
889 :
890 742670 : if (poGDS->bDirectIO)
891 : {
892 : eErr = DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
893 : pData, nBufXSize, nBufYSize, eBufType,
894 1 : nPixelSpace, nLineSpace);
895 :
896 1 : if (eErr == CE_None)
897 1 : return eErr;
898 : }
899 :
900 742669 : if (poGDS->nBands != 1 &&
901 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
902 : eRWFlag == GF_Read &&
903 : nXSize == nBufXSize && nYSize == nBufYSize)
904 : {
905 167490 : int nBlockX1 = nXOff / nBlockXSize;
906 167490 : int nBlockY1 = nYOff / nBlockYSize;
907 167490 : int nBlockX2 = (nXOff + nXSize - 1) / nBlockXSize;
908 167490 : int nBlockY2 = (nYOff + nYSize - 1) / nBlockYSize;
909 167490 : int nXBlocks = nBlockX2 - nBlockX1 + 1;
910 167490 : int nYBlocks = nBlockY2 - nBlockY1 + 1;
911 : GIntBig nRequiredMem = (GIntBig)poGDS->nBands * nXBlocks * nYBlocks *
912 : nBlockXSize * nBlockYSize *
913 167490 : (GDALGetDataTypeSize(eDataType) / 8);
914 167490 : if (nRequiredMem > GDALGetCacheMax64())
915 : {
916 21 : if (!poGDS->bHasWarnedDisableAggressiveBandCaching)
917 : {
918 : CPLDebug("GTiff", "Disable aggressive band caching. Cache not big enough. "
919 1 : "At least " CPL_FRMT_GIB " bytes necessary", nRequiredMem);
920 1 : poGDS->bHasWarnedDisableAggressiveBandCaching = TRUE;
921 : }
922 21 : poGDS->bLoadingOtherBands = TRUE;
923 : }
924 : }
925 :
926 : eErr = GDALPamRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
927 : pData, nBufXSize, nBufYSize, eBufType,
928 742669 : nPixelSpace, nLineSpace);
929 :
930 742669 : poGDS->bLoadingOtherBands = FALSE;
931 :
932 742669 : return eErr;
933 : }
934 :
935 : /************************************************************************/
936 : /* IReadBlock() */
937 : /************************************************************************/
938 :
939 98964 : CPLErr GTiffRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
940 : void * pImage )
941 :
942 : {
943 : int nBlockBufSize, nBlockId, nBlockIdBand0;
944 98964 : CPLErr eErr = CE_None;
945 :
946 98964 : if (!poGDS->SetDirectory())
947 0 : return CE_Failure;
948 :
949 98964 : if( TIFFIsTiled(poGDS->hTIFF) )
950 13714 : nBlockBufSize = TIFFTileSize( poGDS->hTIFF );
951 : else
952 : {
953 85250 : CPLAssert( nBlockXOff == 0 );
954 85250 : nBlockBufSize = TIFFStripSize( poGDS->hTIFF );
955 : }
956 :
957 98964 : CPLAssert(nBlocksPerRow != 0);
958 98964 : nBlockIdBand0 = nBlockXOff + nBlockYOff * nBlocksPerRow;
959 98964 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
960 1241 : nBlockId = nBlockIdBand0 + (nBand-1) * poGDS->nBlocksPerBand;
961 : else
962 97723 : nBlockId = nBlockIdBand0;
963 :
964 : /* -------------------------------------------------------------------- */
965 : /* The bottom most partial tiles and strips are sometimes only */
966 : /* partially encoded. This code reduces the requested data so */
967 : /* an error won't be reported in this case. (#1179) */
968 : /* -------------------------------------------------------------------- */
969 98964 : int nBlockReqSize = nBlockBufSize;
970 :
971 98964 : if( (nBlockYOff+1) * nBlockYSize > nRasterYSize )
972 : {
973 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
974 1697 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
975 : }
976 :
977 : /* -------------------------------------------------------------------- */
978 : /* Handle the case of a strip or tile that doesn't exist yet. */
979 : /* Just set to zeros and return. */
980 : /* -------------------------------------------------------------------- */
981 98964 : if( !poGDS->IsBlockAvailable(nBlockId) )
982 : {
983 12858 : NullBlock( pImage );
984 12858 : return CE_None;
985 : }
986 :
987 : /* -------------------------------------------------------------------- */
988 : /* Handle simple case (separate, onesampleperpixel) */
989 : /* -------------------------------------------------------------------- */
990 86106 : if( poGDS->nBands == 1
991 : || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
992 : {
993 13746 : if( nBlockReqSize < nBlockBufSize )
994 439 : memset( pImage, 0, nBlockBufSize );
995 :
996 13746 : if( TIFFIsTiled( poGDS->hTIFF ) )
997 : {
998 8580 : if( TIFFReadEncodedTile( poGDS->hTIFF, nBlockId, pImage,
999 : nBlockReqSize ) == -1
1000 : && !poGDS->bIgnoreReadErrors )
1001 : {
1002 1 : memset( pImage, 0, nBlockBufSize );
1003 : CPLError( CE_Failure, CPLE_AppDefined,
1004 1 : "TIFFReadEncodedTile() failed.\n" );
1005 :
1006 1 : eErr = CE_Failure;
1007 : }
1008 : }
1009 : else
1010 : {
1011 5166 : if( TIFFReadEncodedStrip( poGDS->hTIFF, nBlockId, pImage,
1012 : nBlockReqSize ) == -1
1013 : && !poGDS->bIgnoreReadErrors )
1014 : {
1015 1 : memset( pImage, 0, nBlockBufSize );
1016 : CPLError( CE_Failure, CPLE_AppDefined,
1017 1 : "TIFFReadEncodedStrip() failed.\n" );
1018 :
1019 1 : eErr = CE_Failure;
1020 : }
1021 : }
1022 :
1023 13746 : return eErr;
1024 : }
1025 :
1026 : /* -------------------------------------------------------------------- */
1027 : /* Load desired block */
1028 : /* -------------------------------------------------------------------- */
1029 72360 : eErr = poGDS->LoadBlockBuf( nBlockId );
1030 72360 : if( eErr != CE_None )
1031 : {
1032 : memset( pImage, 0,
1033 : nBlockXSize * nBlockYSize
1034 0 : * (GDALGetDataTypeSize(eDataType) / 8) );
1035 0 : return eErr;
1036 : }
1037 :
1038 : /* -------------------------------------------------------------------- */
1039 : /* Special case for YCbCr subsampled data. */
1040 : /* -------------------------------------------------------------------- */
1041 : #ifdef notdef
1042 : if( (eBandInterp == GCI_YCbCr_YBand
1043 : || eBandInterp == GCI_YCbCr_CbBand
1044 : || eBandInterp == GCI_YCbCr_CrBand)
1045 : && poGDS->nBitsPerSample == 8 )
1046 : {
1047 : uint16 hs, vs;
1048 : int iX, iY;
1049 :
1050 : TIFFGetFieldDefaulted( poGDS->hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
1051 : &hs, &vs);
1052 :
1053 : for( iY = 0; iY < nBlockYSize; iY++ )
1054 : {
1055 : for( iX = 0; iX < nBlockXSize; iX++ )
1056 : {
1057 : int iBlock = (iY / vs) * (nBlockXSize/hs) + (iX / hs);
1058 : GByte *pabySrcBlock = poGDS->pabyBlockBuf +
1059 : (vs * hs + 2) * iBlock;
1060 :
1061 : if( eBandInterp == GCI_YCbCr_YBand )
1062 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1063 : pabySrcBlock[(iX % hs) + (iY % vs) * hs];
1064 : else if( eBandInterp == GCI_YCbCr_CbBand )
1065 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1066 : pabySrcBlock[vs * hs + 0];
1067 : else if( eBandInterp == GCI_YCbCr_CrBand )
1068 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
1069 : pabySrcBlock[vs * hs + 1];
1070 : }
1071 : }
1072 :
1073 : return CE_None;
1074 : }
1075 : #endif
1076 :
1077 : /* -------------------------------------------------------------------- */
1078 : /* Handle simple case of eight bit data, and pixel interleaving. */
1079 : /* -------------------------------------------------------------------- */
1080 72360 : if( poGDS->nBitsPerSample == 8 )
1081 : {
1082 : int i, nBlockPixels;
1083 : GByte *pabyImage;
1084 72254 : GByte *pabyImageDest = (GByte*)pImage;
1085 72254 : int nBands = poGDS->nBands;
1086 :
1087 72254 : pabyImage = poGDS->pabyBlockBuf + nBand - 1;
1088 :
1089 72254 : nBlockPixels = nBlockXSize * nBlockYSize;
1090 :
1091 : /* ==================================================================== */
1092 : /* Optimization for high number of words to transfer and some */
1093 : /* typical band numbers : we unroll the loop. */
1094 : /* ==================================================================== */
1095 : #define COPY_TO_DST_BUFFER(nBands) \
1096 : if (nBlockPixels > 100) \
1097 : { \
1098 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
1099 : { \
1100 : pabyImageDest[0] = pabyImage[0*nBands]; \
1101 : pabyImageDest[1] = pabyImage[1*nBands]; \
1102 : pabyImageDest[2] = pabyImage[2*nBands]; \
1103 : pabyImageDest[3] = pabyImage[3*nBands]; \
1104 : pabyImageDest[4] = pabyImage[4*nBands]; \
1105 : pabyImageDest[5] = pabyImage[5*nBands]; \
1106 : pabyImageDest[6] = pabyImage[6*nBands]; \
1107 : pabyImageDest[7] = pabyImage[7*nBands]; \
1108 : pabyImageDest[8] = pabyImage[8*nBands]; \
1109 : pabyImageDest[9] = pabyImage[9*nBands]; \
1110 : pabyImageDest[10] = pabyImage[10*nBands]; \
1111 : pabyImageDest[11] = pabyImage[11*nBands]; \
1112 : pabyImageDest[12] = pabyImage[12*nBands]; \
1113 : pabyImageDest[13] = pabyImage[13*nBands]; \
1114 : pabyImageDest[14] = pabyImage[14*nBands]; \
1115 : pabyImageDest[15] = pabyImage[15*nBands]; \
1116 : pabyImageDest += 16; \
1117 : pabyImage += 16*nBands; \
1118 : } \
1119 : nBlockPixels = nBlockPixels % 16; \
1120 : } \
1121 : for( i = 0; i < nBlockPixels; i++ ) \
1122 : { \
1123 : pabyImageDest[i] = *pabyImage; \
1124 : pabyImage += nBands; \
1125 : }
1126 :
1127 72254 : switch (nBands)
1128 : {
1129 4666 : case 3: COPY_TO_DST_BUFFER(3); break;
1130 1980 : case 4: COPY_TO_DST_BUFFER(4); break;
1131 : default:
1132 : {
1133 770081 : for( i = 0; i < nBlockPixels; i++ )
1134 : {
1135 704473 : pabyImageDest[i] = *pabyImage;
1136 704473 : pabyImage += nBands;
1137 : }
1138 : }
1139 : }
1140 : #undef COPY_TO_DST_BUFFER
1141 : }
1142 :
1143 : else
1144 : {
1145 : int i, nBlockPixels, nWordBytes;
1146 : GByte *pabyImage;
1147 :
1148 106 : nWordBytes = poGDS->nBitsPerSample / 8;
1149 106 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
1150 :
1151 106 : nBlockPixels = nBlockXSize * nBlockYSize;
1152 559754 : for( i = 0; i < nBlockPixels; i++ )
1153 : {
1154 2795040 : for( int j = 0; j < nWordBytes; j++ )
1155 : {
1156 2235392 : ((GByte *) pImage)[i*nWordBytes + j] = pabyImage[j];
1157 : }
1158 559648 : pabyImage += poGDS->nBands * nWordBytes;
1159 : }
1160 : }
1161 :
1162 72360 : if (eErr == CE_None)
1163 72360 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
1164 :
1165 72360 : return eErr;
1166 : }
1167 :
1168 :
1169 : /************************************************************************/
1170 : /* FillCacheForOtherBands() */
1171 : /************************************************************************/
1172 :
1173 72376 : CPLErr GTiffRasterBand::FillCacheForOtherBands( int nBlockXOff, int nBlockYOff )
1174 :
1175 : {
1176 72376 : CPLErr eErr = CE_None;
1177 : /* -------------------------------------------------------------------- */
1178 : /* In the fairly common case of pixel interleaved 8bit data */
1179 : /* that is multi-band, lets push the rest of the data into the */
1180 : /* block cache too, to avoid (hopefully) having to redecode it. */
1181 : /* */
1182 : /* Our following logic actually depends on the fact that the */
1183 : /* this block is already loaded, so subsequent calls will end */
1184 : /* up back in this method and pull from the loaded block. */
1185 : /* */
1186 : /* Be careful not entering this portion of code from */
1187 : /* the other bands, otherwise we'll get very deep nested calls */
1188 : /* and O(nBands^2) performance ! */
1189 : /* */
1190 : /* If there are many bands and the block cache size is not big */
1191 : /* enough to accomodate the size of all the blocks, don't enter */
1192 : /* -------------------------------------------------------------------- */
1193 72376 : if( poGDS->nBands != 1 && !poGDS->bLoadingOtherBands &&
1194 : nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) < GDALGetCacheMax64() / poGDS->nBands)
1195 : {
1196 : int iOtherBand;
1197 :
1198 2126 : poGDS->bLoadingOtherBands = TRUE;
1199 :
1200 74499 : for( iOtherBand = 1; iOtherBand <= poGDS->nBands; iOtherBand++ )
1201 : {
1202 72373 : if( iOtherBand == nBand )
1203 2126 : continue;
1204 :
1205 : GDALRasterBlock *poBlock;
1206 :
1207 : poBlock = poGDS->GetRasterBand(iOtherBand)->
1208 70247 : GetLockedBlockRef(nBlockXOff,nBlockYOff);
1209 70247 : if (poBlock == NULL)
1210 : {
1211 0 : eErr = CE_Failure;
1212 0 : break;
1213 : }
1214 70247 : poBlock->DropLock();
1215 : }
1216 :
1217 2126 : poGDS->bLoadingOtherBands = FALSE;
1218 : }
1219 :
1220 72376 : return eErr;
1221 : }
1222 :
1223 : /************************************************************************/
1224 : /* IWriteBlock() */
1225 : /************************************************************************/
1226 :
1227 27590 : CPLErr GTiffRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1228 : void * pImage )
1229 :
1230 : {
1231 : int nBlockId;
1232 27590 : CPLErr eErr = CE_None;
1233 :
1234 27590 : if (poGDS->bDebugDontWriteBlocks)
1235 7024 : return CE_None;
1236 :
1237 20566 : if (poGDS->bWriteErrorInFlushBlockBuf)
1238 : {
1239 : /* Report as an error if a previously loaded block couldn't be */
1240 : /* written correctly */
1241 0 : poGDS->bWriteErrorInFlushBlockBuf = FALSE;
1242 0 : return CE_Failure;
1243 : }
1244 :
1245 20566 : if (!poGDS->SetDirectory())
1246 0 : return CE_Failure;
1247 :
1248 : CPLAssert( poGDS != NULL
1249 : && nBlockXOff >= 0
1250 : && nBlockYOff >= 0
1251 20566 : && pImage != NULL );
1252 20566 : CPLAssert(nBlocksPerRow != 0);
1253 :
1254 : /* -------------------------------------------------------------------- */
1255 : /* Handle case of "separate" images */
1256 : /* -------------------------------------------------------------------- */
1257 20566 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
1258 : || poGDS->nBands == 1 )
1259 : {
1260 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow
1261 15953 : + (nBand-1) * poGDS->nBlocksPerBand;
1262 :
1263 15953 : eErr = poGDS->WriteEncodedTileOrStrip(nBlockId, pImage, TRUE);
1264 :
1265 15953 : return eErr;
1266 : }
1267 :
1268 : /* -------------------------------------------------------------------- */
1269 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
1270 : /* -------------------------------------------------------------------- */
1271 4613 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1272 :
1273 4613 : eErr = poGDS->LoadBlockBuf( nBlockId );
1274 4613 : if( eErr != CE_None )
1275 0 : return eErr;
1276 :
1277 : /* -------------------------------------------------------------------- */
1278 : /* On write of pixel interleaved data, we might as well flush */
1279 : /* out any other bands that are dirty in our cache. This is */
1280 : /* especially helpful when writing compressed blocks. */
1281 : /* -------------------------------------------------------------------- */
1282 : int iBand;
1283 4613 : int nWordBytes = poGDS->nBitsPerSample / 8;
1284 4613 : int nBands = poGDS->nBands;
1285 :
1286 20726 : for( iBand = 0; iBand < nBands; iBand++ )
1287 : {
1288 16113 : const GByte *pabyThisImage = NULL;
1289 16113 : GDALRasterBlock *poBlock = NULL;
1290 :
1291 16113 : if( iBand+1 == nBand )
1292 4613 : pabyThisImage = (GByte *) pImage;
1293 : else
1294 : {
1295 : poBlock = ((GTiffRasterBand *)poGDS->GetRasterBand( iBand+1 ))
1296 11500 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
1297 :
1298 11500 : if( poBlock == NULL )
1299 226 : continue;
1300 :
1301 11274 : if( !poBlock->GetDirty() )
1302 : {
1303 199 : poBlock->DropLock();
1304 199 : continue;
1305 : }
1306 :
1307 11075 : pabyThisImage = (GByte *) poBlock->GetDataRef();
1308 : }
1309 :
1310 15688 : int i, nBlockPixels = nBlockXSize * nBlockYSize;
1311 15688 : GByte *pabyOut = poGDS->pabyBlockBuf + iBand*nWordBytes;
1312 :
1313 15688 : if (nWordBytes == 1)
1314 : {
1315 :
1316 : /* ==================================================================== */
1317 : /* Optimization for high number of words to transfer and some */
1318 : /* typical band numbers : we unroll the loop. */
1319 : /* ==================================================================== */
1320 : #define COPY_TO_DST_BUFFER(nBands) \
1321 : if (nBlockPixels > 100) \
1322 : { \
1323 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
1324 : { \
1325 : pabyOut[0*nBands] = pabyThisImage[0]; \
1326 : pabyOut[1*nBands] = pabyThisImage[1]; \
1327 : pabyOut[2*nBands] = pabyThisImage[2]; \
1328 : pabyOut[3*nBands] = pabyThisImage[3]; \
1329 : pabyOut[4*nBands] = pabyThisImage[4]; \
1330 : pabyOut[5*nBands] = pabyThisImage[5]; \
1331 : pabyOut[6*nBands] = pabyThisImage[6]; \
1332 : pabyOut[7*nBands] = pabyThisImage[7]; \
1333 : pabyOut[8*nBands] = pabyThisImage[8]; \
1334 : pabyOut[9*nBands] = pabyThisImage[9]; \
1335 : pabyOut[10*nBands] = pabyThisImage[10]; \
1336 : pabyOut[11*nBands] = pabyThisImage[11]; \
1337 : pabyOut[12*nBands] = pabyThisImage[12]; \
1338 : pabyOut[13*nBands] = pabyThisImage[13]; \
1339 : pabyOut[14*nBands] = pabyThisImage[14]; \
1340 : pabyOut[15*nBands] = pabyThisImage[15]; \
1341 : pabyThisImage += 16; \
1342 : pabyOut += 16*nBands; \
1343 : } \
1344 : nBlockPixels = nBlockPixels % 16; \
1345 : } \
1346 : for( i = 0; i < nBlockPixels; i++ ) \
1347 : { \
1348 : *pabyOut = pabyThisImage[i]; \
1349 : pabyOut += nBands; \
1350 : }
1351 :
1352 15624 : switch (nBands)
1353 : {
1354 6479 : case 3: COPY_TO_DST_BUFFER(3); break;
1355 9029 : case 4: COPY_TO_DST_BUFFER(4); break;
1356 : default:
1357 : {
1358 446514 : for( i = 0; i < nBlockPixels; i++ )
1359 : {
1360 446398 : *pabyOut = pabyThisImage[i];
1361 446398 : pabyOut += nBands;
1362 : }
1363 : }
1364 : }
1365 : #undef COPY_TO_DST_BUFFER
1366 : }
1367 : else
1368 : {
1369 205496 : for( i = 0; i < nBlockPixels; i++ )
1370 : {
1371 205432 : memcpy( pabyOut, pabyThisImage, nWordBytes );
1372 :
1373 205432 : pabyOut += nWordBytes * nBands;
1374 205432 : pabyThisImage += nWordBytes;
1375 : }
1376 : }
1377 :
1378 15688 : if( poBlock != NULL )
1379 : {
1380 11075 : poBlock->MarkClean();
1381 11075 : poBlock->DropLock();
1382 : }
1383 : }
1384 :
1385 4613 : poGDS->bLoadedBlockDirty = TRUE;
1386 :
1387 4613 : return CE_None;
1388 : }
1389 :
1390 : /************************************************************************/
1391 : /* SetDescription() */
1392 : /************************************************************************/
1393 :
1394 11 : void GTiffRasterBand::SetDescription( const char *pszDescription )
1395 :
1396 : {
1397 11 : if( pszDescription == NULL )
1398 0 : pszDescription = "";
1399 :
1400 11 : osDescription = pszDescription;
1401 11 : }
1402 :
1403 : /************************************************************************/
1404 : /* GetDescription() */
1405 : /************************************************************************/
1406 :
1407 134318 : const char *GTiffRasterBand::GetDescription() const
1408 : {
1409 134318 : return osDescription;
1410 : }
1411 :
1412 : /************************************************************************/
1413 : /* GetOffset() */
1414 : /************************************************************************/
1415 :
1416 134160 : double GTiffRasterBand::GetOffset( int *pbSuccess )
1417 :
1418 : {
1419 134160 : if( pbSuccess )
1420 1101 : *pbSuccess = bHaveOffsetScale;
1421 134160 : return dfOffset;
1422 : }
1423 :
1424 : /************************************************************************/
1425 : /* SetOffset() */
1426 : /************************************************************************/
1427 :
1428 14 : CPLErr GTiffRasterBand::SetOffset( double dfNewValue )
1429 :
1430 : {
1431 14 : if( !bHaveOffsetScale || dfNewValue != dfOffset )
1432 14 : poGDS->bMetadataChanged = TRUE;
1433 :
1434 14 : bHaveOffsetScale = TRUE;
1435 14 : dfOffset = dfNewValue;
1436 14 : return CE_None;
1437 : }
1438 :
1439 : /************************************************************************/
1440 : /* GetScale() */
1441 : /************************************************************************/
1442 :
1443 134160 : double GTiffRasterBand::GetScale( int *pbSuccess )
1444 :
1445 : {
1446 134160 : if( pbSuccess )
1447 1101 : *pbSuccess = bHaveOffsetScale;
1448 134160 : return dfScale;
1449 : }
1450 :
1451 : /************************************************************************/
1452 : /* SetScale() */
1453 : /************************************************************************/
1454 :
1455 14 : CPLErr GTiffRasterBand::SetScale( double dfNewValue )
1456 :
1457 : {
1458 14 : if( !bHaveOffsetScale || dfNewValue != dfScale )
1459 14 : poGDS->bMetadataChanged = TRUE;
1460 :
1461 14 : bHaveOffsetScale = TRUE;
1462 14 : dfScale = dfNewValue;
1463 14 : return CE_None;
1464 : }
1465 :
1466 : /************************************************************************/
1467 : /* GetUnitType() */
1468 : /************************************************************************/
1469 :
1470 133734 : const char* GTiffRasterBand::GetUnitType()
1471 :
1472 : {
1473 133734 : return osUnitType.c_str();
1474 : }
1475 :
1476 : /************************************************************************/
1477 : /* SetUnitType() */
1478 : /************************************************************************/
1479 :
1480 22 : CPLErr GTiffRasterBand::SetUnitType( const char* pszNewValue )
1481 :
1482 : {
1483 22 : CPLString osNewValue(pszNewValue ? pszNewValue : "");
1484 22 : if( osNewValue.compare(osUnitType) != 0 )
1485 21 : poGDS->bMetadataChanged = TRUE;
1486 :
1487 22 : osUnitType = osNewValue;
1488 22 : return CE_None;
1489 : }
1490 :
1491 : /************************************************************************/
1492 : /* GetMetadata() */
1493 : /************************************************************************/
1494 :
1495 2678 : char **GTiffRasterBand::GetMetadata( const char * pszDomain )
1496 :
1497 : {
1498 2678 : return oGTiffMDMD.GetMetadata( pszDomain );
1499 : }
1500 :
1501 : /************************************************************************/
1502 : /* SetMetadata() */
1503 : /************************************************************************/
1504 :
1505 376 : CPLErr GTiffRasterBand::SetMetadata( char ** papszMD, const char *pszDomain )
1506 :
1507 : {
1508 376 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1509 : {
1510 376 : if( papszMD != NULL )
1511 38 : poGDS->bMetadataChanged = TRUE;
1512 : }
1513 :
1514 376 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
1515 : }
1516 :
1517 : /************************************************************************/
1518 : /* GetMetadataItem() */
1519 : /************************************************************************/
1520 :
1521 5489 : const char *GTiffRasterBand::GetMetadataItem( const char * pszName,
1522 : const char * pszDomain )
1523 :
1524 : {
1525 5489 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
1526 : }
1527 :
1528 : /************************************************************************/
1529 : /* SetMetadataItem() */
1530 : /************************************************************************/
1531 :
1532 709 : CPLErr GTiffRasterBand::SetMetadataItem( const char *pszName,
1533 : const char *pszValue,
1534 : const char *pszDomain )
1535 :
1536 : {
1537 709 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1538 709 : poGDS->bMetadataChanged = TRUE;
1539 :
1540 709 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
1541 : }
1542 :
1543 : /************************************************************************/
1544 : /* GetColorInterpretation() */
1545 : /************************************************************************/
1546 :
1547 3811 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1548 :
1549 : {
1550 3811 : return eBandInterp;
1551 : }
1552 :
1553 : /************************************************************************/
1554 : /* GTiffGetAlphaValue() */
1555 : /************************************************************************/
1556 :
1557 : /* Note: was EXTRASAMPLE_ASSOCALPHA in GDAL < 1.10 */
1558 : #define DEFAULT_ALPHA_TYPE EXTRASAMPLE_UNASSALPHA
1559 :
1560 102 : static int GTiffGetAlphaValue(const char* pszValue, int nDefault)
1561 : {
1562 102 : if (pszValue == NULL)
1563 101 : return nDefault;
1564 1 : else if (EQUAL(pszValue, "YES"))
1565 1 : return DEFAULT_ALPHA_TYPE;
1566 0 : else if (EQUAL(pszValue, "PREMULTIPLIED"))
1567 0 : return EXTRASAMPLE_ASSOCALPHA;
1568 0 : else if (EQUAL(pszValue, "NON-PREMULTIPLIED"))
1569 0 : return EXTRASAMPLE_UNASSALPHA;
1570 0 : else if (EQUAL(pszValue, "NO") ||
1571 : EQUAL(pszValue, "UNSPECIFIED"))
1572 0 : return EXTRASAMPLE_UNSPECIFIED;
1573 : else
1574 0 : return nDefault;
1575 : }
1576 :
1577 : /************************************************************************/
1578 : /* SetColorInterpretation() */
1579 : /************************************************************************/
1580 :
1581 20 : CPLErr GTiffRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
1582 :
1583 : {
1584 20 : if( eInterp == eBandInterp )
1585 12 : return CE_None;
1586 :
1587 8 : if( poGDS->bCrystalized )
1588 0 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1589 :
1590 : /* greyscale + alpha */
1591 8 : else if( eInterp == GCI_AlphaBand
1592 : && nBand == 2
1593 : && poGDS->nSamplesPerPixel == 2
1594 : && poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK )
1595 : {
1596 : uint16 v[1];
1597 : v[0] = GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", NULL),
1598 1 : DEFAULT_ALPHA_TYPE);
1599 :
1600 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1601 1 : eBandInterp = eInterp;
1602 1 : return CE_None;
1603 : }
1604 :
1605 : /* RGB + alpha */
1606 7 : else if( eInterp == GCI_AlphaBand
1607 : && nBand == 4
1608 : && poGDS->nSamplesPerPixel == 4
1609 : && poGDS->nPhotometric == PHOTOMETRIC_RGB )
1610 : {
1611 : uint16 v[1];
1612 : v[0] = GTiffGetAlphaValue(CPLGetConfigOption("GTIFF_ALPHA", NULL),
1613 1 : DEFAULT_ALPHA_TYPE);
1614 :
1615 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1616 1 : eBandInterp = eInterp;
1617 1 : return CE_None;
1618 : }
1619 :
1620 : else
1621 6 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1622 : }
1623 :
1624 : /************************************************************************/
1625 : /* GetColorTable() */
1626 : /************************************************************************/
1627 :
1628 2486 : GDALColorTable *GTiffRasterBand::GetColorTable()
1629 :
1630 : {
1631 2486 : if( nBand == 1 )
1632 2039 : return poGDS->poColorTable;
1633 : else
1634 447 : return NULL;
1635 : }
1636 :
1637 : /************************************************************************/
1638 : /* SetColorTable() */
1639 : /************************************************************************/
1640 :
1641 17 : CPLErr GTiffRasterBand::SetColorTable( GDALColorTable * poCT )
1642 :
1643 : {
1644 : /* -------------------------------------------------------------------- */
1645 : /* Check if this is even a candidate for applying a PCT. */
1646 : /* -------------------------------------------------------------------- */
1647 17 : if( nBand != 1)
1648 : {
1649 : CPLError( CE_Failure, CPLE_NotSupported,
1650 0 : "SetColorTable() can only be called on band 1." );
1651 0 : return CE_Failure;
1652 : }
1653 :
1654 17 : if( poGDS->nSamplesPerPixel != 1 && poGDS->nSamplesPerPixel != 2)
1655 : {
1656 : CPLError( CE_Failure, CPLE_NotSupported,
1657 0 : "SetColorTable() not supported for multi-sample TIFF files." );
1658 0 : return CE_Failure;
1659 : }
1660 :
1661 17 : if( eDataType != GDT_Byte && eDataType != GDT_UInt16 )
1662 : {
1663 : CPLError( CE_Failure, CPLE_NotSupported,
1664 0 : "SetColorTable() only supported for Byte or UInt16 bands in TIFF format." );
1665 0 : return CE_Failure;
1666 : }
1667 :
1668 : /* -------------------------------------------------------------------- */
1669 : /* We are careful about calling SetDirectory() to avoid */
1670 : /* prematurely crystalizing the directory. (#2820) */
1671 : /* -------------------------------------------------------------------- */
1672 17 : if( poGDS->bCrystalized )
1673 : {
1674 6 : if (!poGDS->SetDirectory())
1675 0 : return CE_Failure;
1676 : }
1677 :
1678 : /* -------------------------------------------------------------------- */
1679 : /* Is this really a request to clear the color table? */
1680 : /* -------------------------------------------------------------------- */
1681 17 : if( poCT == NULL || poCT->GetColorEntryCount() == 0 )
1682 : {
1683 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC,
1684 1 : PHOTOMETRIC_MINISBLACK );
1685 :
1686 : #ifdef HAVE_UNSETFIELD
1687 1 : TIFFUnsetField( poGDS->hTIFF, TIFFTAG_COLORMAP );
1688 : #else
1689 : CPLDebug( "GTiff",
1690 : "TIFFUnsetField() not supported, colormap may not be cleared." );
1691 : #endif
1692 :
1693 1 : if( poGDS->poColorTable )
1694 : {
1695 1 : delete poGDS->poColorTable;
1696 1 : poGDS->poColorTable = NULL;
1697 : }
1698 :
1699 1 : return CE_None;
1700 : }
1701 :
1702 : /* -------------------------------------------------------------------- */
1703 : /* Write out the colortable, and update the configuration. */
1704 : /* -------------------------------------------------------------------- */
1705 : int nColors;
1706 :
1707 16 : if( eDataType == GDT_Byte )
1708 15 : nColors = 256;
1709 : else
1710 1 : nColors = 65536;
1711 :
1712 : unsigned short *panTRed, *panTGreen, *panTBlue;
1713 :
1714 16 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1715 16 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1716 16 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1717 :
1718 69392 : for( int iColor = 0; iColor < nColors; iColor++ )
1719 : {
1720 69376 : if( iColor < poCT->GetColorEntryCount() )
1721 : {
1722 : GDALColorEntry sRGB;
1723 :
1724 826 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
1725 :
1726 826 : panTRed[iColor] = (unsigned short) (257 * sRGB.c1);
1727 826 : panTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
1728 826 : panTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
1729 : }
1730 : else
1731 : {
1732 68550 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
1733 : }
1734 : }
1735 :
1736 16 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
1737 : TIFFSetField( poGDS->hTIFF, TIFFTAG_COLORMAP,
1738 16 : panTRed, panTGreen, panTBlue );
1739 :
1740 16 : CPLFree( panTRed );
1741 16 : CPLFree( panTGreen );
1742 16 : CPLFree( panTBlue );
1743 :
1744 16 : if( poGDS->poColorTable )
1745 3 : delete poGDS->poColorTable;
1746 :
1747 : /* libtiff 3.X needs setting this in all cases (creation or update) */
1748 : /* whereas libtiff 4.X would just need it if there */
1749 : /* was no color table before */
1750 : #if 0
1751 : else
1752 : #endif
1753 16 : poGDS->bNeedsRewrite = TRUE;
1754 :
1755 16 : poGDS->poColorTable = poCT->Clone();
1756 16 : eBandInterp = GCI_PaletteIndex;
1757 :
1758 16 : return CE_None;
1759 : }
1760 :
1761 : /************************************************************************/
1762 : /* GetNoDataValue() */
1763 : /************************************************************************/
1764 :
1765 20527 : double GTiffRasterBand::GetNoDataValue( int * pbSuccess )
1766 :
1767 : {
1768 20527 : if( bNoDataSet )
1769 : {
1770 105 : if( pbSuccess )
1771 94 : *pbSuccess = TRUE;
1772 :
1773 105 : return dfNoDataValue;
1774 : }
1775 :
1776 20422 : if( poGDS->bNoDataSet )
1777 : {
1778 264 : if( pbSuccess )
1779 245 : *pbSuccess = TRUE;
1780 :
1781 264 : return poGDS->dfNoDataValue;
1782 : }
1783 :
1784 20158 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
1785 : }
1786 :
1787 : /************************************************************************/
1788 : /* SetNoDataValue() */
1789 : /************************************************************************/
1790 :
1791 73 : CPLErr GTiffRasterBand::SetNoDataValue( double dfNoData )
1792 :
1793 : {
1794 73 : if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
1795 21 : return CE_None;
1796 :
1797 52 : if (!poGDS->SetDirectory()) // needed to call TIFFSetField().
1798 0 : return CE_Failure;
1799 :
1800 52 : poGDS->bNoDataSet = TRUE;
1801 52 : poGDS->dfNoDataValue = dfNoData;
1802 :
1803 52 : poGDS->WriteNoDataValue( poGDS->hTIFF, dfNoData );
1804 52 : poGDS->bNeedsRewrite = TRUE;
1805 :
1806 52 : bNoDataSet = TRUE;
1807 52 : dfNoDataValue = dfNoData;
1808 52 : return CE_None;
1809 : }
1810 :
1811 : /************************************************************************/
1812 : /* NullBlock() */
1813 : /* */
1814 : /* Set the block data to the null value if it is set, or zero */
1815 : /* if there is no null data value. */
1816 : /************************************************************************/
1817 :
1818 13424 : void GTiffRasterBand::NullBlock( void *pData )
1819 :
1820 : {
1821 13424 : int nWords = nBlockXSize * nBlockYSize;
1822 13424 : int nChunkSize = MAX(1,GDALGetDataTypeSize(eDataType)/8);
1823 :
1824 : int bNoDataSet;
1825 13424 : double dfNoData = GetNoDataValue( &bNoDataSet );
1826 13424 : if( !bNoDataSet )
1827 : {
1828 : #ifdef ESRI_BUILD
1829 : if ( poGDS->nBitsPerSample >= 2 )
1830 : memset( pData, 0, nWords*nChunkSize );
1831 : else
1832 : memset( pData, 1, nWords*nChunkSize );
1833 : #else
1834 13333 : memset( pData, 0, nWords*nChunkSize );
1835 : #endif
1836 : }
1837 : else
1838 : {
1839 : /* Will convert nodata value to the right type and copy efficiently */
1840 : GDALCopyWords( &dfNoData, GDT_Float64, 0,
1841 91 : pData, eDataType, nChunkSize, nWords);
1842 : }
1843 13424 : }
1844 :
1845 : /************************************************************************/
1846 : /* GetOverviewCount() */
1847 : /************************************************************************/
1848 :
1849 302351 : int GTiffRasterBand::GetOverviewCount()
1850 :
1851 : {
1852 302351 : poGDS->ScanDirectories();
1853 :
1854 302351 : if( poGDS->nOverviewCount > 0 )
1855 1026 : return poGDS->nOverviewCount;
1856 : else
1857 301325 : return GDALRasterBand::GetOverviewCount();
1858 : }
1859 :
1860 : /************************************************************************/
1861 : /* GetOverview() */
1862 : /************************************************************************/
1863 :
1864 1134 : GDALRasterBand *GTiffRasterBand::GetOverview( int i )
1865 :
1866 : {
1867 1134 : poGDS->ScanDirectories();
1868 :
1869 1134 : if( poGDS->nOverviewCount > 0 )
1870 : {
1871 850 : if( i < 0 || i >= poGDS->nOverviewCount )
1872 2 : return NULL;
1873 : else
1874 848 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
1875 : }
1876 : else
1877 284 : return GDALRasterBand::GetOverview( i );
1878 : }
1879 :
1880 : /************************************************************************/
1881 : /* GetMaskFlags() */
1882 : /************************************************************************/
1883 :
1884 3411 : int GTiffRasterBand::GetMaskFlags()
1885 : {
1886 3411 : poGDS->ScanDirectories();
1887 :
1888 3411 : if( poGDS->poMaskDS != NULL )
1889 : {
1890 51 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1891 : {
1892 45 : return GMF_PER_DATASET;
1893 : }
1894 : else
1895 : {
1896 6 : return 0;
1897 : }
1898 : }
1899 : else
1900 3360 : return GDALPamRasterBand::GetMaskFlags();
1901 : }
1902 :
1903 : /************************************************************************/
1904 : /* GetMaskBand() */
1905 : /************************************************************************/
1906 :
1907 2500 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1908 : {
1909 2500 : poGDS->ScanDirectories();
1910 :
1911 2500 : if( poGDS->poMaskDS != NULL )
1912 : {
1913 1419 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1914 1413 : return poGDS->poMaskDS->GetRasterBand(1);
1915 : else
1916 6 : return poGDS->poMaskDS->GetRasterBand(nBand);
1917 : }
1918 : else
1919 1081 : return GDALPamRasterBand::GetMaskBand();
1920 : }
1921 :
1922 : /************************************************************************/
1923 : /* ==================================================================== */
1924 : /* GTiffSplitBand */
1925 : /* ==================================================================== */
1926 : /************************************************************************/
1927 :
1928 : class GTiffSplitBand : public GTiffRasterBand
1929 : {
1930 : friend class GTiffDataset;
1931 :
1932 : public:
1933 :
1934 : GTiffSplitBand( GTiffDataset *, int );
1935 : virtual ~GTiffSplitBand();
1936 :
1937 : virtual CPLErr IReadBlock( int, int, void * );
1938 : virtual CPLErr IWriteBlock( int, int, void * );
1939 : };
1940 :
1941 : /************************************************************************/
1942 : /* GTiffSplitBand() */
1943 : /************************************************************************/
1944 :
1945 28 : GTiffSplitBand::GTiffSplitBand( GTiffDataset *poDS, int nBand )
1946 28 : : GTiffRasterBand( poDS, nBand )
1947 :
1948 : {
1949 28 : nBlockXSize = poDS->GetRasterXSize();
1950 28 : nBlockYSize = 1;
1951 28 : }
1952 :
1953 : /************************************************************************/
1954 : /* ~GTiffSplitBand() */
1955 : /************************************************************************/
1956 :
1957 28 : GTiffSplitBand::~GTiffSplitBand()
1958 : {
1959 28 : }
1960 :
1961 : /************************************************************************/
1962 : /* IReadBlock() */
1963 : /************************************************************************/
1964 :
1965 69856 : CPLErr GTiffSplitBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1966 : void * pImage )
1967 :
1968 : {
1969 : (void) nBlockXOff;
1970 :
1971 : /* Optimization when reading the same line in a contig multi-band TIFF */
1972 69856 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 &&
1973 : poGDS->nLastLineRead == nBlockYOff )
1974 : {
1975 9 : goto extract_band_data;
1976 : }
1977 :
1978 69847 : if (!poGDS->SetDirectory())
1979 0 : return CE_Failure;
1980 :
1981 109694 : if (poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
1982 : poGDS->nBands > 1)
1983 : {
1984 39847 : if (poGDS->pabyBlockBuf == NULL)
1985 4 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
1986 : }
1987 : else
1988 : {
1989 30000 : CPLAssert(TIFFScanlineSize(poGDS->hTIFF) == nBlockXSize);
1990 : }
1991 :
1992 : /* -------------------------------------------------------------------- */
1993 : /* Read through to target scanline. */
1994 : /* -------------------------------------------------------------------- */
1995 69847 : if( poGDS->nLastLineRead >= nBlockYOff )
1996 31 : poGDS->nLastLineRead = -1;
1997 :
1998 69847 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE && poGDS->nBands > 1 )
1999 : {
2000 : /* If we change of band, we must start reading the */
2001 : /* new strip from its beginning */
2002 30000 : if ( poGDS->nLastBandRead != nBand )
2003 20 : poGDS->nLastLineRead = -1;
2004 30000 : poGDS->nLastBandRead = nBand;
2005 : }
2006 :
2007 258854 : while( poGDS->nLastLineRead < nBlockYOff )
2008 : {
2009 119160 : if( TIFFReadScanline( poGDS->hTIFF,
2010 : poGDS->pabyBlockBuf ? poGDS->pabyBlockBuf : pImage,
2011 : ++poGDS->nLastLineRead,
2012 : (poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE) ? (uint16) (nBand-1) : 0 ) == -1
2013 : && !poGDS->bIgnoreReadErrors )
2014 : {
2015 : CPLError( CE_Failure, CPLE_AppDefined,
2016 0 : "TIFFReadScanline() failed." );
2017 0 : return CE_Failure;
2018 : }
2019 : }
2020 :
2021 : extract_band_data:
2022 : /* -------------------------------------------------------------------- */
2023 : /* Extract band data from contig buffer. */
2024 : /* -------------------------------------------------------------------- */
2025 69856 : if ( poGDS->pabyBlockBuf != NULL )
2026 : {
2027 39856 : int iPixel, iSrcOffset= nBand - 1, iDstOffset=0;
2028 :
2029 13947104 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset+=poGDS->nBands, iDstOffset++ )
2030 : {
2031 13907248 : ((GByte *) pImage)[iDstOffset] = poGDS->pabyBlockBuf[iSrcOffset];
2032 : }
2033 : }
2034 :
2035 69856 : return CE_None;
2036 : }
2037 :
2038 : /************************************************************************/
2039 : /* IWriteBlock() */
2040 : /************************************************************************/
2041 :
2042 0 : CPLErr GTiffSplitBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2043 : void * pImage )
2044 :
2045 : {
2046 : (void) nBlockXOff;
2047 : (void) nBlockYOff;
2048 : (void) pImage;
2049 :
2050 : CPLError( CE_Failure, CPLE_AppDefined,
2051 0 : "Split bands are read-only." );
2052 0 : return CE_Failure;
2053 : }
2054 :
2055 : /************************************************************************/
2056 : /* ==================================================================== */
2057 : /* GTiffRGBABand */
2058 : /* ==================================================================== */
2059 : /************************************************************************/
2060 :
2061 : class GTiffRGBABand : public GTiffRasterBand
2062 20 : {
2063 : friend class GTiffDataset;
2064 :
2065 : public:
2066 :
2067 : GTiffRGBABand( GTiffDataset *, int );
2068 :
2069 : virtual CPLErr IReadBlock( int, int, void * );
2070 : virtual CPLErr IWriteBlock( int, int, void * );
2071 :
2072 : virtual GDALColorInterp GetColorInterpretation();
2073 : };
2074 :
2075 :
2076 : /************************************************************************/
2077 : /* GTiffRGBABand() */
2078 : /************************************************************************/
2079 :
2080 20 : GTiffRGBABand::GTiffRGBABand( GTiffDataset *poDS, int nBand )
2081 20 : : GTiffRasterBand( poDS, nBand )
2082 :
2083 : {
2084 20 : eDataType = GDT_Byte;
2085 20 : }
2086 :
2087 : /************************************************************************/
2088 : /* IWriteBlock() */
2089 : /************************************************************************/
2090 :
2091 0 : CPLErr GTiffRGBABand::IWriteBlock( int, int, void * )
2092 :
2093 : {
2094 : CPLError( CE_Failure, CPLE_AppDefined,
2095 0 : "RGBA interpreted raster bands are read-only." );
2096 0 : return CE_Failure;
2097 : }
2098 :
2099 : /************************************************************************/
2100 : /* IReadBlock() */
2101 : /************************************************************************/
2102 :
2103 16 : CPLErr GTiffRGBABand::IReadBlock( int nBlockXOff, int nBlockYOff,
2104 : void * pImage )
2105 :
2106 : {
2107 : int nBlockBufSize, nBlockId;
2108 16 : CPLErr eErr = CE_None;
2109 :
2110 16 : if (!poGDS->SetDirectory())
2111 0 : return CE_Failure;
2112 :
2113 16 : CPLAssert(nBlocksPerRow != 0);
2114 16 : nBlockBufSize = 4 * nBlockXSize * nBlockYSize;
2115 16 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2116 :
2117 : /* -------------------------------------------------------------------- */
2118 : /* Allocate a temporary buffer for this strip. */
2119 : /* -------------------------------------------------------------------- */
2120 16 : if( poGDS->pabyBlockBuf == NULL )
2121 : {
2122 3 : poGDS->pabyBlockBuf = (GByte *) VSIMalloc3( 4, nBlockXSize, nBlockYSize );
2123 3 : if( poGDS->pabyBlockBuf == NULL )
2124 0 : return( CE_Failure );
2125 : }
2126 :
2127 : /* -------------------------------------------------------------------- */
2128 : /* Read the strip */
2129 : /* -------------------------------------------------------------------- */
2130 16 : if( poGDS->nLoadedBlock != nBlockId )
2131 : {
2132 4 : if( TIFFIsTiled( poGDS->hTIFF ) )
2133 : {
2134 1 : if( TIFFReadRGBATile(poGDS->hTIFF,
2135 : nBlockXOff * nBlockXSize,
2136 : nBlockYOff * nBlockYSize,
2137 : (uint32 *) poGDS->pabyBlockBuf) == -1
2138 : && !poGDS->bIgnoreReadErrors )
2139 : {
2140 : /* Once TIFFError() is properly hooked, this can go away */
2141 : CPLError( CE_Failure, CPLE_AppDefined,
2142 0 : "TIFFReadRGBATile() failed." );
2143 :
2144 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
2145 :
2146 0 : eErr = CE_Failure;
2147 : }
2148 : }
2149 : else
2150 : {
2151 3 : if( TIFFReadRGBAStrip(poGDS->hTIFF,
2152 : nBlockId * nBlockYSize,
2153 : (uint32 *) poGDS->pabyBlockBuf) == -1
2154 : && !poGDS->bIgnoreReadErrors )
2155 : {
2156 : /* Once TIFFError() is properly hooked, this can go away */
2157 : CPLError( CE_Failure, CPLE_AppDefined,
2158 0 : "TIFFReadRGBAStrip() failed." );
2159 :
2160 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
2161 :
2162 0 : eErr = CE_Failure;
2163 : }
2164 : }
2165 : }
2166 :
2167 16 : poGDS->nLoadedBlock = nBlockId;
2168 :
2169 : /* -------------------------------------------------------------------- */
2170 : /* Handle simple case of eight bit data, and pixel interleaving. */
2171 : /* -------------------------------------------------------------------- */
2172 : int iDestLine, nBO;
2173 : int nThisBlockYSize;
2174 :
2175 16 : if( (nBlockYOff+1) * nBlockYSize > GetYSize()
2176 : && !TIFFIsTiled( poGDS->hTIFF ) )
2177 4 : nThisBlockYSize = GetYSize() - nBlockYOff * nBlockYSize;
2178 : else
2179 12 : nThisBlockYSize = nBlockYSize;
2180 :
2181 : #ifdef CPL_LSB
2182 16 : nBO = nBand - 1;
2183 : #else
2184 : nBO = 4 - nBand;
2185 : #endif
2186 :
2187 1116 : for( iDestLine = 0; iDestLine < nThisBlockYSize; iDestLine++ )
2188 : {
2189 : int nSrcOffset;
2190 :
2191 1100 : nSrcOffset = (nThisBlockYSize - iDestLine - 1) * nBlockXSize * 4;
2192 :
2193 : GDALCopyWords( poGDS->pabyBlockBuf + nBO + nSrcOffset, GDT_Byte, 4,
2194 : ((GByte *) pImage)+iDestLine*nBlockXSize, GDT_Byte, 1,
2195 1100 : nBlockXSize );
2196 : }
2197 :
2198 16 : if (eErr == CE_None)
2199 16 : eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
2200 :
2201 16 : return eErr;
2202 : }
2203 :
2204 : /************************************************************************/
2205 : /* GetColorInterpretation() */
2206 : /************************************************************************/
2207 :
2208 6 : GDALColorInterp GTiffRGBABand::GetColorInterpretation()
2209 :
2210 : {
2211 6 : if( nBand == 1 )
2212 2 : return GCI_RedBand;
2213 4 : else if( nBand == 2 )
2214 1 : return GCI_GreenBand;
2215 3 : else if( nBand == 3 )
2216 1 : return GCI_BlueBand;
2217 : else
2218 2 : return GCI_AlphaBand;
2219 : }
2220 :
2221 : /************************************************************************/
2222 : /* ==================================================================== */
2223 : /* GTiffOddBitsBand */
2224 : /* ==================================================================== */
2225 : /************************************************************************/
2226 :
2227 : class GTiffOddBitsBand : public GTiffRasterBand
2228 : {
2229 : friend class GTiffDataset;
2230 : public:
2231 :
2232 : GTiffOddBitsBand( GTiffDataset *, int );
2233 : virtual ~GTiffOddBitsBand();
2234 :
2235 : virtual CPLErr IReadBlock( int, int, void * );
2236 : virtual CPLErr IWriteBlock( int, int, void * );
2237 : };
2238 :
2239 :
2240 : /************************************************************************/
2241 : /* GTiffOddBitsBand() */
2242 : /************************************************************************/
2243 :
2244 383 : GTiffOddBitsBand::GTiffOddBitsBand( GTiffDataset *poGDS, int nBand )
2245 383 : : GTiffRasterBand( poGDS, nBand )
2246 :
2247 : {
2248 383 : eDataType = GDT_Byte;
2249 383 : if( poGDS->nSampleFormat == SAMPLEFORMAT_IEEEFP )
2250 2 : eDataType = GDT_Float32;
2251 478 : else if( poGDS->nBitsPerSample > 8 && poGDS->nBitsPerSample < 16 )
2252 97 : eDataType = GDT_UInt16;
2253 284 : else if( poGDS->nBitsPerSample > 16 )
2254 67 : eDataType = GDT_UInt32;
2255 383 : }
2256 :
2257 : /************************************************************************/
2258 : /* ~GTiffOddBitsBand() */
2259 : /************************************************************************/
2260 :
2261 383 : GTiffOddBitsBand::~GTiffOddBitsBand()
2262 :
2263 : {
2264 383 : }
2265 :
2266 : /************************************************************************/
2267 : /* IWriteBlock() */
2268 : /************************************************************************/
2269 :
2270 441 : CPLErr GTiffOddBitsBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2271 : void *pImage )
2272 :
2273 : {
2274 : int nBlockId;
2275 441 : CPLErr eErr = CE_None;
2276 :
2277 441 : if (poGDS->bWriteErrorInFlushBlockBuf)
2278 : {
2279 : /* Report as an error if a previously loaded block couldn't be */
2280 : /* written correctly */
2281 0 : poGDS->bWriteErrorInFlushBlockBuf = FALSE;
2282 0 : return CE_Failure;
2283 : }
2284 :
2285 441 : if (!poGDS->SetDirectory())
2286 0 : return CE_Failure;
2287 :
2288 : CPLAssert( poGDS != NULL
2289 : && nBlockXOff >= 0
2290 : && nBlockYOff >= 0
2291 441 : && pImage != NULL );
2292 :
2293 441 : if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
2294 : {
2295 : CPLError(CE_Failure, CPLE_NotSupported,
2296 0 : "Writing float data with nBitsPerSample < 32 is unsupported");
2297 0 : return CE_Failure;
2298 : }
2299 :
2300 : /* -------------------------------------------------------------------- */
2301 : /* Load the block buffer. */
2302 : /* -------------------------------------------------------------------- */
2303 441 : CPLAssert(nBlocksPerRow != 0);
2304 441 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2305 :
2306 441 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
2307 18 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
2308 :
2309 : /* Only read content from disk in the CONTIG case */
2310 : eErr = poGDS->LoadBlockBuf( nBlockId,
2311 441 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 );
2312 441 : if( eErr != CE_None )
2313 0 : return eErr;
2314 :
2315 441 : GUInt32 nMaxVal = (1 << poGDS->nBitsPerSample) - 1;
2316 :
2317 : /* -------------------------------------------------------------------- */
2318 : /* Handle case of "separate" images or single band images where */
2319 : /* no interleaving with other data is required. */
2320 : /* -------------------------------------------------------------------- */
2321 441 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
2322 : || poGDS->nBands == 1 )
2323 : {
2324 425 : int iBit, iPixel, iBitOffset = 0;
2325 : int iX, iY, nBitsPerLine;
2326 :
2327 : // bits per line rounds up to next byte boundary.
2328 425 : nBitsPerLine = nBlockXSize * poGDS->nBitsPerSample;
2329 425 : if( (nBitsPerLine & 7) != 0 )
2330 35 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2331 :
2332 : /* Initialize to zero as we set the buffer with binary or operations */
2333 425 : if (poGDS->nBitsPerSample != 24)
2334 420 : memset(poGDS->pabyBlockBuf, 0, (nBitsPerLine / 8) * nBlockYSize);
2335 :
2336 425 : iPixel = 0;
2337 40759 : for( iY = 0; iY < nBlockYSize; iY++ )
2338 : {
2339 40334 : iBitOffset = iY * nBitsPerLine;
2340 :
2341 : /* Small optimization in 1 bit case */
2342 40334 : if (poGDS->nBitsPerSample == 1)
2343 : {
2344 18178763 : for( iX = 0; iX < nBlockXSize; iX++ )
2345 : {
2346 18139027 : if (((GByte *) pImage)[iPixel++])
2347 10262134 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2348 18139027 : iBitOffset++;
2349 : }
2350 :
2351 39736 : continue;
2352 : }
2353 :
2354 39368 : for( iX = 0; iX < nBlockXSize; iX++ )
2355 : {
2356 38770 : GUInt32 nInWord = 0;
2357 38770 : if( eDataType == GDT_Byte )
2358 400 : nInWord = ((GByte *) pImage)[iPixel++];
2359 38370 : else if( eDataType == GDT_UInt16 )
2360 35569 : nInWord = ((GUInt16 *) pImage)[iPixel++];
2361 2801 : else if( eDataType == GDT_UInt32 )
2362 2801 : nInWord = ((GUInt32 *) pImage)[iPixel++];
2363 : else
2364 0 : CPLAssert(0);
2365 :
2366 38770 : if (nInWord > nMaxVal)
2367 : {
2368 400 : nInWord = nMaxVal;
2369 400 : if( !poGDS->bClipWarn )
2370 : {
2371 1 : poGDS->bClipWarn = TRUE;
2372 : CPLError( CE_Warning, CPLE_AppDefined,
2373 1 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
2374 : }
2375 : }
2376 :
2377 38770 : if (poGDS->nBitsPerSample == 24)
2378 : {
2379 : /* -------------------------------------------------------------------- */
2380 : /* Special case for 24bit data which is pre-byteswapped since */
2381 : /* the size falls on a byte boundary ... ugg (#2361). */
2382 : /* -------------------------------------------------------------------- */
2383 : #ifdef CPL_MSB
2384 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2385 : (GByte) nInWord;
2386 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2387 : (GByte) (nInWord >> 8);
2388 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2389 : (GByte) (nInWord >> 16);
2390 : #else
2391 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2392 1400 : (GByte) (nInWord >> 16);
2393 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2394 1400 : (GByte) (nInWord >> 8);
2395 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2396 1400 : (GByte) nInWord;
2397 : #endif
2398 1400 : iBitOffset += 24;
2399 : }
2400 : else
2401 : {
2402 485812 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2403 : {
2404 448442 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
2405 18485 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2406 448442 : iBitOffset++;
2407 : }
2408 : }
2409 : }
2410 : }
2411 :
2412 425 : poGDS->bLoadedBlockDirty = TRUE;
2413 :
2414 425 : return eErr;
2415 : }
2416 :
2417 : /* -------------------------------------------------------------------- */
2418 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
2419 : /* -------------------------------------------------------------------- */
2420 :
2421 : /* -------------------------------------------------------------------- */
2422 : /* On write of pixel interleaved data, we might as well flush */
2423 : /* out any other bands that are dirty in our cache. This is */
2424 : /* especially helpful when writing compressed blocks. */
2425 : /* -------------------------------------------------------------------- */
2426 : int iBand;
2427 :
2428 54 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
2429 : {
2430 38 : const GByte *pabyThisImage = NULL;
2431 38 : GDALRasterBlock *poBlock = NULL;
2432 38 : int iBit, iPixel, iBitOffset = 0;
2433 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2434 :
2435 38 : if( iBand+1 == nBand )
2436 16 : pabyThisImage = (GByte *) pImage;
2437 : else
2438 : {
2439 : poBlock = ((GTiffOddBitsBand *)poGDS->GetRasterBand( iBand+1 ))
2440 22 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
2441 :
2442 22 : if( poBlock == NULL )
2443 10 : continue;
2444 :
2445 12 : if( !poBlock->GetDirty() )
2446 : {
2447 0 : poBlock->DropLock();
2448 0 : continue;
2449 : }
2450 :
2451 12 : pabyThisImage = (GByte *) poBlock->GetDataRef();
2452 : }
2453 :
2454 28 : iPixelBitSkip = poGDS->nBitsPerSample * poGDS->nBands;
2455 28 : iBandBitOffset = iBand * poGDS->nBitsPerSample;
2456 :
2457 : // bits per line rounds up to next byte boundary.
2458 28 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2459 28 : if( (nBitsPerLine & 7) != 0 )
2460 15 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2461 :
2462 28 : iPixel = 0;
2463 671 : for( iY = 0; iY < nBlockYSize; iY++ )
2464 : {
2465 643 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2466 :
2467 22616 : for( iX = 0; iX < nBlockXSize; iX++ )
2468 : {
2469 21973 : GUInt32 nInWord = 0;
2470 21973 : if( eDataType == GDT_Byte )
2471 4085 : nInWord = ((GByte *) pabyThisImage)[iPixel++];
2472 17888 : else if( eDataType == GDT_UInt16 )
2473 15088 : nInWord = ((GUInt16 *) pabyThisImage)[iPixel++];
2474 2800 : else if( eDataType == GDT_UInt32 )
2475 2800 : nInWord = ((GUInt32 *) pabyThisImage)[iPixel++];
2476 : else
2477 0 : CPLAssert(0);
2478 :
2479 21973 : if (nInWord > nMaxVal)
2480 : {
2481 0 : nInWord = nMaxVal;
2482 0 : if( !poGDS->bClipWarn )
2483 : {
2484 0 : poGDS->bClipWarn = TRUE;
2485 : CPLError( CE_Warning, CPLE_AppDefined,
2486 0 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
2487 : }
2488 : }
2489 :
2490 21973 : if (poGDS->nBitsPerSample == 24)
2491 : {
2492 : /* -------------------------------------------------------------------- */
2493 : /* Special case for 24bit data which is pre-byteswapped since */
2494 : /* the size falls on a byte boundary ... ugg (#2361). */
2495 : /* -------------------------------------------------------------------- */
2496 : #ifdef CPL_MSB
2497 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2498 : (GByte) nInWord;
2499 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2500 : (GByte) (nInWord >> 8);
2501 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2502 : (GByte) (nInWord >> 16);
2503 : #else
2504 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
2505 1400 : (GByte) (nInWord >> 16);
2506 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
2507 1400 : (GByte) (nInWord >> 8);
2508 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
2509 1400 : (GByte) nInWord;
2510 : #endif
2511 1400 : iBitOffset += 24;
2512 : }
2513 : else
2514 : {
2515 248624 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2516 : {
2517 228051 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
2518 101895 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
2519 : else
2520 : {
2521 : /* We must explictly unset the bit as we may update an existing block */
2522 126156 : poGDS->pabyBlockBuf[iBitOffset>>3] &= ~(0x80 >>(iBitOffset & 7));
2523 : }
2524 :
2525 228051 : iBitOffset++;
2526 : }
2527 : }
2528 :
2529 21973 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2530 : }
2531 : }
2532 :
2533 28 : if( poBlock != NULL )
2534 : {
2535 12 : poBlock->MarkClean();
2536 12 : poBlock->DropLock();
2537 : }
2538 : }
2539 :
2540 16 : poGDS->bLoadedBlockDirty = TRUE;
2541 :
2542 16 : return CE_None;
2543 : }
2544 :
2545 : /************************************************************************/
2546 : /* IReadBlock() */
2547 : /************************************************************************/
2548 :
2549 815 : CPLErr GTiffOddBitsBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2550 : void * pImage )
2551 :
2552 : {
2553 : int nBlockId;
2554 815 : CPLErr eErr = CE_None;
2555 :
2556 815 : if (!poGDS->SetDirectory())
2557 0 : return CE_Failure;
2558 :
2559 815 : CPLAssert(nBlocksPerRow != 0);
2560 815 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2561 :
2562 815 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
2563 20 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
2564 :
2565 : /* -------------------------------------------------------------------- */
2566 : /* Handle the case of a strip in a writable file that doesn't */
2567 : /* exist yet, but that we want to read. Just set to zeros and */
2568 : /* return. */
2569 : /* -------------------------------------------------------------------- */
2570 815 : if( !poGDS->IsBlockAvailable(nBlockId) )
2571 : {
2572 566 : NullBlock( pImage );
2573 566 : return CE_None;
2574 : }
2575 :
2576 : /* -------------------------------------------------------------------- */
2577 : /* Load the block buffer. */
2578 : /* -------------------------------------------------------------------- */
2579 249 : eErr = poGDS->LoadBlockBuf( nBlockId );
2580 249 : if( eErr != CE_None )
2581 0 : return eErr;
2582 :
2583 416 : if ( poGDS->nBitsPerSample == 1 && (poGDS->nBands == 1 || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) )
2584 : {
2585 : /* -------------------------------------------------------------------- */
2586 : /* Translate 1bit data to eight bit. */
2587 : /* -------------------------------------------------------------------- */
2588 167 : int iDstOffset=0, iLine;
2589 167 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2590 :
2591 17841 : for( iLine = 0; iLine < nBlockYSize; iLine++ )
2592 : {
2593 : int iSrcOffset, iPixel;
2594 :
2595 17674 : iSrcOffset = ((nBlockXSize+7) >> 3) * 8 * iLine;
2596 :
2597 17674 : GByte bSetVal = (poGDS->bPromoteTo8Bits) ? 255 : 1;
2598 :
2599 4724882 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2600 : {
2601 4707208 : if( pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2602 1534422 : ((GByte *) pImage)[iDstOffset++] = bSetVal;
2603 : else
2604 3172786 : ((GByte *) pImage)[iDstOffset++] = 0;
2605 : }
2606 : }
2607 : }
2608 : /* -------------------------------------------------------------------- */
2609 : /* Handle the case of 16- and 24-bit floating point data as per */
2610 : /* TIFF Technical Note 3. */
2611 : /* -------------------------------------------------------------------- */
2612 84 : else if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
2613 : {
2614 : int i, nBlockPixels, nWordBytes, iSkipBytes;
2615 : GByte *pabyImage;
2616 :
2617 2 : nWordBytes = poGDS->nBitsPerSample / 8;
2618 2 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
2619 : iSkipBytes = ( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) ?
2620 2 : nWordBytes : poGDS->nBands * nWordBytes;
2621 :
2622 2 : nBlockPixels = nBlockXSize * nBlockYSize;
2623 2 : if ( poGDS->nBitsPerSample == 16 )
2624 : {
2625 401 : for( i = 0; i < nBlockPixels; i++ )
2626 : {
2627 400 : ((GUInt32 *) pImage)[i] =
2628 400 : HalfToFloat( *((GUInt16 *)pabyImage) );
2629 400 : pabyImage += iSkipBytes;
2630 : }
2631 : }
2632 1 : else if ( poGDS->nBitsPerSample == 24 )
2633 : {
2634 401 : for( i = 0; i < nBlockPixels; i++ )
2635 : {
2636 : #ifdef CPL_MSB
2637 : ((GUInt32 *) pImage)[i] =
2638 : TripleToFloat( ((GUInt32)*(pabyImage + 0) << 16)
2639 : | ((GUInt32)*(pabyImage + 1) << 8)
2640 : | (GUInt32)*(pabyImage + 2) );
2641 : #else
2642 400 : ((GUInt32 *) pImage)[i] =
2643 : TripleToFloat( ((GUInt32)*(pabyImage + 2) << 16)
2644 : | ((GUInt32)*(pabyImage + 1) << 8)
2645 400 : | (GUInt32)*pabyImage );
2646 : #endif
2647 400 : pabyImage += iSkipBytes;
2648 : }
2649 : }
2650 : }
2651 :
2652 : /* -------------------------------------------------------------------- */
2653 : /* Special case for moving 12bit data somewhat more efficiently. */
2654 : /* -------------------------------------------------------------------- */
2655 80 : else if( poGDS->nBitsPerSample == 12 )
2656 : {
2657 20 : int iPixel, iBitOffset = 0;
2658 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2659 :
2660 20 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2661 : {
2662 17 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2663 17 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2664 : }
2665 : else
2666 : {
2667 3 : iPixelBitSkip = poGDS->nBitsPerSample;
2668 3 : iBandBitOffset = 0;
2669 : }
2670 :
2671 : // bits per line rounds up to next byte boundary.
2672 20 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2673 20 : if( (nBitsPerLine & 7) != 0 )
2674 0 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2675 :
2676 20 : iPixel = 0;
2677 904 : for( iY = 0; iY < nBlockYSize; iY++ )
2678 : {
2679 884 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2680 :
2681 65524 : for( iX = 0; iX < nBlockXSize; iX++ )
2682 : {
2683 64640 : int iByte = iBitOffset>>3;
2684 :
2685 64640 : if( (iBitOffset & 0x7) == 0 )
2686 : {
2687 : /* starting on byte boundary */
2688 :
2689 64840 : ((GUInt16 *) pImage)[iPixel++] =
2690 32420 : (poGDS->pabyBlockBuf[iByte] << 4)
2691 32420 : | (poGDS->pabyBlockBuf[iByte+1] >> 4);
2692 : }
2693 : else
2694 : {
2695 : /* starting off byte boundary */
2696 :
2697 64440 : ((GUInt16 *) pImage)[iPixel++] =
2698 32220 : ((poGDS->pabyBlockBuf[iByte] & 0xf) << 8)
2699 32220 : | (poGDS->pabyBlockBuf[iByte+1]);
2700 : }
2701 64640 : iBitOffset += iPixelBitSkip;
2702 : }
2703 : }
2704 : }
2705 :
2706 : /* -------------------------------------------------------------------- */
2707 : /* Special case for 24bit data which is pre-byteswapped since */
2708 : /* the size falls on a byte boundary ... ugg (#2361). */
2709 : /* -------------------------------------------------------------------- */
2710 60 : else if( poGDS->nBitsPerSample == 24 )
2711 : {
2712 : int iPixel;
2713 : int iPixelByteSkip, iBandByteOffset, iX, iY, nBytesPerLine;
2714 :
2715 11 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2716 : {
2717 8 : iPixelByteSkip = (poGDS->nBands * poGDS->nBitsPerSample) / 8;
2718 8 : iBandByteOffset = ((nBand-1) * poGDS->nBitsPerSample) / 8;
2719 : }
2720 : else
2721 : {
2722 3 : iPixelByteSkip = poGDS->nBitsPerSample / 8;
2723 3 : iBandByteOffset = 0;
2724 : }
2725 :
2726 11 : nBytesPerLine = nBlockXSize * iPixelByteSkip;
2727 :
2728 11 : iPixel = 0;
2729 191 : for( iY = 0; iY < nBlockYSize; iY++ )
2730 : {
2731 : GByte *pabyImage =
2732 180 : poGDS->pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
2733 :
2734 3380 : for( iX = 0; iX < nBlockXSize; iX++ )
2735 : {
2736 : #ifdef CPL_MSB
2737 : ((GUInt32 *) pImage)[iPixel++] =
2738 : ((GUInt32)*(pabyImage + 2) << 16)
2739 : | ((GUInt32)*(pabyImage + 1) << 8)
2740 : | (GUInt32)*(pabyImage + 0);
2741 : #else
2742 6400 : ((GUInt32 *) pImage)[iPixel++] =
2743 : ((GUInt32)*(pabyImage + 0) << 16)
2744 : | ((GUInt32)*(pabyImage + 1) << 8)
2745 3200 : | (GUInt32)*(pabyImage + 2);
2746 : #endif
2747 3200 : pabyImage += iPixelByteSkip;
2748 : }
2749 : }
2750 : }
2751 :
2752 : /* -------------------------------------------------------------------- */
2753 : /* Handle 1-32 bit integer data. */
2754 : /* -------------------------------------------------------------------- */
2755 : else
2756 : {
2757 49 : int iBit, iPixel, iBitOffset = 0;
2758 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2759 :
2760 49 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2761 : {
2762 43 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2763 43 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2764 : }
2765 : else
2766 : {
2767 6 : iPixelBitSkip = poGDS->nBitsPerSample;
2768 6 : iBandBitOffset = 0;
2769 : }
2770 :
2771 : // bits per line rounds up to next byte boundary.
2772 49 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2773 49 : if( (nBitsPerLine & 7) != 0 )
2774 48 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2775 :
2776 49 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2777 49 : iPixel = 0;
2778 :
2779 2285 : for( iY = 0; iY < nBlockYSize; iY++ )
2780 : {
2781 2236 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2782 :
2783 180540 : for( iX = 0; iX < nBlockXSize; iX++ )
2784 : {
2785 178304 : int nOutWord = 0;
2786 :
2787 452342 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2788 : {
2789 274038 : if( pabyBlockBuf[iBitOffset>>3]
2790 : & (0x80 >>(iBitOffset & 7)) )
2791 137696 : nOutWord |= (1 << (poGDS->nBitsPerSample - 1 - iBit));
2792 274038 : iBitOffset++;
2793 : }
2794 :
2795 178304 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2796 :
2797 178304 : if( eDataType == GDT_Byte )
2798 172302 : ((GByte *) pImage)[iPixel++] = (GByte) nOutWord;
2799 6002 : else if( eDataType == GDT_UInt16 )
2800 3201 : ((GUInt16 *) pImage)[iPixel++] = (GUInt16) nOutWord;
2801 2801 : else if( eDataType == GDT_UInt32 )
2802 2801 : ((GUInt32 *) pImage)[iPixel++] = nOutWord;
2803 : else
2804 0 : CPLAssert(0);
2805 : }
2806 : }
2807 : }
2808 :
2809 249 : return CE_None;
2810 : }
2811 :
2812 :
2813 : /************************************************************************/
2814 : /* ==================================================================== */
2815 : /* GTiffBitmapBand */
2816 : /* ==================================================================== */
2817 : /************************************************************************/
2818 :
2819 : class GTiffBitmapBand : public GTiffOddBitsBand
2820 : {
2821 : friend class GTiffDataset;
2822 :
2823 : GDALColorTable *poColorTable;
2824 :
2825 : public:
2826 :
2827 : GTiffBitmapBand( GTiffDataset *, int );
2828 : virtual ~GTiffBitmapBand();
2829 :
2830 : virtual GDALColorInterp GetColorInterpretation();
2831 : virtual GDALColorTable *GetColorTable();
2832 : };
2833 :
2834 :
2835 : /************************************************************************/
2836 : /* GTiffBitmapBand() */
2837 : /************************************************************************/
2838 :
2839 129 : GTiffBitmapBand::GTiffBitmapBand( GTiffDataset *poDS, int nBand )
2840 129 : : GTiffOddBitsBand( poDS, nBand )
2841 :
2842 : {
2843 129 : eDataType = GDT_Byte;
2844 :
2845 129 : if( poDS->poColorTable != NULL )
2846 17 : poColorTable = poDS->poColorTable->Clone();
2847 : else
2848 : {
2849 : #ifdef ESRI_BUILD
2850 : poColorTable = NULL;
2851 : #else
2852 : GDALColorEntry oWhite, oBlack;
2853 :
2854 112 : oWhite.c1 = 255;
2855 112 : oWhite.c2 = 255;
2856 112 : oWhite.c3 = 255;
2857 112 : oWhite.c4 = 255;
2858 :
2859 112 : oBlack.c1 = 0;
2860 112 : oBlack.c2 = 0;
2861 112 : oBlack.c3 = 0;
2862 112 : oBlack.c4 = 255;
2863 :
2864 112 : poColorTable = new GDALColorTable();
2865 :
2866 112 : if( poDS->nPhotometric == PHOTOMETRIC_MINISWHITE )
2867 : {
2868 0 : poColorTable->SetColorEntry( 0, &oWhite );
2869 0 : poColorTable->SetColorEntry( 1, &oBlack );
2870 : }
2871 : else
2872 : {
2873 112 : poColorTable->SetColorEntry( 0, &oBlack );
2874 112 : poColorTable->SetColorEntry( 1, &oWhite );
2875 : }
2876 : #endif /* not defined ESRI_BUILD */
2877 : }
2878 129 : }
2879 :
2880 : /************************************************************************/
2881 : /* ~GTiffBitmapBand() */
2882 : /************************************************************************/
2883 :
2884 129 : GTiffBitmapBand::~GTiffBitmapBand()
2885 :
2886 : {
2887 129 : delete poColorTable;
2888 129 : }
2889 :
2890 : /************************************************************************/
2891 : /* GetColorInterpretation() */
2892 : /************************************************************************/
2893 :
2894 21 : GDALColorInterp GTiffBitmapBand::GetColorInterpretation()
2895 :
2896 : {
2897 21 : if (poGDS->bPromoteTo8Bits)
2898 13 : return GCI_Undefined;
2899 : else
2900 8 : return GCI_PaletteIndex;
2901 : }
2902 :
2903 : /************************************************************************/
2904 : /* GetColorTable() */
2905 : /************************************************************************/
2906 :
2907 12 : GDALColorTable *GTiffBitmapBand::GetColorTable()
2908 :
2909 : {
2910 12 : if (poGDS->bPromoteTo8Bits)
2911 0 : return NULL;
2912 : else
2913 12 : return poColorTable;
2914 : }
2915 :
2916 : /************************************************************************/
2917 : /* ==================================================================== */
2918 : /* GTiffSplitBitmapBand */
2919 : /* ==================================================================== */
2920 : /************************************************************************/
2921 :
2922 : class GTiffSplitBitmapBand : public GTiffBitmapBand
2923 : {
2924 : friend class GTiffDataset;
2925 :
2926 : public:
2927 :
2928 : GTiffSplitBitmapBand( GTiffDataset *, int );
2929 : virtual ~GTiffSplitBitmapBand();
2930 :
2931 : virtual CPLErr IReadBlock( int, int, void * );
2932 : virtual CPLErr IWriteBlock( int, int, void * );
2933 : };
2934 :
2935 :
2936 : /************************************************************************/
2937 : /* GTiffSplitBitmapBand() */
2938 : /************************************************************************/
2939 :
2940 4 : GTiffSplitBitmapBand::GTiffSplitBitmapBand( GTiffDataset *poDS, int nBand )
2941 4 : : GTiffBitmapBand( poDS, nBand )
2942 :
2943 : {
2944 4 : nBlockXSize = poDS->GetRasterXSize();
2945 4 : nBlockYSize = 1;
2946 4 : }
2947 :
2948 : /************************************************************************/
2949 : /* ~GTiffSplitBitmapBand() */
2950 : /************************************************************************/
2951 :
2952 4 : GTiffSplitBitmapBand::~GTiffSplitBitmapBand()
2953 :
2954 : {
2955 4 : }
2956 :
2957 :
2958 : /************************************************************************/
2959 : /* IReadBlock() */
2960 : /************************************************************************/
2961 :
2962 21600 : CPLErr GTiffSplitBitmapBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2963 : void * pImage )
2964 :
2965 : {
2966 : (void) nBlockXOff;
2967 :
2968 21600 : if (!poGDS->SetDirectory())
2969 0 : return CE_Failure;
2970 :
2971 21600 : if (poGDS->pabyBlockBuf == NULL)
2972 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
2973 :
2974 : /* -------------------------------------------------------------------- */
2975 : /* Read through to target scanline. */
2976 : /* -------------------------------------------------------------------- */
2977 21600 : if( poGDS->nLastLineRead >= nBlockYOff )
2978 0 : poGDS->nLastLineRead = -1;
2979 :
2980 64800 : while( poGDS->nLastLineRead < nBlockYOff )
2981 : {
2982 21600 : if( TIFFReadScanline( poGDS->hTIFF, poGDS->pabyBlockBuf, ++poGDS->nLastLineRead, 0 ) == -1
2983 : && !poGDS->bIgnoreReadErrors )
2984 : {
2985 : CPLError( CE_Failure, CPLE_AppDefined,
2986 0 : "TIFFReadScanline() failed." );
2987 0 : return CE_Failure;
2988 : }
2989 : }
2990 :
2991 : /* -------------------------------------------------------------------- */
2992 : /* Translate 1bit data to eight bit. */
2993 : /* -------------------------------------------------------------------- */
2994 21600 : int iPixel, iSrcOffset=0, iDstOffset=0;
2995 :
2996 21621600 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2997 : {
2998 21600000 : if( poGDS->pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2999 21243630 : ((GByte *) pImage)[iDstOffset++] = 1;
3000 : else
3001 356370 : ((GByte *) pImage)[iDstOffset++] = 0;
3002 : }
3003 :
3004 21600 : return CE_None;
3005 : }
3006 :
3007 : /************************************************************************/
3008 : /* IWriteBlock() */
3009 : /************************************************************************/
3010 :
3011 0 : CPLErr GTiffSplitBitmapBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
3012 : void * pImage )
3013 :
3014 : {
3015 : (void) nBlockXOff;
3016 : (void) nBlockYOff;
3017 : (void) pImage;
3018 :
3019 : CPLError( CE_Failure, CPLE_AppDefined,
3020 0 : "Split bitmap bands are read-only." );
3021 0 : return CE_Failure;
3022 : }
3023 :
3024 : /************************************************************************/
3025 : /* ==================================================================== */
3026 : /* GTiffDataset */
3027 : /* ==================================================================== */
3028 : /************************************************************************/
3029 :
3030 :
3031 : /************************************************************************/
3032 : /* GTiffDataset() */
3033 : /************************************************************************/
3034 :
3035 5278 : GTiffDataset::GTiffDataset()
3036 :
3037 : {
3038 5278 : nLoadedBlock = -1;
3039 5278 : bLoadedBlockDirty = FALSE;
3040 5278 : pabyBlockBuf = NULL;
3041 5278 : bWriteErrorInFlushBlockBuf = FALSE;
3042 5278 : hTIFF = NULL;
3043 5278 : bNeedsRewrite = FALSE;
3044 5278 : bMetadataChanged = FALSE;
3045 5278 : bGeoTIFFInfoChanged = FALSE;
3046 5278 : bForceUnsetGT = FALSE;
3047 5278 : bForceUnsetProjection = FALSE;
3048 5278 : bCrystalized = TRUE;
3049 5278 : poColorTable = NULL;
3050 5278 : bNoDataSet = FALSE;
3051 5278 : dfNoDataValue = -9999.0;
3052 5278 : pszProjection = CPLStrdup("");
3053 5278 : bLookedForProjection = FALSE;
3054 5278 : bLookedForMDAreaOrPoint = FALSE;
3055 5278 : bBase = TRUE;
3056 5278 : bCloseTIFFHandle = FALSE;
3057 5278 : bTreatAsRGBA = FALSE;
3058 5278 : nOverviewCount = 0;
3059 5278 : papoOverviewDS = NULL;
3060 5278 : nDirOffset = 0;
3061 5278 : poActiveDS = NULL;
3062 5278 : ppoActiveDSRef = NULL;
3063 :
3064 5278 : bGeoTransformValid = FALSE;
3065 5278 : adfGeoTransform[0] = 0.0;
3066 5278 : adfGeoTransform[1] = 1.0;
3067 5278 : adfGeoTransform[2] = 0.0;
3068 5278 : adfGeoTransform[3] = 0.0;
3069 5278 : adfGeoTransform[4] = 0.0;
3070 5278 : adfGeoTransform[5] = 1.0;
3071 :
3072 5278 : nGCPCount = 0;
3073 5278 : pasGCPList = NULL;
3074 :
3075 5278 : osProfile = "GDALGeoTIFF";
3076 :
3077 5278 : papszCreationOptions = NULL;
3078 :
3079 5278 : nTempWriteBufferSize = 0;
3080 5278 : pabyTempWriteBuffer = NULL;
3081 :
3082 5278 : poMaskDS = NULL;
3083 5278 : poBaseDS = NULL;
3084 :
3085 5278 : bFillEmptyTiles = FALSE;
3086 5278 : bLoadingOtherBands = FALSE;
3087 5278 : nLastLineRead = -1;
3088 5278 : nLastBandRead = -1;
3089 5278 : bTreatAsSplit = FALSE;
3090 5278 : bTreatAsSplitBitmap = FALSE;
3091 5278 : bClipWarn = FALSE;
3092 5278 : bHasWarnedDisableAggressiveBandCaching = FALSE;
3093 5278 : bDontReloadFirstBlock = FALSE;
3094 :
3095 5278 : nZLevel = -1;
3096 5278 : nLZMAPreset = -1;
3097 5278 : nJpegQuality = -1;
3098 :
3099 5278 : bPromoteTo8Bits = FALSE;
3100 :
3101 5278 : bDebugDontWriteBlocks = CSLTestBoolean(CPLGetConfigOption("GTIFF_DONT_WRITE_BLOCKS", "NO"));
3102 :
3103 5278 : bIsFinalized = FALSE;
3104 5278 : bIgnoreReadErrors = CSLTestBoolean(CPLGetConfigOption("GTIFF_IGNORE_READ_ERRORS", "NO"));
3105 :
3106 5278 : bHasSearchedRPC = FALSE;
3107 5278 : bHasSearchedIMD = FALSE;
3108 5278 : bHasSearchedPVL = FALSE;
3109 5278 : bEXIFMetadataLoaded = FALSE;
3110 :
3111 5278 : bScanDeferred = TRUE;
3112 :
3113 5278 : bDirectIO = CSLTestBoolean(CPLGetConfigOption("GTIFF_DIRECT_IO", "NO"));
3114 5278 : }
3115 :
3116 : /************************************************************************/
3117 : /* ~GTiffDataset() */
3118 : /************************************************************************/
3119 :
3120 5278 : GTiffDataset::~GTiffDataset()
3121 :
3122 : {
3123 5278 : Finalize();
3124 5278 : }
3125 :
3126 : /************************************************************************/
3127 : /* Finalize() */
3128 : /************************************************************************/
3129 :
3130 5282 : int GTiffDataset::Finalize()
3131 : {
3132 5282 : if (bIsFinalized)
3133 4 : return FALSE;
3134 :
3135 5278 : int bHasDroppedRef = FALSE;
3136 :
3137 5278 : Crystalize();
3138 :
3139 : /* -------------------------------------------------------------------- */
3140 : /* Handle forcing xml:ESRI data to be written to PAM. */
3141 : /* -------------------------------------------------------------------- */
3142 5278 : if( CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
3143 : {
3144 7 : char **papszESRIMD = GetMetadata("xml:ESRI");
3145 7 : if( papszESRIMD )
3146 : {
3147 5 : GDALPamDataset::SetMetadata( papszESRIMD, "xml:ESRI");
3148 : }
3149 : }
3150 :
3151 : /* -------------------------------------------------------------------- */
3152 : /* Ensure any blocks write cached by GDAL gets pushed through libtiff.*/
3153 : /* -------------------------------------------------------------------- */
3154 5278 : GDALPamDataset::FlushCache();
3155 :
3156 : /* -------------------------------------------------------------------- */
3157 : /* Fill in missing blocks with empty data. */
3158 : /* -------------------------------------------------------------------- */
3159 5278 : if( bFillEmptyTiles )
3160 : {
3161 958 : FillEmptyTiles();
3162 958 : bFillEmptyTiles = FALSE;
3163 : }
3164 :
3165 : /* -------------------------------------------------------------------- */
3166 : /* Force a complete flush, including either rewriting(moving) */
3167 : /* of writing in place the current directory. */
3168 : /* -------------------------------------------------------------------- */
3169 5278 : FlushCache();
3170 :
3171 : /* -------------------------------------------------------------------- */
3172 : /* If there is still changed metadata, then presumably we want */
3173 : /* to push it into PAM. */
3174 : /* -------------------------------------------------------------------- */
3175 5278 : if( bMetadataChanged )
3176 : {
3177 31 : PushMetadataToPam();
3178 31 : bMetadataChanged = FALSE;
3179 31 : GDALPamDataset::FlushCache();
3180 : }
3181 :
3182 : /* -------------------------------------------------------------------- */
3183 : /* Cleanup overviews. */
3184 : /* -------------------------------------------------------------------- */
3185 5278 : if( bBase )
3186 : {
3187 5162 : for( int i = 0; i < nOverviewCount; i++ )
3188 : {
3189 276 : delete papoOverviewDS[i];
3190 276 : bHasDroppedRef = TRUE;
3191 : }
3192 4886 : nOverviewCount = 0;
3193 : }
3194 :
3195 : /* If we are a mask dataset, we can have overviews, but we don't */
3196 : /* own them. We can only free the array, not the overviews themselves */
3197 5278 : CPLFree( papoOverviewDS );
3198 5278 : papoOverviewDS = NULL;
3199 :
3200 : /* poMaskDS is owned by the main image and the overviews */
3201 : /* so because of the latter case, we can delete it even if */
3202 : /* we are not the base image */
3203 5278 : if (poMaskDS)
3204 : {
3205 108 : delete poMaskDS;
3206 108 : poMaskDS = NULL;
3207 108 : bHasDroppedRef = TRUE;
3208 : }
3209 :
3210 5278 : if( poColorTable != NULL )
3211 102 : delete poColorTable;
3212 5278 : poColorTable = NULL;
3213 :
3214 5278 : if( bBase || bCloseTIFFHandle )
3215 : {
3216 4892 : XTIFFClose( hTIFF );
3217 4892 : hTIFF = NULL;
3218 : }
3219 :
3220 5278 : if( nGCPCount > 0 )
3221 : {
3222 29 : GDALDeinitGCPs( nGCPCount, pasGCPList );
3223 29 : CPLFree( pasGCPList );
3224 29 : pasGCPList = NULL;
3225 29 : nGCPCount = 0;
3226 : }
3227 :
3228 5278 : CPLFree( pszProjection );
3229 5278 : pszProjection = NULL;
3230 :
3231 5278 : CSLDestroy( papszCreationOptions );
3232 5278 : papszCreationOptions = NULL;
3233 :
3234 5278 : CPLFree(pabyTempWriteBuffer);
3235 5278 : pabyTempWriteBuffer = NULL;
3236 :
3237 5278 : if( *ppoActiveDSRef == this )
3238 5004 : *ppoActiveDSRef = NULL;
3239 5278 : ppoActiveDSRef = NULL;
3240 :
3241 5278 : bIsFinalized = TRUE;
3242 :
3243 5278 : return bHasDroppedRef;
3244 : }
3245 :
3246 : /************************************************************************/
3247 : /* CloseDependentDatasets() */
3248 : /************************************************************************/
3249 :
3250 4 : int GTiffDataset::CloseDependentDatasets()
3251 : {
3252 4 : if (!bBase)
3253 0 : return FALSE;
3254 :
3255 4 : int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
3256 :
3257 4 : bHasDroppedRef |= Finalize();
3258 :
3259 4 : return bHasDroppedRef;
3260 : }
3261 :
3262 : /************************************************************************/
3263 : /* FillEmptyTiles() */
3264 : /************************************************************************/
3265 :
3266 958 : void GTiffDataset::FillEmptyTiles()
3267 :
3268 : {
3269 958 : toff_t *panByteCounts = NULL;
3270 : int nBlockCount, iBlock;
3271 :
3272 958 : if (!SetDirectory())
3273 0 : return;
3274 :
3275 : /* -------------------------------------------------------------------- */
3276 : /* How many blocks are there in this file? */
3277 : /* -------------------------------------------------------------------- */
3278 958 : if( nPlanarConfig == PLANARCONFIG_SEPARATE )
3279 9 : nBlockCount = nBlocksPerBand * nBands;
3280 : else
3281 949 : nBlockCount = nBlocksPerBand;
3282 :
3283 : /* -------------------------------------------------------------------- */
3284 : /* Fetch block maps. */
3285 : /* -------------------------------------------------------------------- */
3286 958 : if( TIFFIsTiled( hTIFF ) )
3287 21 : TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts );
3288 : else
3289 937 : TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
3290 :
3291 958 : if (panByteCounts == NULL)
3292 : {
3293 : /* Got here with libtiff 3.9.3 and tiff_write_8 test */
3294 0 : CPLError(CE_Failure, CPLE_AppDefined, "FillEmptyTiles() failed because panByteCounts == NULL");
3295 0 : return;
3296 : }
3297 :
3298 : /* -------------------------------------------------------------------- */
3299 : /* Prepare a blank data buffer to write for uninitialized blocks. */
3300 : /* -------------------------------------------------------------------- */
3301 : int nBlockBytes;
3302 :
3303 958 : if( TIFFIsTiled( hTIFF ) )
3304 21 : nBlockBytes = TIFFTileSize(hTIFF);
3305 : else
3306 937 : nBlockBytes = TIFFStripSize(hTIFF);
3307 :
3308 958 : GByte *pabyData = (GByte *) VSICalloc(nBlockBytes,1);
3309 958 : if (pabyData == NULL)
3310 : {
3311 : CPLError(CE_Failure, CPLE_OutOfMemory,
3312 0 : "Cannot allocate %d bytes", nBlockBytes);
3313 0 : return;
3314 : }
3315 :
3316 : /* -------------------------------------------------------------------- */
3317 : /* Check all blocks, writing out data for uninitialized blocks. */
3318 : /* -------------------------------------------------------------------- */
3319 102921 : for( iBlock = 0; iBlock < nBlockCount; iBlock++ )
3320 : {
3321 101963 : if( panByteCounts[iBlock] == 0 )
3322 : {
3323 88554 : if( WriteEncodedTileOrStrip( iBlock, pabyData, FALSE ) != CE_None )
3324 0 : break;
3325 : }
3326 : }
3327 :
3328 958 : CPLFree( pabyData );
3329 : }
3330 :
3331 : /************************************************************************/
3332 : /* WriteEncodedTile() */
3333 : /************************************************************************/
3334 :
3335 9806 : int GTiffDataset::WriteEncodedTile(uint32 tile, GByte *pabyData,
3336 : int bPreserveDataBuffer)
3337 : {
3338 9806 : int cc = TIFFTileSize( hTIFF );
3339 9806 : int bNeedTileFill = FALSE;
3340 9806 : int iRow=0, iColumn=0;
3341 9806 : int nBlocksPerRow=1, nBlocksPerColumn=1;
3342 :
3343 : /*
3344 : ** Do we need to spread edge values right or down for a partial
3345 : ** JPEG encoded tile? We do this to avoid edge artifacts.
3346 : */
3347 9806 : if( nCompression == COMPRESSION_JPEG )
3348 : {
3349 351 : nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
3350 351 : nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, nBlockYSize);
3351 :
3352 351 : iColumn = (tile % nBlocksPerBand) % nBlocksPerRow;
3353 351 : iRow = (tile % nBlocksPerBand) / nBlocksPerRow;
3354 :
3355 : // Is this a partial right edge tile?
3356 351 : if( iRow == nBlocksPerRow - 1
3357 : && nRasterXSize % nBlockXSize != 0 )
3358 28 : bNeedTileFill = TRUE;
3359 :
3360 : // Is this a partial bottom edge tile?
3361 351 : if( iColumn == nBlocksPerColumn - 1
3362 : && nRasterYSize % nBlockYSize != 0 )
3363 38 : bNeedTileFill = TRUE;
3364 : }
3365 :
3366 : /*
3367 : ** If we need to fill out the tile, or if we want to prevent
3368 : ** TIFFWriteEncodedTile from altering the buffer as part of
3369 : ** byte swapping the data on write then we will need a temporary
3370 : ** working buffer. If not, we can just do a direct write.
3371 : */
3372 9806 : if (bPreserveDataBuffer
3373 : && (TIFFIsByteSwapped(hTIFF) || bNeedTileFill) )
3374 : {
3375 131 : if (cc != nTempWriteBufferSize)
3376 : {
3377 34 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
3378 34 : nTempWriteBufferSize = cc;
3379 : }
3380 131 : memcpy(pabyTempWriteBuffer, pabyData, cc);
3381 :
3382 131 : pabyData = (GByte *) pabyTempWriteBuffer;
3383 : }
3384 :
3385 : /*
3386 : ** Perform tile fill if needed.
3387 : */
3388 9806 : if( bNeedTileFill )
3389 : {
3390 38 : int nRightPixelsToFill = 0;
3391 38 : int nBottomPixelsToFill = 0;
3392 38 : int nPixelSize = cc / (nBlockXSize * nBlockYSize);
3393 : unsigned int iX, iY, iSrcX, iSrcY;
3394 :
3395 38 : CPLDebug( "GTiff", "Filling out jpeg edge tile on write." );
3396 :
3397 38 : if( iColumn == nBlocksPerRow - 1 )
3398 28 : nRightPixelsToFill = nBlockXSize * (iColumn+1) - nRasterXSize;
3399 38 : if( iRow == nBlocksPerColumn - 1 )
3400 30 : nBottomPixelsToFill = nBlockYSize * (iRow+1) - nRasterYSize;
3401 :
3402 : // Fill out to the right.
3403 38 : iSrcX = nBlockXSize - nRightPixelsToFill - 1;
3404 :
3405 2048 : for( iX = iSrcX+1; iX < nBlockXSize; iX++ )
3406 : {
3407 258394 : for( iY = 0; iY < nBlockYSize; iY++ )
3408 : {
3409 : memcpy( pabyData + (nBlockXSize * iY + iX) * nPixelSize,
3410 : pabyData + (nBlockXSize * iY + iSrcX) * nPixelSize,
3411 256384 : nPixelSize );
3412 : }
3413 : }
3414 :
3415 : // now fill out the bottom.
3416 38 : iSrcY = nBlockYSize - nBottomPixelsToFill - 1;
3417 2188 : for( iY = iSrcY+1; iY < nBlockYSize; iY++ )
3418 : {
3419 : memcpy( pabyData + nBlockXSize * nPixelSize * iY,
3420 : pabyData + nBlockXSize * nPixelSize * iSrcY,
3421 2150 : nPixelSize * nBlockXSize );
3422 : }
3423 : }
3424 :
3425 9806 : return TIFFWriteEncodedTile(hTIFF, tile, pabyData, cc);
3426 : }
3427 :
3428 : /************************************************************************/
3429 : /* WriteEncodedStrip() */
3430 : /************************************************************************/
3431 :
3432 99755 : int GTiffDataset::WriteEncodedStrip(uint32 strip, GByte* pabyData,
3433 : int bPreserveDataBuffer)
3434 : {
3435 99755 : int cc = TIFFStripSize( hTIFF );
3436 :
3437 : /* -------------------------------------------------------------------- */
3438 : /* If this is the last strip in the image, and is partial, then */
3439 : /* we need to trim the number of scanlines written to the */
3440 : /* amount of valid data we have. (#2748) */
3441 : /* -------------------------------------------------------------------- */
3442 99755 : int nStripWithinBand = strip % nBlocksPerBand;
3443 :
3444 99755 : if( (int) ((nStripWithinBand+1) * nRowsPerStrip) > GetRasterYSize() )
3445 : {
3446 : cc = (cc / nRowsPerStrip)
3447 173 : * (GetRasterYSize() - nStripWithinBand * nRowsPerStrip);
3448 : CPLDebug( "GTiff", "Adjusted bytes to write from %d to %d.",
3449 173 : (int) TIFFStripSize(hTIFF), cc );
3450 : }
3451 :
3452 : /* -------------------------------------------------------------------- */
3453 : /* TIFFWriteEncodedStrip can alter the passed buffer if */
3454 : /* byte-swapping is necessary so we use a temporary buffer */
3455 : /* before calling it. */
3456 : /* -------------------------------------------------------------------- */
3457 99755 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
3458 : {
3459 211 : if (cc != nTempWriteBufferSize)
3460 : {
3461 23 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
3462 23 : nTempWriteBufferSize = cc;
3463 : }
3464 211 : memcpy(pabyTempWriteBuffer, pabyData, cc);
3465 211 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyTempWriteBuffer, cc);
3466 : }
3467 : else
3468 99544 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyData, cc);
3469 : }
3470 :
3471 : /************************************************************************/
3472 : /* WriteEncodedTileOrStrip() */
3473 : /************************************************************************/
3474 :
3475 109561 : CPLErr GTiffDataset::WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data,
3476 : int bPreserveDataBuffer)
3477 : {
3478 109561 : CPLErr eErr = CE_None;
3479 :
3480 109561 : if( TIFFIsTiled( hTIFF ) )
3481 : {
3482 9806 : if( WriteEncodedTile(tile_or_strip, (GByte*) data,
3483 : bPreserveDataBuffer) == -1 )
3484 : {
3485 0 : eErr = CE_Failure;
3486 : }
3487 : }
3488 : else
3489 : {
3490 99755 : if( WriteEncodedStrip(tile_or_strip, (GByte *) data,
3491 : bPreserveDataBuffer) == -1 )
3492 : {
3493 0 : eErr = CE_Failure;
3494 : }
3495 : }
3496 :
3497 109561 : return eErr;
3498 : }
3499 :
3500 : /************************************************************************/
3501 : /* FlushBlockBuf() */
3502 : /************************************************************************/
3503 :
3504 230188 : CPLErr GTiffDataset::FlushBlockBuf()
3505 :
3506 : {
3507 230188 : CPLErr eErr = CE_None;
3508 :
3509 230188 : if( nLoadedBlock < 0 || !bLoadedBlockDirty )
3510 225134 : return CE_None;
3511 :
3512 5054 : bLoadedBlockDirty = FALSE;
3513 :
3514 5054 : if (!SetDirectory())
3515 0 : return CE_Failure;
3516 :
3517 5054 : eErr = WriteEncodedTileOrStrip(nLoadedBlock, pabyBlockBuf, TRUE);
3518 5054 : if (eErr != CE_None)
3519 : {
3520 : CPLError( CE_Failure, CPLE_AppDefined,
3521 0 : "WriteEncodedTile/Strip() failed." );
3522 0 : bWriteErrorInFlushBlockBuf = TRUE;
3523 : }
3524 :
3525 5054 : return eErr;
3526 : }
3527 :
3528 : /************************************************************************/
3529 : /* LoadBlockBuf() */
3530 : /* */
3531 : /* Load working block buffer with request block (tile/strip). */
3532 : /************************************************************************/
3533 :
3534 77663 : CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
3535 :
3536 : {
3537 : int nBlockBufSize;
3538 77663 : CPLErr eErr = CE_None;
3539 :
3540 77663 : if( nLoadedBlock == nBlockId )
3541 70345 : return CE_None;
3542 :
3543 : /* -------------------------------------------------------------------- */
3544 : /* If we have a dirty loaded block, flush it out first. */
3545 : /* -------------------------------------------------------------------- */
3546 7318 : if( nLoadedBlock != -1 && bLoadedBlockDirty )
3547 : {
3548 0 : eErr = FlushBlockBuf();
3549 0 : if( eErr != CE_None )
3550 0 : return eErr;
3551 : }
3552 :
3553 : /* -------------------------------------------------------------------- */
3554 : /* Get block size. */
3555 : /* -------------------------------------------------------------------- */
3556 7318 : if( TIFFIsTiled(hTIFF) )
3557 993 : nBlockBufSize = TIFFTileSize( hTIFF );
3558 : else
3559 6325 : nBlockBufSize = TIFFStripSize( hTIFF );
3560 :
3561 7318 : if ( !nBlockBufSize )
3562 : {
3563 : CPLError( CE_Failure, CPLE_AppDefined,
3564 0 : "Bogus block size; unable to allocate a buffer.");
3565 0 : return CE_Failure;
3566 : }
3567 :
3568 : /* -------------------------------------------------------------------- */
3569 : /* Allocate a temporary buffer for this strip. */
3570 : /* -------------------------------------------------------------------- */
3571 7318 : if( pabyBlockBuf == NULL )
3572 : {
3573 538 : pabyBlockBuf = (GByte *) VSICalloc( 1, nBlockBufSize );
3574 538 : if( pabyBlockBuf == NULL )
3575 : {
3576 : CPLError( CE_Failure, CPLE_OutOfMemory,
3577 : "Unable to allocate %d bytes for a temporary strip "
3578 : "buffer in GTIFF driver.",
3579 0 : nBlockBufSize );
3580 :
3581 0 : return( CE_Failure );
3582 : }
3583 : }
3584 :
3585 : /* -------------------------------------------------------------------- */
3586 : /* When called from ::IWriteBlock in separate cases (or in single band */
3587 : /* geotiffs), the ::IWriteBlock will override the content of the buffer*/
3588 : /* with pImage, so we don't need to read data from disk */
3589 : /* -------------------------------------------------------------------- */
3590 7318 : if( !bReadFromDisk )
3591 : {
3592 419 : nLoadedBlock = nBlockId;
3593 419 : return CE_None;
3594 : }
3595 :
3596 : /* libtiff 3.X doesn't like mixing read&write of JPEG compressed blocks */
3597 : /* The below hack is necessary due to another hack that consist in */
3598 : /* writing zero block to force creation of JPEG tables */
3599 6899 : if( nBlockId == 0 && bDontReloadFirstBlock )
3600 : {
3601 0 : bDontReloadFirstBlock = FALSE;
3602 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3603 0 : nLoadedBlock = nBlockId;
3604 0 : return CE_None;
3605 : }
3606 :
3607 : /* -------------------------------------------------------------------- */
3608 : /* The bottom most partial tiles and strips are sometimes only */
3609 : /* partially encoded. This code reduces the requested data so */
3610 : /* an error won't be reported in this case. (#1179) */
3611 : /* -------------------------------------------------------------------- */
3612 6899 : int nBlockReqSize = nBlockBufSize;
3613 6899 : int nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, nBlockXSize);
3614 6899 : int nBlockYOff = (nBlockId % nBlocksPerBand) / nBlocksPerRow;
3615 :
3616 6899 : if( (int)((nBlockYOff+1) * nBlockYSize) > nRasterYSize )
3617 : {
3618 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
3619 288 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
3620 288 : memset( pabyBlockBuf, 0, nBlockBufSize );
3621 : }
3622 :
3623 : /* -------------------------------------------------------------------- */
3624 : /* If we don't have this block already loaded, and we know it */
3625 : /* doesn't yet exist on disk, just zero the memory buffer and */
3626 : /* pretend we loaded it. */
3627 : /* -------------------------------------------------------------------- */
3628 6899 : if( !IsBlockAvailable( nBlockId ) )
3629 : {
3630 4494 : memset( pabyBlockBuf, 0, nBlockBufSize );
3631 4494 : nLoadedBlock = nBlockId;
3632 4494 : return CE_None;
3633 : }
3634 :
3635 : /* -------------------------------------------------------------------- */
3636 : /* Load the block, if it isn't our current block. */
3637 : /* -------------------------------------------------------------------- */
3638 2405 : if( TIFFIsTiled( hTIFF ) )
3639 : {
3640 458 : if( TIFFReadEncodedTile(hTIFF, nBlockId, pabyBlockBuf,
3641 : nBlockReqSize) == -1
3642 : && !bIgnoreReadErrors )
3643 : {
3644 : /* Once TIFFError() is properly hooked, this can go away */
3645 : CPLError( CE_Failure, CPLE_AppDefined,
3646 0 : "TIFFReadEncodedTile() failed." );
3647 :
3648 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3649 :
3650 0 : eErr = CE_Failure;
3651 : }
3652 : }
3653 : else
3654 : {
3655 1947 : if( TIFFReadEncodedStrip(hTIFF, nBlockId, pabyBlockBuf,
3656 : nBlockReqSize) == -1
3657 : && !bIgnoreReadErrors )
3658 : {
3659 : /* Once TIFFError() is properly hooked, this can go away */
3660 : CPLError( CE_Failure, CPLE_AppDefined,
3661 0 : "TIFFReadEncodedStrip() failed." );
3662 :
3663 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
3664 :
3665 0 : eErr = CE_Failure;
3666 : }
3667 : }
3668 :
3669 2405 : nLoadedBlock = nBlockId;
3670 2405 : bLoadedBlockDirty = FALSE;
3671 :
3672 2405 : return eErr;
3673 : }
3674 :
3675 :
3676 : /************************************************************************/
3677 : /* Crystalize() */
3678 : /* */
3679 : /* Make sure that the directory information is written out for */
3680 : /* a new file, require before writing any imagery data. */
3681 : /************************************************************************/
3682 :
3683 235309 : void GTiffDataset::Crystalize()
3684 :
3685 : {
3686 235309 : if( !bCrystalized )
3687 : {
3688 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
3689 976 : papszCreationOptions );
3690 976 : WriteGeoTIFFInfo();
3691 :
3692 976 : bMetadataChanged = FALSE;
3693 976 : bGeoTIFFInfoChanged = FALSE;
3694 976 : bNeedsRewrite = FALSE;
3695 :
3696 976 : bCrystalized = TRUE;
3697 :
3698 976 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffDataset::Crystalize");
3699 :
3700 : // Keep zip and tiff quality, and jpegcolormode which get reset when we call
3701 : // TIFFWriteDirectory
3702 976 : int jquality = -1, zquality = -1, nColorMode = -1;
3703 976 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
3704 976 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
3705 976 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
3706 :
3707 976 : TIFFWriteDirectory( hTIFF );
3708 976 : TIFFSetDirectory( hTIFF, 0 );
3709 :
3710 :
3711 : // Now, reset zip and tiff quality and jpegcolormode.
3712 976 : if(jquality > 0)
3713 14 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
3714 976 : if(zquality > 0)
3715 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
3716 976 : if (nColorMode >= 0)
3717 14 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, nColorMode);
3718 :
3719 976 : nDirOffset = TIFFCurrentDirOffset( hTIFF );
3720 : }
3721 235309 : }
3722 :
3723 :
3724 : /************************************************************************/
3725 : /* IsBlockAvailable() */
3726 : /* */
3727 : /* Return TRUE if the indicated strip/tile is available. We */
3728 : /* establish this by testing if the stripbytecount is zero. If */
3729 : /* zero then the block has never been committed to disk. */
3730 : /************************************************************************/
3731 :
3732 106678 : int GTiffDataset::IsBlockAvailable( int nBlockId )
3733 :
3734 : {
3735 106678 : toff_t *panByteCounts = NULL;
3736 :
3737 106678 : if( ( TIFFIsTiled( hTIFF )
3738 : && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts ) )
3739 : || ( !TIFFIsTiled( hTIFF )
3740 : && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts ) ) )
3741 : {
3742 106678 : if( panByteCounts == NULL )
3743 0 : return FALSE;
3744 : else
3745 106678 : return panByteCounts[nBlockId] != 0;
3746 : }
3747 : else
3748 0 : return FALSE;
3749 : }
3750 :
3751 : /************************************************************************/
3752 : /* FlushCache() */
3753 : /* */
3754 : /* We override this so we can also flush out local tiff strip */
3755 : /* cache if need be. */
3756 : /************************************************************************/
3757 :
3758 5915 : void GTiffDataset::FlushCache()
3759 :
3760 : {
3761 5915 : if (bIsFinalized)
3762 0 : return;
3763 :
3764 5915 : GDALPamDataset::FlushCache();
3765 :
3766 5915 : if( bLoadedBlockDirty && nLoadedBlock != -1 )
3767 157 : FlushBlockBuf();
3768 :
3769 5915 : CPLFree( pabyBlockBuf );
3770 5915 : pabyBlockBuf = NULL;
3771 5915 : nLoadedBlock = -1;
3772 5915 : bLoadedBlockDirty = FALSE;
3773 :
3774 5915 : if (!SetDirectory())
3775 0 : return;
3776 5915 : FlushDirectory();
3777 : }
3778 :
3779 : /************************************************************************/
3780 : /* FlushDirectory() */
3781 : /************************************************************************/
3782 :
3783 7319 : void GTiffDataset::FlushDirectory()
3784 :
3785 : {
3786 7319 : if( GetAccess() == GA_Update )
3787 : {
3788 3524 : if( bMetadataChanged )
3789 : {
3790 22 : if (!SetDirectory())
3791 0 : return;
3792 : bNeedsRewrite =
3793 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
3794 22 : papszCreationOptions );
3795 22 : bMetadataChanged = FALSE;
3796 : }
3797 :
3798 3524 : if( bGeoTIFFInfoChanged )
3799 : {
3800 31 : if (!SetDirectory())
3801 0 : return;
3802 31 : WriteGeoTIFFInfo();
3803 : }
3804 :
3805 3524 : if( bNeedsRewrite )
3806 : {
3807 : #if defined(TIFFLIB_VERSION)
3808 : #if defined(HAVE_TIFFGETSIZEPROC)
3809 90 : if (!SetDirectory())
3810 0 : return;
3811 :
3812 90 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3813 :
3814 90 : nDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3815 90 : if( (nDirOffset % 2) == 1 )
3816 15 : nDirOffset++;
3817 :
3818 90 : TIFFRewriteDirectory( hTIFF );
3819 :
3820 90 : TIFFSetSubDirectory( hTIFF, nDirOffset );
3821 : #elif TIFFLIB_VERSION > 20010925 && TIFFLIB_VERSION != 20011807
3822 : if (!SetDirectory())
3823 : return;
3824 :
3825 : TIFFRewriteDirectory( hTIFF );
3826 : #endif
3827 : #endif
3828 90 : bNeedsRewrite = FALSE;
3829 : }
3830 : }
3831 :
3832 : // there are some circumstances in which we can reach this point
3833 : // without having made this our directory (SetDirectory()) in which
3834 : // case we should not risk a flush.
3835 7319 : if( GetAccess() == GA_Update && TIFFCurrentDirOffset(hTIFF) == nDirOffset )
3836 : {
3837 : #if defined(BIGTIFF_SUPPORT)
3838 3506 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3839 :
3840 3506 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3841 3506 : if( (nNewDirOffset % 2) == 1 )
3842 438 : nNewDirOffset++;
3843 :
3844 3506 : TIFFFlush( hTIFF );
3845 :
3846 3506 : if( nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
3847 : {
3848 55 : nDirOffset = nNewDirOffset;
3849 : CPLDebug( "GTiff",
3850 55 : "directory moved during flush in FlushDirectory()" );
3851 : }
3852 : #else
3853 : /* For libtiff 3.X, the above causes regressions and crashes in */
3854 : /* tiff_write.py and tiff_ovr.py */
3855 : TIFFFlush( hTIFF );
3856 : #endif
3857 : }
3858 : }
3859 :
3860 : /************************************************************************/
3861 : /* TIFF_OvLevelAdjust() */
3862 : /* */
3863 : /* Some overview levels cannot be achieved closely enough to be */
3864 : /* recognised as the desired overview level. This function */
3865 : /* will adjust an overview level to one that is achievable on */
3866 : /* the given raster size. */
3867 : /* */
3868 : /* For instance a 1200x1200 image on which a 256 level overview */
3869 : /* is request will end up generating a 5x5 overview. However, */
3870 : /* this will appear to the system be a level 240 overview. */
3871 : /* This function will adjust 256 to 240 based on knowledge of */
3872 : /* the image size. */
3873 : /* */
3874 : /* This is a copy of the GDALOvLevelAdjust() function in */
3875 : /* gdaldefaultoverviews.cpp. */
3876 : /************************************************************************/
3877 :
3878 199 : static int TIFF_OvLevelAdjust( int nOvLevel, int nXSize )
3879 :
3880 : {
3881 199 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
3882 :
3883 199 : return (int) (0.5 + nXSize / (double) nOXSize);
3884 : }
3885 :
3886 : /************************************************************************/
3887 : /* CleanOverviews() */
3888 : /************************************************************************/
3889 :
3890 2 : CPLErr GTiffDataset::CleanOverviews()
3891 :
3892 : {
3893 2 : CPLAssert( bBase );
3894 :
3895 2 : ScanDirectories();
3896 :
3897 2 : FlushDirectory();
3898 2 : *ppoActiveDSRef = NULL;
3899 :
3900 : /* -------------------------------------------------------------------- */
3901 : /* Cleanup overviews objects, and get offsets to all overview */
3902 : /* directories. */
3903 : /* -------------------------------------------------------------------- */
3904 2 : std::vector<toff_t> anOvDirOffsets;
3905 : int i;
3906 :
3907 4 : for( i = 0; i < nOverviewCount; i++ )
3908 : {
3909 2 : anOvDirOffsets.push_back( papoOverviewDS[i]->nDirOffset );
3910 2 : delete papoOverviewDS[i];
3911 : }
3912 :
3913 : /* -------------------------------------------------------------------- */
3914 : /* Loop through all the directories, translating the offsets */
3915 : /* into indexes we can use with TIFFUnlinkDirectory(). */
3916 : /* -------------------------------------------------------------------- */
3917 2 : std::vector<uint16> anOvDirIndexes;
3918 2 : int iThisOffset = 1;
3919 :
3920 2 : TIFFSetDirectory( hTIFF, 0 );
3921 :
3922 2 : for( ; TRUE; )
3923 : {
3924 8 : for( i = 0; i < nOverviewCount; i++ )
3925 : {
3926 4 : if( anOvDirOffsets[i] == TIFFCurrentDirOffset( hTIFF ) )
3927 : {
3928 : CPLDebug( "GTiff", "%d -> %d",
3929 2 : (int) anOvDirOffsets[i], iThisOffset );
3930 2 : anOvDirIndexes.push_back( (uint16) iThisOffset );
3931 : }
3932 : }
3933 :
3934 4 : if( TIFFLastDirectory( hTIFF ) )
3935 : break;
3936 :
3937 2 : TIFFReadDirectory( hTIFF );
3938 2 : iThisOffset++;
3939 : }
3940 :
3941 : /* -------------------------------------------------------------------- */
3942 : /* Actually unlink the target directories. Note that we do */
3943 : /* this from last to first so as to avoid renumbering any of */
3944 : /* the earlier directories we need to remove. */
3945 : /* -------------------------------------------------------------------- */
3946 6 : while( !anOvDirIndexes.empty() )
3947 : {
3948 2 : TIFFUnlinkDirectory( hTIFF, anOvDirIndexes.back() );
3949 2 : anOvDirIndexes.pop_back();
3950 : }
3951 :
3952 2 : CPLFree( papoOverviewDS );
3953 :
3954 2 : nOverviewCount = 0;
3955 2 : papoOverviewDS = NULL;
3956 :
3957 2 : if (!SetDirectory())
3958 0 : return CE_Failure;
3959 :
3960 2 : return CE_None;
3961 : }
3962 :
3963 :
3964 : /************************************************************************/
3965 : /* RegisterNewOverviewDataset() */
3966 : /************************************************************************/
3967 :
3968 133 : CPLErr GTiffDataset::RegisterNewOverviewDataset(toff_t nOverviewOffset)
3969 : {
3970 133 : GTiffDataset* poODS = new GTiffDataset();
3971 133 : poODS->nJpegQuality = nJpegQuality;
3972 133 : poODS->nZLevel = nZLevel;
3973 133 : poODS->nLZMAPreset = nLZMAPreset;
3974 :
3975 133 : if( nCompression == COMPRESSION_JPEG )
3976 : {
3977 18 : if ( CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
3978 : {
3979 8 : poODS->nJpegQuality = atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75"));
3980 : }
3981 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
3982 18 : poODS->nJpegQuality );
3983 : }
3984 :
3985 133 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nOverviewOffset, FALSE,
3986 : GA_Update ) != CE_None )
3987 : {
3988 0 : delete poODS;
3989 0 : return CE_Failure;
3990 : }
3991 : else
3992 : {
3993 133 : nOverviewCount++;
3994 : papoOverviewDS = (GTiffDataset **)
3995 : CPLRealloc(papoOverviewDS,
3996 133 : nOverviewCount * (sizeof(void*)));
3997 133 : papoOverviewDS[nOverviewCount-1] = poODS;
3998 133 : poODS->poBaseDS = this;
3999 133 : return CE_None;
4000 : }
4001 : }
4002 :
4003 : /************************************************************************/
4004 : /* CreateOverviewsFromSrcOverviews() */
4005 : /************************************************************************/
4006 :
4007 5 : CPLErr GTiffDataset::CreateOverviewsFromSrcOverviews(GDALDataset* poSrcDS)
4008 : {
4009 5 : CPLAssert(poSrcDS->GetRasterCount() != 0);
4010 5 : CPLAssert(nOverviewCount == 0);
4011 :
4012 5 : ScanDirectories();
4013 :
4014 : /* -------------------------------------------------------------------- */
4015 : /* Move to the directory for this dataset. */
4016 : /* -------------------------------------------------------------------- */
4017 5 : if (!SetDirectory())
4018 0 : return CE_Failure;
4019 5 : FlushDirectory();
4020 :
4021 5 : int nOvBitsPerSample = nBitsPerSample;
4022 :
4023 : /* -------------------------------------------------------------------- */
4024 : /* Do we have a palette? If so, create a TIFF compatible version. */
4025 : /* -------------------------------------------------------------------- */
4026 5 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
4027 5 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
4028 :
4029 5 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
4030 : {
4031 : int nColors;
4032 :
4033 0 : if( nOvBitsPerSample == 8 )
4034 0 : nColors = 256;
4035 0 : else if( nOvBitsPerSample < 8 )
4036 0 : nColors = 1 << nOvBitsPerSample;
4037 : else
4038 0 : nColors = 65536;
4039 :
4040 0 : anTRed.resize(nColors,0);
4041 0 : anTGreen.resize(nColors,0);
4042 0 : anTBlue.resize(nColors,0);
4043 :
4044 0 : for( int iColor = 0; iColor < nColors; iColor++ )
4045 : {
4046 0 : if( iColor < poColorTable->GetColorEntryCount() )
4047 : {
4048 : GDALColorEntry sRGB;
4049 :
4050 0 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
4051 :
4052 0 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
4053 0 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
4054 0 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
4055 : }
4056 : else
4057 : {
4058 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
4059 : }
4060 : }
4061 :
4062 0 : panRed = &(anTRed[0]);
4063 0 : panGreen = &(anTGreen[0]);
4064 0 : panBlue = &(anTBlue[0]);
4065 : }
4066 :
4067 : /* -------------------------------------------------------------------- */
4068 : /* Do we need some metadata for the overviews? */
4069 : /* -------------------------------------------------------------------- */
4070 5 : CPLString osMetadata;
4071 :
4072 5 : GTIFFBuildOverviewMetadata( "NONE", this, osMetadata );
4073 :
4074 : /* -------------------------------------------------------------------- */
4075 : /* Fetch extra sample tag */
4076 : /* -------------------------------------------------------------------- */
4077 5 : uint16 *panExtraSampleValues = NULL;
4078 5 : uint16 nExtraSamples = 0;
4079 :
4080 5 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
4081 : {
4082 0 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
4083 0 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
4084 0 : panExtraSampleValues = panExtraSampleValuesNew;
4085 : }
4086 : else
4087 : {
4088 5 : panExtraSampleValues = NULL;
4089 5 : nExtraSamples = 0;
4090 : }
4091 :
4092 : /* -------------------------------------------------------------------- */
4093 : /* Fetch predictor tag */
4094 : /* -------------------------------------------------------------------- */
4095 5 : uint16 nPredictor = PREDICTOR_NONE;
4096 5 : if ( nCompression == COMPRESSION_LZW ||
4097 : nCompression == COMPRESSION_ADOBE_DEFLATE )
4098 0 : TIFFGetField( hTIFF, TIFFTAG_PREDICTOR, &nPredictor );
4099 : int nOvrBlockXSize, nOvrBlockYSize;
4100 5 : GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
4101 :
4102 5 : int nSrcOverviews = poSrcDS->GetRasterBand(1)->GetOverviewCount();
4103 : int i;
4104 5 : CPLErr eErr = CE_None;
4105 :
4106 18 : for(i=0;i<nSrcOverviews && eErr == CE_None;i++)
4107 : {
4108 13 : GDALRasterBand* poOvrBand = poSrcDS->GetRasterBand(1)->GetOverview(i);
4109 :
4110 13 : int nOXSize = poOvrBand->GetXSize(), nOYSize = poOvrBand->GetYSize();
4111 :
4112 : toff_t nOverviewOffset =
4113 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
4114 : nOXSize, nOYSize,
4115 : nOvBitsPerSample, nPlanarConfig,
4116 : nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4117 : nCompression, nPhotometric, nSampleFormat,
4118 : nPredictor,
4119 : panRed, panGreen, panBlue,
4120 : nExtraSamples, panExtraSampleValues,
4121 13 : osMetadata );
4122 :
4123 13 : if( nOverviewOffset == 0 )
4124 0 : eErr = CE_Failure;
4125 : else
4126 13 : eErr = RegisterNewOverviewDataset(nOverviewOffset);
4127 : }
4128 :
4129 5 : CPLFree(panExtraSampleValues);
4130 5 : panExtraSampleValues = NULL;
4131 :
4132 : /* -------------------------------------------------------------------- */
4133 : /* Create overviews for the mask. */
4134 : /* -------------------------------------------------------------------- */
4135 5 : if (eErr == CE_None)
4136 5 : eErr = CreateInternalMaskOverviews(nOvrBlockXSize, nOvrBlockYSize);
4137 :
4138 5 : return eErr;
4139 : }
4140 :
4141 :
4142 : /************************************************************************/
4143 : /* CreateInternalMaskOverviews() */
4144 : /************************************************************************/
4145 :
4146 88 : CPLErr GTiffDataset::CreateInternalMaskOverviews(int nOvrBlockXSize,
4147 : int nOvrBlockYSize)
4148 : {
4149 : GTiffDataset *poODS;
4150 :
4151 88 : ScanDirectories();
4152 :
4153 : /* -------------------------------------------------------------------- */
4154 : /* Create overviews for the mask. */
4155 : /* -------------------------------------------------------------------- */
4156 88 : CPLErr eErr = CE_None;
4157 :
4158 88 : const char* pszInternalMask = CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", NULL);
4159 88 : if (poMaskDS != NULL &&
4160 : poMaskDS->GetRasterCount() == 1 &&
4161 : (pszInternalMask == NULL || CSLTestBoolean(pszInternalMask)))
4162 : {
4163 : int nMaskOvrCompression;
4164 4 : if( strstr(GDALGetMetadataItem(GDALGetDriverByName( "GTiff" ),
4165 : GDAL_DMD_CREATIONOPTIONLIST, NULL ),
4166 : "<Value>DEFLATE</Value>") != NULL )
4167 4 : nMaskOvrCompression = COMPRESSION_ADOBE_DEFLATE;
4168 : else
4169 0 : nMaskOvrCompression = COMPRESSION_PACKBITS;
4170 :
4171 : int i;
4172 12 : for( i = 0; i < nOverviewCount; i++ )
4173 : {
4174 8 : if (papoOverviewDS[i]->poMaskDS == NULL)
4175 : {
4176 : toff_t nOverviewOffset;
4177 :
4178 : nOverviewOffset =
4179 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
4180 16 : papoOverviewDS[i]->nRasterXSize, papoOverviewDS[i]->nRasterYSize,
4181 : 1, PLANARCONFIG_CONTIG,
4182 : 1, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4183 : nMaskOvrCompression, PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT, PREDICTOR_NONE,
4184 : NULL, NULL, NULL, 0, NULL,
4185 24 : "" );
4186 :
4187 8 : if( nOverviewOffset == 0 )
4188 : {
4189 0 : eErr = CE_Failure;
4190 0 : continue;
4191 : }
4192 :
4193 8 : poODS = new GTiffDataset();
4194 8 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef,
4195 : nOverviewOffset, FALSE,
4196 : GA_Update ) != CE_None )
4197 : {
4198 0 : delete poODS;
4199 0 : eErr = CE_Failure;
4200 : }
4201 : else
4202 : {
4203 8 : poODS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
4204 8 : poODS->poBaseDS = this;
4205 8 : papoOverviewDS[i]->poMaskDS = poODS;
4206 8 : poMaskDS->nOverviewCount++;
4207 : poMaskDS->papoOverviewDS = (GTiffDataset **)
4208 : CPLRealloc(poMaskDS->papoOverviewDS,
4209 8 : poMaskDS->nOverviewCount * (sizeof(void*)));
4210 8 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] = poODS;
4211 : }
4212 : }
4213 : }
4214 : }
4215 :
4216 88 : return eErr;
4217 : }
4218 :
4219 : /************************************************************************/
4220 : /* IBuildOverviews() */
4221 : /************************************************************************/
4222 :
4223 151 : CPLErr GTiffDataset::IBuildOverviews(
4224 : const char * pszResampling,
4225 : int nOverviews, int * panOverviewList,
4226 : int nBands, int * panBandList,
4227 : GDALProgressFunc pfnProgress, void * pProgressData )
4228 :
4229 : {
4230 151 : CPLErr eErr = CE_None;
4231 : int i;
4232 : GTiffDataset *poODS;
4233 151 : int bUseGenericHandling = FALSE;
4234 :
4235 151 : ScanDirectories();
4236 :
4237 : /* -------------------------------------------------------------------- */
4238 : /* If RRD or external OVR overviews requested, then invoke */
4239 : /* generic handling. */
4240 : /* -------------------------------------------------------------------- */
4241 151 : if( CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" ))
4242 : || CSLTestBoolean(CPLGetConfigOption( "TIFF_USE_OVR", "NO" )) )
4243 : {
4244 2 : bUseGenericHandling = TRUE;
4245 : }
4246 :
4247 : /* -------------------------------------------------------------------- */
4248 : /* If we don't have read access, then create the overviews */
4249 : /* externally. */
4250 : /* -------------------------------------------------------------------- */
4251 151 : if( GetAccess() != GA_Update )
4252 : {
4253 : CPLDebug( "GTiff",
4254 : "File open for read-only accessing, "
4255 63 : "creating overviews externally." );
4256 :
4257 63 : bUseGenericHandling = TRUE;
4258 : }
4259 :
4260 151 : if( bUseGenericHandling )
4261 : {
4262 65 : if (nOverviewCount != 0)
4263 : {
4264 : CPLError(CE_Failure, CPLE_NotSupported,
4265 0 : "Cannot add external overviews when there are already internal overviews");
4266 0 : return CE_Failure;
4267 : }
4268 :
4269 : return GDALDataset::IBuildOverviews(
4270 : pszResampling, nOverviews, panOverviewList,
4271 65 : nBands, panBandList, pfnProgress, pProgressData );
4272 : }
4273 :
4274 : /* -------------------------------------------------------------------- */
4275 : /* Our TIFF overview support currently only works safely if all */
4276 : /* bands are handled at the same time. */
4277 : /* -------------------------------------------------------------------- */
4278 86 : if( nBands != GetRasterCount() )
4279 : {
4280 : CPLError( CE_Failure, CPLE_NotSupported,
4281 : "Generation of overviews in TIFF currently only"
4282 : " supported when operating on all bands.\n"
4283 0 : "Operation failed.\n" );
4284 0 : return CE_Failure;
4285 : }
4286 :
4287 : /* -------------------------------------------------------------------- */
4288 : /* If zero overviews were requested, we need to clear all */
4289 : /* existing overviews. */
4290 : /* -------------------------------------------------------------------- */
4291 86 : if( nOverviews == 0 )
4292 : {
4293 3 : if( nOverviewCount == 0 )
4294 : return GDALDataset::IBuildOverviews(
4295 : pszResampling, nOverviews, panOverviewList,
4296 1 : nBands, panBandList, pfnProgress, pProgressData );
4297 : else
4298 2 : return CleanOverviews();
4299 : }
4300 :
4301 : /* -------------------------------------------------------------------- */
4302 : /* libtiff 3.X has issues when generating interleaved overviews. */
4303 : /* so generate them one after another one. */
4304 : /* -------------------------------------------------------------------- */
4305 : #ifndef BIGTIFF_SUPPORT
4306 : if( nOverviews > 1 )
4307 : {
4308 : double* padfOvrRasterFactor = (double*) CPLMalloc(sizeof(double) * nOverviews);
4309 : double dfTotal = 0;
4310 : for( i = 0; i < nOverviews; i++ )
4311 : {
4312 : if( panOverviewList[i] <= 0 )
4313 : {
4314 : CPLError(CE_Failure, CPLE_AppDefined,
4315 : "Invalid overview factor : %d", panOverviewList[i]);
4316 : eErr = CE_Failure;
4317 : break;
4318 : }
4319 : padfOvrRasterFactor[i] = 1.0 / (panOverviewList[i] * panOverviewList[i]);
4320 : dfTotal += padfOvrRasterFactor[i];
4321 : }
4322 :
4323 : double dfAcc = 0.0;
4324 : for( i = 0; i < nOverviews && eErr == CE_None; i++ )
4325 : {
4326 : void *pScaledProgressData;
4327 : pScaledProgressData =
4328 : GDALCreateScaledProgress( dfAcc / dfTotal,
4329 : (dfAcc + padfOvrRasterFactor[i]) / dfTotal,
4330 : pfnProgress, pProgressData );
4331 : dfAcc += padfOvrRasterFactor[i];
4332 :
4333 : eErr = IBuildOverviews(
4334 : pszResampling, 1, &panOverviewList[i],
4335 : nBands, panBandList, GDALScaledProgress, pScaledProgressData );
4336 :
4337 : GDALDestroyScaledProgress(pScaledProgressData);
4338 : }
4339 :
4340 : CPLFree(padfOvrRasterFactor);
4341 :
4342 : return eErr;
4343 : }
4344 : #endif
4345 :
4346 : /* -------------------------------------------------------------------- */
4347 : /* Initialize progress counter. */
4348 : /* -------------------------------------------------------------------- */
4349 83 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
4350 : {
4351 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
4352 0 : return CE_Failure;
4353 : }
4354 :
4355 : /* -------------------------------------------------------------------- */
4356 : /* Move to the directory for this dataset. */
4357 : /* -------------------------------------------------------------------- */
4358 83 : if (!SetDirectory())
4359 0 : return CE_Failure;
4360 83 : FlushDirectory();
4361 :
4362 : /* -------------------------------------------------------------------- */
4363 : /* If we are averaging bit data to grayscale we need to create */
4364 : /* 8bit overviews. */
4365 : /* -------------------------------------------------------------------- */
4366 83 : int nOvBitsPerSample = nBitsPerSample;
4367 :
4368 83 : if( EQUALN(pszResampling,"AVERAGE_BIT2",12) )
4369 2 : nOvBitsPerSample = 8;
4370 :
4371 : /* -------------------------------------------------------------------- */
4372 : /* Do we have a palette? If so, create a TIFF compatible version. */
4373 : /* -------------------------------------------------------------------- */
4374 83 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
4375 83 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
4376 :
4377 83 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
4378 : {
4379 : int nColors;
4380 :
4381 9 : if( nOvBitsPerSample == 8 )
4382 9 : nColors = 256;
4383 0 : else if( nOvBitsPerSample < 8 )
4384 0 : nColors = 1 << nOvBitsPerSample;
4385 : else
4386 0 : nColors = 65536;
4387 :
4388 9 : anTRed.resize(nColors,0);
4389 9 : anTGreen.resize(nColors,0);
4390 9 : anTBlue.resize(nColors,0);
4391 :
4392 2313 : for( int iColor = 0; iColor < nColors; iColor++ )
4393 : {
4394 2304 : if( iColor < poColorTable->GetColorEntryCount() )
4395 : {
4396 : GDALColorEntry sRGB;
4397 :
4398 2304 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
4399 :
4400 2304 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
4401 2304 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
4402 2304 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
4403 : }
4404 : else
4405 : {
4406 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
4407 : }
4408 : }
4409 :
4410 9 : panRed = &(anTRed[0]);
4411 9 : panGreen = &(anTGreen[0]);
4412 9 : panBlue = &(anTBlue[0]);
4413 : }
4414 :
4415 : /* -------------------------------------------------------------------- */
4416 : /* Do we need some metadata for the overviews? */
4417 : /* -------------------------------------------------------------------- */
4418 83 : CPLString osMetadata;
4419 :
4420 83 : GTIFFBuildOverviewMetadata( pszResampling, this, osMetadata );
4421 :
4422 : /* -------------------------------------------------------------------- */
4423 : /* Fetch extra sample tag */
4424 : /* -------------------------------------------------------------------- */
4425 83 : uint16 *panExtraSampleValues = NULL;
4426 83 : uint16 nExtraSamples = 0;
4427 :
4428 83 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
4429 : {
4430 8 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
4431 8 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
4432 8 : panExtraSampleValues = panExtraSampleValuesNew;
4433 : }
4434 : else
4435 : {
4436 75 : panExtraSampleValues = NULL;
4437 75 : nExtraSamples = 0;
4438 : }
4439 :
4440 : /* -------------------------------------------------------------------- */
4441 : /* Fetch predictor tag */
4442 : /* -------------------------------------------------------------------- */
4443 83 : uint16 nPredictor = PREDICTOR_NONE;
4444 83 : if ( nCompression == COMPRESSION_LZW ||
4445 : nCompression == COMPRESSION_ADOBE_DEFLATE )
4446 7 : TIFFGetField( hTIFF, TIFFTAG_PREDICTOR, &nPredictor );
4447 :
4448 : /* -------------------------------------------------------------------- */
4449 : /* Establish which of the overview levels we already have, and */
4450 : /* which are new. We assume that band 1 of the file is */
4451 : /* representative. */
4452 : /* -------------------------------------------------------------------- */
4453 : int nOvrBlockXSize, nOvrBlockYSize;
4454 83 : GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
4455 217 : for( i = 0; i < nOverviews && eErr == CE_None; i++ )
4456 : {
4457 : int j;
4458 :
4459 221 : for( j = 0; j < nOverviewCount && eErr == CE_None; j++ )
4460 : {
4461 : int nOvFactor;
4462 :
4463 87 : poODS = papoOverviewDS[j];
4464 :
4465 : nOvFactor = (int)
4466 87 : (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
4467 :
4468 87 : if( nOvFactor == panOverviewList[i]
4469 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4470 : GetRasterXSize() ) )
4471 14 : panOverviewList[i] *= -1;
4472 : }
4473 :
4474 134 : if( panOverviewList[i] > 0 )
4475 : {
4476 : toff_t nOverviewOffset;
4477 : int nOXSize, nOYSize;
4478 :
4479 120 : nOXSize = (GetRasterXSize() + panOverviewList[i] - 1)
4480 240 : / panOverviewList[i];
4481 120 : nOYSize = (GetRasterYSize() + panOverviewList[i] - 1)
4482 240 : / panOverviewList[i];
4483 :
4484 : nOverviewOffset =
4485 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
4486 : nOXSize, nOYSize,
4487 : nOvBitsPerSample, nPlanarConfig,
4488 : nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
4489 : nCompression, nPhotometric, nSampleFormat,
4490 : nPredictor,
4491 : panRed, panGreen, panBlue,
4492 : nExtraSamples, panExtraSampleValues,
4493 120 : osMetadata );
4494 :
4495 :
4496 120 : if( nOverviewOffset == 0 )
4497 0 : eErr = CE_Failure;
4498 : else
4499 120 : eErr = RegisterNewOverviewDataset(nOverviewOffset);
4500 : }
4501 : else
4502 14 : panOverviewList[i] *= -1;
4503 : }
4504 :
4505 83 : CPLFree(panExtraSampleValues);
4506 83 : panExtraSampleValues = NULL;
4507 :
4508 : /* -------------------------------------------------------------------- */
4509 : /* Create overviews for the mask. */
4510 : /* -------------------------------------------------------------------- */
4511 83 : if (eErr == CE_None)
4512 83 : eErr = CreateInternalMaskOverviews(nOvrBlockXSize, nOvrBlockYSize);
4513 : else
4514 0 : return eErr;
4515 :
4516 : /* -------------------------------------------------------------------- */
4517 : /* Refresh overviews for the mask */
4518 : /* -------------------------------------------------------------------- */
4519 94 : if (poMaskDS != NULL &&
4520 : poMaskDS->GetRasterCount() == 1)
4521 : {
4522 : GDALRasterBand **papoOverviewBands;
4523 11 : int nMaskOverviews = 0;
4524 :
4525 11 : papoOverviewBands = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviewCount);
4526 33 : for( i = 0; i < nOverviewCount; i++ )
4527 : {
4528 22 : if (papoOverviewDS[i]->poMaskDS != NULL)
4529 : {
4530 36 : papoOverviewBands[nMaskOverviews ++] =
4531 18 : papoOverviewDS[i]->poMaskDS->GetRasterBand(1);
4532 : }
4533 : }
4534 : eErr = GDALRegenerateOverviews( (GDALRasterBandH)
4535 : poMaskDS->GetRasterBand(1),
4536 : nMaskOverviews,
4537 : (GDALRasterBandH *) papoOverviewBands,
4538 11 : pszResampling, GDALDummyProgress, NULL);
4539 11 : CPLFree(papoOverviewBands);
4540 : }
4541 :
4542 :
4543 : /* -------------------------------------------------------------------- */
4544 : /* Refresh old overviews that were listed. */
4545 : /* -------------------------------------------------------------------- */
4546 99 : if (nCompression != COMPRESSION_NONE &&
4547 : nPlanarConfig == PLANARCONFIG_CONTIG &&
4548 : GDALDataTypeIsComplex(GetRasterBand( panBandList[0] )->GetRasterDataType()) == FALSE &&
4549 16 : GetRasterBand( panBandList[0] )->GetColorTable() == NULL &&
4550 : (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
4551 : {
4552 : /* In the case of pixel interleaved compressed overviews, we want to generate */
4553 : /* the overviews for all the bands block by block, and not band after band, */
4554 : /* in order to write the block once and not loose space in the TIFF file */
4555 :
4556 : GDALRasterBand ***papapoOverviewBands;
4557 : GDALRasterBand **papoBandList;
4558 :
4559 16 : int nNewOverviews = 0;
4560 : int iBand;
4561 :
4562 16 : papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
4563 16 : papoBandList = (GDALRasterBand **) CPLCalloc(sizeof(void*),nBands);
4564 60 : for( iBand = 0; iBand < nBands; iBand++ )
4565 : {
4566 44 : GDALRasterBand* poBand = GetRasterBand( panBandList[iBand] );
4567 :
4568 44 : papoBandList[iBand] = poBand;
4569 44 : papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*), poBand->GetOverviewCount());
4570 :
4571 44 : int iCurOverview = 0;
4572 114 : for( i = 0; i < nOverviews; i++ )
4573 : {
4574 : int j;
4575 :
4576 96 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
4577 : {
4578 : int nOvFactor;
4579 96 : GDALRasterBand * poOverview = poBand->GetOverview( j );
4580 :
4581 : nOvFactor = (int)
4582 96 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
4583 :
4584 : int bHasNoData;
4585 96 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
4586 :
4587 96 : if (bHasNoData)
4588 18 : poOverview->SetNoDataValue(noDataValue);
4589 :
4590 96 : if( nOvFactor == panOverviewList[i]
4591 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4592 : poBand->GetXSize() ) )
4593 : {
4594 70 : papapoOverviewBands[iBand][iCurOverview] = poOverview;
4595 70 : iCurOverview++ ;
4596 70 : break;
4597 : }
4598 : }
4599 : }
4600 :
4601 44 : if (nNewOverviews == 0)
4602 16 : nNewOverviews = iCurOverview;
4603 28 : else if (nNewOverviews != iCurOverview)
4604 : {
4605 0 : CPLAssert(0);
4606 0 : return CE_Failure;
4607 : }
4608 : }
4609 :
4610 : GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
4611 : nNewOverviews, papapoOverviewBands,
4612 16 : pszResampling, pfnProgress, pProgressData );
4613 :
4614 60 : for( iBand = 0; iBand < nBands; iBand++ )
4615 : {
4616 44 : CPLFree(papapoOverviewBands[iBand]);
4617 : }
4618 16 : CPLFree(papapoOverviewBands);
4619 16 : CPLFree(papoBandList);
4620 : }
4621 : else
4622 : {
4623 : GDALRasterBand **papoOverviewBands;
4624 :
4625 : papoOverviewBands = (GDALRasterBand **)
4626 67 : CPLCalloc(sizeof(void*),nOverviews);
4627 :
4628 160 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
4629 : {
4630 : GDALRasterBand *poBand;
4631 : int nNewOverviews;
4632 :
4633 93 : poBand = GetRasterBand( panBandList[iBand] );
4634 :
4635 93 : nNewOverviews = 0;
4636 257 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
4637 : {
4638 : int j;
4639 :
4640 263 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
4641 : {
4642 : int nOvFactor;
4643 263 : GDALRasterBand * poOverview = poBand->GetOverview( j );
4644 :
4645 : int bHasNoData;
4646 263 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
4647 :
4648 263 : if (bHasNoData)
4649 7 : poOverview->SetNoDataValue(noDataValue);
4650 :
4651 : nOvFactor = (int)
4652 263 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
4653 :
4654 263 : if( nOvFactor == panOverviewList[i]
4655 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
4656 : poBand->GetXSize() ) )
4657 : {
4658 164 : papoOverviewBands[nNewOverviews++] = poOverview;
4659 164 : break;
4660 : }
4661 : }
4662 : }
4663 :
4664 : void *pScaledProgressData;
4665 :
4666 : pScaledProgressData =
4667 : GDALCreateScaledProgress( iBand / (double) nBands,
4668 : (iBand+1) / (double) nBands,
4669 93 : pfnProgress, pProgressData );
4670 :
4671 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
4672 : nNewOverviews,
4673 : (GDALRasterBandH *) papoOverviewBands,
4674 : pszResampling,
4675 : GDALScaledProgress,
4676 93 : pScaledProgressData);
4677 :
4678 93 : GDALDestroyScaledProgress( pScaledProgressData );
4679 : }
4680 :
4681 : /* -------------------------------------------------------------------- */
4682 : /* Cleanup */
4683 : /* -------------------------------------------------------------------- */
4684 67 : CPLFree( papoOverviewBands );
4685 : }
4686 :
4687 :
4688 83 : pfnProgress( 1.0, NULL, pProgressData );
4689 :
4690 83 : return eErr;
4691 : }
4692 :
4693 : /************************************************************************/
4694 : /* GTiffWriteDummyGeokeyDirectory() */
4695 : /************************************************************************/
4696 :
4697 762 : static void GTiffWriteDummyGeokeyDirectory(TIFF* hTIFF)
4698 : {
4699 : // If we have existing geokeys, try to wipe them
4700 : // by writing a dummy geokey directory. (#2546)
4701 762 : uint16 *panVI = NULL;
4702 : uint16 nKeyCount;
4703 :
4704 762 : if( TIFFGetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
4705 : &nKeyCount, &panVI ) )
4706 : {
4707 22 : GUInt16 anGKVersionInfo[4] = { 1, 1, 0, 0 };
4708 22 : double adfDummyDoubleParams[1] = { 0.0 };
4709 : TIFFSetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
4710 22 : 4, anGKVersionInfo );
4711 : TIFFSetField( hTIFF, TIFFTAG_GEODOUBLEPARAMS,
4712 22 : 1, adfDummyDoubleParams );
4713 22 : TIFFSetField( hTIFF, TIFFTAG_GEOASCIIPARAMS, "" );
4714 : }
4715 762 : }
4716 :
4717 : /************************************************************************/
4718 : /* WriteGeoTIFFInfo() */
4719 : /************************************************************************/
4720 :
4721 1007 : void GTiffDataset::WriteGeoTIFFInfo()
4722 :
4723 : {
4724 1007 : bool bPixelIsPoint = false;
4725 1007 : int bPointGeoIgnore = FALSE;
4726 :
4727 1299 : if( GetMetadataItem( GDALMD_AREA_OR_POINT )
4728 292 : && EQUAL(GetMetadataItem(GDALMD_AREA_OR_POINT),
4729 : GDALMD_AOP_POINT) )
4730 : {
4731 4 : bPixelIsPoint = true;
4732 : bPointGeoIgnore =
4733 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
4734 4 : "FALSE") );
4735 : }
4736 :
4737 1007 : if( bForceUnsetGT )
4738 : {
4739 1 : bNeedsRewrite = TRUE;
4740 1 : bForceUnsetGT = FALSE;
4741 :
4742 : #ifdef HAVE_UNSETFIELD
4743 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
4744 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTIEPOINTS );
4745 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTRANSMATRIX );
4746 : #endif
4747 : }
4748 :
4749 1007 : if( bForceUnsetProjection )
4750 : {
4751 1 : bNeedsRewrite = TRUE;
4752 1 : bForceUnsetProjection = FALSE;
4753 :
4754 : #ifdef HAVE_UNSETFIELD
4755 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY );
4756 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEODOUBLEPARAMS );
4757 1 : TIFFUnsetField( hTIFF, TIFFTAG_GEOASCIIPARAMS );
4758 : #else
4759 : GTiffWriteDummyGeokeyDirectory(hTIFF);
4760 : #endif
4761 : }
4762 :
4763 : /* -------------------------------------------------------------------- */
4764 : /* If the geotransform is the default, don't bother writing it. */
4765 : /* -------------------------------------------------------------------- */
4766 3176 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
4767 588 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
4768 861 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 )
4769 : {
4770 720 : bNeedsRewrite = TRUE;
4771 :
4772 : /* -------------------------------------------------------------------- */
4773 : /* Clear old tags to ensure we don't end up with conflicting */
4774 : /* information. (#2625) */
4775 : /* -------------------------------------------------------------------- */
4776 : #ifdef HAVE_UNSETFIELD
4777 720 : TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
4778 720 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTIEPOINTS );
4779 720 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTRANSMATRIX );
4780 : #endif
4781 :
4782 : /* -------------------------------------------------------------------- */
4783 : /* Write the transform. If we have a normal north-up image we */
4784 : /* use the tiepoint plus pixelscale otherwise we use a matrix. */
4785 : /* -------------------------------------------------------------------- */
4786 2155 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
4787 718 : && adfGeoTransform[5] < 0.0 )
4788 : {
4789 : double adfPixelScale[3], adfTiePoints[6];
4790 :
4791 717 : adfPixelScale[0] = adfGeoTransform[1];
4792 717 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
4793 717 : adfPixelScale[2] = 0.0;
4794 :
4795 717 : if( !EQUAL(osProfile,"BASELINE") )
4796 712 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
4797 :
4798 717 : adfTiePoints[0] = 0.0;
4799 717 : adfTiePoints[1] = 0.0;
4800 717 : adfTiePoints[2] = 0.0;
4801 717 : adfTiePoints[3] = adfGeoTransform[0];
4802 717 : adfTiePoints[4] = adfGeoTransform[3];
4803 717 : adfTiePoints[5] = 0.0;
4804 :
4805 717 : if( bPixelIsPoint && !bPointGeoIgnore )
4806 : {
4807 0 : adfTiePoints[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
4808 0 : adfTiePoints[4] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
4809 : }
4810 :
4811 717 : if( !EQUAL(osProfile,"BASELINE") )
4812 712 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
4813 : }
4814 : else
4815 : {
4816 : double adfMatrix[16];
4817 :
4818 3 : memset(adfMatrix,0,sizeof(double) * 16);
4819 :
4820 3 : adfMatrix[0] = adfGeoTransform[1];
4821 3 : adfMatrix[1] = adfGeoTransform[2];
4822 3 : adfMatrix[3] = adfGeoTransform[0];
4823 3 : adfMatrix[4] = adfGeoTransform[4];
4824 3 : adfMatrix[5] = adfGeoTransform[5];
4825 3 : adfMatrix[7] = adfGeoTransform[3];
4826 3 : adfMatrix[15] = 1.0;
4827 :
4828 3 : if( bPixelIsPoint && !bPointGeoIgnore )
4829 : {
4830 0 : adfMatrix[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
4831 0 : adfMatrix[7] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
4832 : }
4833 :
4834 3 : if( !EQUAL(osProfile,"BASELINE") )
4835 3 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
4836 : }
4837 :
4838 : // Do we need a world file?
4839 720 : if( CSLFetchBoolean( papszCreationOptions, "TFW", FALSE ) )
4840 2 : GDALWriteWorldFile( osFilename, "tfw", adfGeoTransform );
4841 718 : else if( CSLFetchBoolean( papszCreationOptions, "WORLDFILE", FALSE ) )
4842 2 : GDALWriteWorldFile( osFilename, "wld", adfGeoTransform );
4843 : }
4844 287 : else if( GetGCPCount() > 0 )
4845 : {
4846 : double *padfTiePoints;
4847 : int iGCP;
4848 :
4849 2 : bNeedsRewrite = TRUE;
4850 :
4851 : padfTiePoints = (double *)
4852 2 : CPLMalloc( 6 * sizeof(double) * GetGCPCount() );
4853 :
4854 14 : for( iGCP = 0; iGCP < GetGCPCount(); iGCP++ )
4855 : {
4856 :
4857 12 : padfTiePoints[iGCP*6+0] = pasGCPList[iGCP].dfGCPPixel;
4858 12 : padfTiePoints[iGCP*6+1] = pasGCPList[iGCP].dfGCPLine;
4859 12 : padfTiePoints[iGCP*6+2] = 0;
4860 12 : padfTiePoints[iGCP*6+3] = pasGCPList[iGCP].dfGCPX;
4861 12 : padfTiePoints[iGCP*6+4] = pasGCPList[iGCP].dfGCPY;
4862 12 : padfTiePoints[iGCP*6+5] = pasGCPList[iGCP].dfGCPZ;
4863 :
4864 12 : if( bPixelIsPoint && !bPointGeoIgnore )
4865 : {
4866 0 : padfTiePoints[iGCP*6+0] += 0.5;
4867 0 : padfTiePoints[iGCP*6+1] += 0.5;
4868 : }
4869 : }
4870 :
4871 2 : if( !EQUAL(osProfile,"BASELINE") )
4872 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
4873 2 : 6 * GetGCPCount(), padfTiePoints );
4874 2 : CPLFree( padfTiePoints );
4875 : }
4876 :
4877 : /* -------------------------------------------------------------------- */
4878 : /* Write out projection definition. */
4879 : /* -------------------------------------------------------------------- */
4880 1007 : if( pszProjection != NULL && !EQUAL( pszProjection, "" )
4881 : && !EQUAL(osProfile,"BASELINE") )
4882 : {
4883 : GTIF *psGTIF;
4884 :
4885 762 : bNeedsRewrite = TRUE;
4886 :
4887 : // If we have existing geokeys, try to wipe them
4888 : // by writing a dummy geokey directory. (#2546)
4889 762 : GTiffWriteDummyGeokeyDirectory(hTIFF);
4890 :
4891 762 : psGTIF = GTIFNew( hTIFF );
4892 :
4893 : // set according to coordinate system.
4894 762 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
4895 :
4896 762 : if( bPixelIsPoint )
4897 : {
4898 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
4899 4 : RasterPixelIsPoint);
4900 : }
4901 :
4902 762 : GTIFWriteKeys( psGTIF );
4903 762 : GTIFFree( psGTIF );
4904 : }
4905 1007 : }
4906 :
4907 : /************************************************************************/
4908 : /* AppendMetadataItem() */
4909 : /************************************************************************/
4910 :
4911 312 : static void AppendMetadataItem( CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
4912 : const char *pszKey, const char *pszValue,
4913 : int nBand, const char *pszRole,
4914 : const char *pszDomain )
4915 :
4916 : {
4917 : char szBandId[32];
4918 : CPLXMLNode *psItem;
4919 :
4920 : /* -------------------------------------------------------------------- */
4921 : /* Create the Item element, and subcomponents. */
4922 : /* -------------------------------------------------------------------- */
4923 312 : psItem = CPLCreateXMLNode( NULL, CXT_Element, "Item" );
4924 : CPLCreateXMLNode( CPLCreateXMLNode( psItem, CXT_Attribute, "name"),
4925 312 : CXT_Text, pszKey );
4926 :
4927 312 : if( nBand > 0 )
4928 : {
4929 88 : sprintf( szBandId, "%d", nBand - 1 );
4930 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"sample"),
4931 88 : CXT_Text, szBandId );
4932 : }
4933 :
4934 312 : if( pszRole != NULL )
4935 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"role"),
4936 22 : CXT_Text, pszRole );
4937 :
4938 312 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
4939 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"domain"),
4940 7 : CXT_Text, pszDomain );
4941 :
4942 312 : char *pszEscapedItemValue = CPLEscapeString(pszValue,-1,CPLES_XML);
4943 312 : CPLCreateXMLNode( psItem, CXT_Text, pszEscapedItemValue );
4944 312 : CPLFree( pszEscapedItemValue );
4945 :
4946 : /* -------------------------------------------------------------------- */
4947 : /* Create root, if missing. */
4948 : /* -------------------------------------------------------------------- */
4949 312 : if( *ppsRoot == NULL )
4950 82 : *ppsRoot = CPLCreateXMLNode( NULL, CXT_Element, "GDALMetadata" );
4951 :
4952 : /* -------------------------------------------------------------------- */
4953 : /* Append item to tail. We keep track of the tail to avoid */
4954 : /* O(nsquared) time as the list gets longer. */
4955 : /* -------------------------------------------------------------------- */
4956 312 : if( *ppsTail == NULL )
4957 82 : CPLAddXMLChild( *ppsRoot, psItem );
4958 : else
4959 230 : CPLAddXMLSibling( *ppsTail, psItem );
4960 :
4961 312 : *ppsTail = psItem;
4962 312 : }
4963 :
4964 : /************************************************************************/
4965 : /* WriteMDMDMetadata() */
4966 : /************************************************************************/
4967 :
4968 133496 : static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
4969 : CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
4970 : int nBand, const char *pszProfile )
4971 :
4972 : {
4973 : int iDomain;
4974 : char **papszDomainList;
4975 :
4976 : (void) pszProfile;
4977 :
4978 : /* ==================================================================== */
4979 : /* Process each domain. */
4980 : /* ==================================================================== */
4981 133496 : papszDomainList = poMDMD->GetDomainList();
4982 134075 : for( iDomain = 0; papszDomainList && papszDomainList[iDomain]; iDomain++ )
4983 : {
4984 579 : char **papszMD = poMDMD->GetMetadata( papszDomainList[iDomain] );
4985 : int iItem;
4986 579 : int bIsXML = FALSE;
4987 :
4988 579 : if( EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") )
4989 62 : continue; // ignored
4990 517 : if( EQUAL(papszDomainList[iDomain], "RPC") )
4991 0 : continue; // handled elsewhere
4992 517 : if( EQUAL(papszDomainList[iDomain], "xml:ESRI")
4993 : && CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
4994 1 : continue; // handled elsewhere
4995 :
4996 516 : if( EQUALN(papszDomainList[iDomain], "xml:",4 ) )
4997 2 : bIsXML = TRUE;
4998 :
4999 : /* -------------------------------------------------------------------- */
5000 : /* Process each item in this domain. */
5001 : /* -------------------------------------------------------------------- */
5002 1241 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
5003 : {
5004 : const char *pszItemValue;
5005 725 : char *pszItemName = NULL;
5006 :
5007 725 : if( bIsXML )
5008 : {
5009 2 : pszItemName = CPLStrdup("doc");
5010 2 : pszItemValue = papszMD[iItem];
5011 : }
5012 : else
5013 : {
5014 723 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
5015 723 : if( pszItemName == NULL )
5016 : {
5017 1 : CPLDebug("GTiff", "Invalid metadata item : %s", papszMD[iItem]);
5018 1 : continue;
5019 : }
5020 : }
5021 :
5022 : /* -------------------------------------------------------------------- */
5023 : /* Convert into XML item or handle as a special TIFF tag. */
5024 : /* -------------------------------------------------------------------- */
5025 753 : if( strlen(papszDomainList[iDomain]) == 0
5026 : && nBand == 0 && EQUALN(pszItemName,"TIFFTAG_",8) )
5027 : {
5028 29 : if( EQUAL(pszItemName,"TIFFTAG_DOCUMENTNAME") )
5029 4 : TIFFSetField( hTIFF, TIFFTAG_DOCUMENTNAME, pszItemValue );
5030 25 : else if( EQUAL(pszItemName,"TIFFTAG_IMAGEDESCRIPTION") )
5031 1 : TIFFSetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, pszItemValue );
5032 24 : else if( EQUAL(pszItemName,"TIFFTAG_SOFTWARE") )
5033 2 : TIFFSetField( hTIFF, TIFFTAG_SOFTWARE, pszItemValue );
5034 22 : else if( EQUAL(pszItemName,"TIFFTAG_DATETIME") )
5035 1 : TIFFSetField( hTIFF, TIFFTAG_DATETIME, pszItemValue );
5036 21 : else if( EQUAL(pszItemName,"TIFFTAG_ARTIST") )
5037 1 : TIFFSetField( hTIFF, TIFFTAG_ARTIST, pszItemValue );
5038 20 : else if( EQUAL(pszItemName,"TIFFTAG_HOSTCOMPUTER") )
5039 1 : TIFFSetField( hTIFF, TIFFTAG_HOSTCOMPUTER, pszItemValue );
5040 19 : else if( EQUAL(pszItemName,"TIFFTAG_COPYRIGHT") )
5041 1 : TIFFSetField( hTIFF, TIFFTAG_COPYRIGHT, pszItemValue );
5042 18 : else if( EQUAL(pszItemName,"TIFFTAG_XRESOLUTION") )
5043 6 : TIFFSetField( hTIFF, TIFFTAG_XRESOLUTION, CPLAtof(pszItemValue) );
5044 12 : else if( EQUAL(pszItemName,"TIFFTAG_YRESOLUTION") )
5045 6 : TIFFSetField( hTIFF, TIFFTAG_YRESOLUTION, CPLAtof(pszItemValue) );
5046 6 : else if( EQUAL(pszItemName,"TIFFTAG_RESOLUTIONUNIT") )
5047 6 : TIFFSetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, atoi(pszItemValue) );
5048 0 : else if( EQUAL(pszItemName,"TIFFTAG_MINSAMPLEVALUE") )
5049 0 : TIFFSetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, atoi(pszItemValue) );
5050 0 : else if( EQUAL(pszItemName,"TIFFTAG_MAXSAMPLEVALUE") )
5051 0 : TIFFSetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, atoi(pszItemValue) );
5052 : else
5053 : CPLError(CE_Warning, CPLE_NotSupported,
5054 : "%s metadata item is unhandled and will not be written",
5055 0 : pszItemName);
5056 : }
5057 695 : else if( nBand == 0 && EQUAL(pszItemName,GDALMD_AREA_OR_POINT) )
5058 : /* do nothing, handled elsewhere */;
5059 : else
5060 : AppendMetadataItem( ppsRoot, ppsTail,
5061 : pszItemName, pszItemValue,
5062 290 : nBand, NULL, papszDomainList[iDomain] );
5063 :
5064 724 : CPLFree( pszItemName );
5065 : }
5066 : }
5067 133496 : }
5068 :
5069 : /************************************************************************/
5070 : /* WriteMetadata() */
5071 : /************************************************************************/
5072 :
5073 1234 : int GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
5074 : int bSrcIsGeoTIFF,
5075 : const char *pszProfile,
5076 : const char *pszTIFFFilename,
5077 : char **papszCreationOptions,
5078 : int bExcludeRPBandIMGFileWriting)
5079 :
5080 : {
5081 : /* -------------------------------------------------------------------- */
5082 : /* Convert all the remaining metadata into a simple XML */
5083 : /* format. */
5084 : /* -------------------------------------------------------------------- */
5085 1234 : CPLXMLNode *psRoot = NULL, *psTail = NULL;
5086 :
5087 1234 : if( bSrcIsGeoTIFF )
5088 : {
5089 : WriteMDMetadata( &(((GTiffDataset *)poSrcDS)->oGTiffMDMD),
5090 1002 : hTIFF, &psRoot, &psTail, 0, pszProfile );
5091 : }
5092 : else
5093 : {
5094 232 : char **papszMD = poSrcDS->GetMetadata();
5095 :
5096 232 : if( CSLCount(papszMD) > 0 )
5097 : {
5098 156 : GDALMultiDomainMetadata oMDMD;
5099 156 : oMDMD.SetMetadata( papszMD );
5100 :
5101 156 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, 0, pszProfile );
5102 : }
5103 : }
5104 :
5105 : /* -------------------------------------------------------------------- */
5106 : /* Handle RPC data written to an RPB file. */
5107 : /* -------------------------------------------------------------------- */
5108 1234 : char **papszRPCMD = poSrcDS->GetMetadata("RPC");
5109 1234 : if( papszRPCMD != NULL && !bExcludeRPBandIMGFileWriting )
5110 : {
5111 4 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
5112 2 : WriteRPCTag( hTIFF, papszRPCMD );
5113 :
5114 4 : if( !EQUAL(pszProfile,"GDALGeoTIFF")
5115 : || CSLFetchBoolean( papszCreationOptions, "RPB", FALSE ) )
5116 : {
5117 2 : GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
5118 : }
5119 : }
5120 :
5121 : /* -------------------------------------------------------------------- */
5122 : /* Handle metadata data written to an IMD file. */
5123 : /* -------------------------------------------------------------------- */
5124 1234 : char **papszIMDMD = poSrcDS->GetMetadata("IMD");
5125 1234 : if( papszIMDMD != NULL && !bExcludeRPBandIMGFileWriting)
5126 : {
5127 4 : GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
5128 : }
5129 :
5130 : /* -------------------------------------------------------------------- */
5131 : /* We also need to address band specific metadata, and special */
5132 : /* "role" metadata. */
5133 : /* -------------------------------------------------------------------- */
5134 : int nBand;
5135 133910 : for( nBand = 1; nBand <= poSrcDS->GetRasterCount(); nBand++ )
5136 : {
5137 132676 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( nBand );
5138 :
5139 132676 : if( bSrcIsGeoTIFF )
5140 : {
5141 : WriteMDMetadata( &(((GTiffRasterBand *)poBand)->oGTiffMDMD),
5142 132311 : hTIFF, &psRoot, &psTail, nBand, pszProfile );
5143 : }
5144 : else
5145 : {
5146 365 : char **papszMD = poBand->GetMetadata();
5147 :
5148 365 : if( CSLCount(papszMD) > 0 )
5149 : {
5150 27 : GDALMultiDomainMetadata oMDMD;
5151 27 : oMDMD.SetMetadata( papszMD );
5152 :
5153 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, nBand,
5154 27 : pszProfile );
5155 : }
5156 : }
5157 :
5158 132676 : double dfOffset = poBand->GetOffset();
5159 132676 : double dfScale = poBand->GetScale();
5160 :
5161 132676 : if( dfOffset != 0.0 || dfScale != 1.0 )
5162 : {
5163 : char szValue[128];
5164 :
5165 6 : sprintf( szValue, "%.18g", dfOffset );
5166 : AppendMetadataItem( &psRoot, &psTail, "OFFSET", szValue, nBand,
5167 6 : "offset", "" );
5168 6 : sprintf( szValue, "%.18g", dfScale );
5169 : AppendMetadataItem( &psRoot, &psTail, "SCALE", szValue, nBand,
5170 6 : "scale", "" );
5171 : }
5172 :
5173 132676 : const char* pszUnitType = poBand->GetUnitType();
5174 132676 : if (pszUnitType != NULL && pszUnitType[0] != '\0')
5175 : AppendMetadataItem( &psRoot, &psTail, "UNITTYPE", pszUnitType, nBand,
5176 7 : "unittype", "" );
5177 :
5178 :
5179 132676 : if (strlen(poBand->GetDescription()) > 0)
5180 : {
5181 : AppendMetadataItem( &psRoot, &psTail, "DESCRIPTION",
5182 3 : poBand->GetDescription(), nBand,
5183 6 : "description", "" );
5184 : }
5185 : }
5186 :
5187 : /* -------------------------------------------------------------------- */
5188 : /* Write out the generic XML metadata if there is any. */
5189 : /* -------------------------------------------------------------------- */
5190 1234 : if( psRoot != NULL )
5191 : {
5192 82 : int bRet = TRUE;
5193 :
5194 82 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
5195 : {
5196 72 : char *pszXML_MD = CPLSerializeXMLTree( psRoot );
5197 72 : if( strlen(pszXML_MD) > 32000 )
5198 : {
5199 1 : if( bSrcIsGeoTIFF )
5200 1 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
5201 : else
5202 0 : bRet = FALSE;
5203 : CPLError( CE_Warning, CPLE_AppDefined,
5204 1 : "Lost metadata writing to GeoTIFF ... too large to fit in tag." );
5205 : }
5206 : else
5207 : {
5208 71 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszXML_MD );
5209 : }
5210 72 : CPLFree( pszXML_MD );
5211 : }
5212 : else
5213 : {
5214 10 : if( bSrcIsGeoTIFF )
5215 6 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
5216 : else
5217 4 : bRet = FALSE;
5218 : }
5219 :
5220 82 : CPLDestroyXMLNode( psRoot );
5221 :
5222 82 : return bRet;
5223 : }
5224 : else
5225 : {
5226 : /* If we have no more metadata but it existed before, remove the GDAL_METADATA tag */
5227 1152 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
5228 : {
5229 1146 : char* pszText = NULL;
5230 1146 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
5231 : {
5232 : #ifdef HAVE_UNSETFIELD
5233 2 : TIFFUnsetField( hTIFF, TIFFTAG_GDAL_METADATA );
5234 : #else
5235 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, "" );
5236 : #endif
5237 : }
5238 : }
5239 : }
5240 :
5241 1152 : return TRUE;
5242 : }
5243 :
5244 : /************************************************************************/
5245 : /* PushMetadataToPam() */
5246 : /* */
5247 : /* When producing a strict profile TIFF or if our aggregate */
5248 : /* metadata is too big for a single tiff tag we may end up */
5249 : /* needing to write it via the PAM mechanisms. This method */
5250 : /* copies all the appropriate metadata into the PAM level */
5251 : /* metadata object but with special care to avoid copying */
5252 : /* metadata handled in other ways in TIFF format. */
5253 : /************************************************************************/
5254 :
5255 38 : void GTiffDataset::PushMetadataToPam()
5256 :
5257 : {
5258 : int nBand;
5259 126 : for( nBand = 0; nBand <= GetRasterCount(); nBand++ )
5260 : {
5261 : GDALMultiDomainMetadata *poSrcMDMD;
5262 88 : GTiffRasterBand *poBand = NULL;
5263 :
5264 88 : if( nBand == 0 )
5265 38 : poSrcMDMD = &(this->oGTiffMDMD);
5266 : else
5267 : {
5268 50 : poBand = (GTiffRasterBand *) GetRasterBand(nBand);
5269 50 : poSrcMDMD = &(poBand->oGTiffMDMD);
5270 : }
5271 :
5272 : /* -------------------------------------------------------------------- */
5273 : /* Loop over the available domains. */
5274 : /* -------------------------------------------------------------------- */
5275 : int iDomain, i;
5276 : char **papszDomainList;
5277 :
5278 88 : papszDomainList = poSrcMDMD->GetDomainList();
5279 379 : for( iDomain = 0;
5280 185 : papszDomainList && papszDomainList[iDomain];
5281 : iDomain++ )
5282 : {
5283 106 : char **papszMD = poSrcMDMD->GetMetadata( papszDomainList[iDomain] );
5284 :
5285 424 : if( EQUAL(papszDomainList[iDomain],"RPC")
5286 106 : || EQUAL(papszDomainList[iDomain],"IMD")
5287 106 : || EQUAL(papszDomainList[iDomain],"_temporary_")
5288 106 : || EQUAL(papszDomainList[iDomain],"IMAGE_STRUCTURE") )
5289 41 : continue;
5290 :
5291 65 : papszMD = CSLDuplicate(papszMD);
5292 :
5293 228 : for( i = CSLCount(papszMD)-1; i >= 0; i-- )
5294 : {
5295 320 : if( EQUALN(papszMD[i],"TIFFTAG_",8)
5296 157 : || EQUALN(papszMD[i],GDALMD_AREA_OR_POINT,
5297 : strlen(GDALMD_AREA_OR_POINT)) )
5298 27 : papszMD = CSLRemoveStrings( papszMD, i, 1, NULL );
5299 : }
5300 :
5301 65 : if( nBand == 0 )
5302 28 : GDALPamDataset::SetMetadata( papszMD, papszDomainList[iDomain]);
5303 : else
5304 37 : poBand->GDALPamRasterBand::SetMetadata( papszMD, papszDomainList[iDomain]);
5305 :
5306 65 : CSLDestroy( papszMD );
5307 : }
5308 :
5309 : /* -------------------------------------------------------------------- */
5310 : /* Handle some "special domain" stuff. */
5311 : /* -------------------------------------------------------------------- */
5312 88 : if( poBand != NULL )
5313 : {
5314 50 : poBand->GDALPamRasterBand::SetOffset( poBand->GetOffset() );
5315 50 : poBand->GDALPamRasterBand::SetScale( poBand->GetScale() );
5316 50 : poBand->GDALPamRasterBand::SetUnitType( poBand->GetUnitType() );
5317 50 : poBand->GDALPamRasterBand::SetDescription( poBand->GetDescription() );
5318 : }
5319 : }
5320 38 : }
5321 :
5322 : /************************************************************************/
5323 : /* WriteRPCTag() */
5324 : /* */
5325 : /* Format a TAG according to: */
5326 : /* */
5327 : /* http://geotiff.maptools.org/rpc_prop.html */
5328 : /************************************************************************/
5329 :
5330 : /* static */
5331 2 : void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
5332 :
5333 : {
5334 : double adfRPCTag[92];
5335 : GDALRPCInfo sRPC;
5336 :
5337 2 : if( !GDALExtractRPCInfo( papszRPCMD, &sRPC ) )
5338 0 : return;
5339 :
5340 2 : adfRPCTag[0] = -1.0; // Error Bias
5341 2 : adfRPCTag[1] = -1.0; // Error Random
5342 :
5343 2 : adfRPCTag[2] = sRPC.dfLINE_OFF;
5344 2 : adfRPCTag[3] = sRPC.dfSAMP_OFF;
5345 2 : adfRPCTag[4] = sRPC.dfLAT_OFF;
5346 2 : adfRPCTag[5] = sRPC.dfLONG_OFF;
5347 2 : adfRPCTag[6] = sRPC.dfHEIGHT_OFF;
5348 2 : adfRPCTag[7] = sRPC.dfLINE_SCALE;
5349 2 : adfRPCTag[8] = sRPC.dfSAMP_SCALE;
5350 2 : adfRPCTag[9] = sRPC.dfLAT_SCALE;
5351 2 : adfRPCTag[10] = sRPC.dfLONG_SCALE;
5352 2 : adfRPCTag[11] = sRPC.dfHEIGHT_SCALE;
5353 :
5354 2 : memcpy( adfRPCTag + 12, sRPC.adfLINE_NUM_COEFF, sizeof(double) * 20 );
5355 2 : memcpy( adfRPCTag + 32, sRPC.adfLINE_DEN_COEFF, sizeof(double) * 20 );
5356 2 : memcpy( adfRPCTag + 52, sRPC.adfSAMP_NUM_COEFF, sizeof(double) * 20 );
5357 2 : memcpy( adfRPCTag + 72, sRPC.adfSAMP_DEN_COEFF, sizeof(double) * 20 );
5358 :
5359 2 : TIFFSetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, 92, adfRPCTag );
5360 : }
5361 :
5362 : /************************************************************************/
5363 : /* ReadRPCTag() */
5364 : /* */
5365 : /* Format a TAG according to: */
5366 : /* */
5367 : /* http://geotiff.maptools.org/rpc_prop.html */
5368 : /************************************************************************/
5369 :
5370 2259 : void GTiffDataset::ReadRPCTag()
5371 :
5372 : {
5373 : double *padfRPCTag;
5374 2259 : char **papszMD = NULL;
5375 2259 : CPLString osField;
5376 2259 : CPLString osMultiField;
5377 : int i;
5378 : uint16 nCount;
5379 :
5380 2259 : if( !TIFFGetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag )
5381 : || nCount != 92 )
5382 : return;
5383 :
5384 6 : osField.Printf( "%.15g", padfRPCTag[2] );
5385 6 : papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
5386 :
5387 6 : osField.Printf( "%.15g", padfRPCTag[3] );
5388 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
5389 :
5390 6 : osField.Printf( "%.15g", padfRPCTag[4] );
5391 6 : papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
5392 :
5393 6 : osField.Printf( "%.15g", padfRPCTag[5] );
5394 6 : papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
5395 :
5396 6 : osField.Printf( "%.15g", padfRPCTag[6] );
5397 6 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
5398 :
5399 6 : osField.Printf( "%.15g", padfRPCTag[7] );
5400 6 : papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
5401 :
5402 6 : osField.Printf( "%.15g", padfRPCTag[8] );
5403 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
5404 :
5405 6 : osField.Printf( "%.15g", padfRPCTag[9] );
5406 6 : papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
5407 :
5408 6 : osField.Printf( "%.15g", padfRPCTag[10] );
5409 6 : papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
5410 :
5411 6 : osField.Printf( "%.15g", padfRPCTag[11] );
5412 6 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
5413 :
5414 126 : for( i = 0; i < 20; i++ )
5415 : {
5416 120 : osField.Printf( "%.15g", padfRPCTag[12+i] );
5417 120 : if( i > 0 )
5418 114 : osMultiField += " ";
5419 : else
5420 6 : osMultiField = "";
5421 120 : osMultiField += osField;
5422 : }
5423 6 : papszMD = CSLSetNameValue( papszMD, "LINE_NUM_COEFF", osMultiField );
5424 :
5425 126 : for( i = 0; i < 20; i++ )
5426 : {
5427 120 : osField.Printf( "%.15g", padfRPCTag[32+i] );
5428 120 : if( i > 0 )
5429 114 : osMultiField += " ";
5430 : else
5431 6 : osMultiField = "";
5432 120 : osMultiField += osField;
5433 : }
5434 6 : papszMD = CSLSetNameValue( papszMD, "LINE_DEN_COEFF", osMultiField );
5435 :
5436 126 : for( i = 0; i < 20; i++ )
5437 : {
5438 120 : osField.Printf( "%.15g", padfRPCTag[52+i] );
5439 120 : if( i > 0 )
5440 114 : osMultiField += " ";
5441 : else
5442 6 : osMultiField = "";
5443 120 : osMultiField += osField;
5444 : }
5445 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_NUM_COEFF", osMultiField );
5446 :
5447 126 : for( i = 0; i < 20; i++ )
5448 : {
5449 120 : osField.Printf( "%.15g", padfRPCTag[72+i] );
5450 120 : if( i > 0 )
5451 114 : osMultiField += " ";
5452 : else
5453 6 : osMultiField = "";
5454 120 : osMultiField += osField;
5455 : }
5456 6 : papszMD = CSLSetNameValue( papszMD, "SAMP_DEN_COEFF", osMultiField );
5457 :
5458 6 : oGTiffMDMD.SetMetadata( papszMD, "RPC" );
5459 6 : CSLDestroy( papszMD );
5460 : }
5461 :
5462 : /************************************************************************/
5463 : /* WriteNoDataValue() */
5464 : /************************************************************************/
5465 :
5466 81 : void GTiffDataset::WriteNoDataValue( TIFF *hTIFF, double dfNoData )
5467 :
5468 : {
5469 : char szVal[400];
5470 81 : if (CPLIsNan(dfNoData))
5471 3 : strcpy(szVal, "nan");
5472 : else
5473 78 : snprintf(szVal, sizeof(szVal), "%.18g", dfNoData);
5474 81 : TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, szVal );
5475 81 : }
5476 :
5477 : /************************************************************************/
5478 : /* SetDirectory() */
5479 : /************************************************************************/
5480 :
5481 230031 : int GTiffDataset::SetDirectory( toff_t nNewOffset )
5482 :
5483 : {
5484 230031 : Crystalize();
5485 :
5486 230031 : FlushBlockBuf();
5487 :
5488 230031 : if( nNewOffset == 0 )
5489 225729 : nNewOffset = nDirOffset;
5490 :
5491 230031 : if( TIFFCurrentDirOffset(hTIFF) == nNewOffset )
5492 : {
5493 228460 : CPLAssert( *ppoActiveDSRef == this || *ppoActiveDSRef == NULL );
5494 228460 : *ppoActiveDSRef = this;
5495 228460 : return TRUE;
5496 : }
5497 :
5498 1571 : if( GetAccess() == GA_Update )
5499 : {
5500 1273 : if( *ppoActiveDSRef != NULL )
5501 1147 : (*ppoActiveDSRef)->FlushDirectory();
5502 : }
5503 :
5504 1571 : if( nNewOffset == 0)
5505 0 : return TRUE;
5506 :
5507 1571 : (*ppoActiveDSRef) = this;
5508 :
5509 1571 : int nSetDirResult = TIFFSetSubDirectory( hTIFF, nNewOffset );
5510 1571 : if (!nSetDirResult)
5511 0 : return nSetDirResult;
5512 :
5513 : /* -------------------------------------------------------------------- */
5514 : /* YCbCr JPEG compressed images should be translated on the fly */
5515 : /* to RGB by libtiff/libjpeg unless specifically requested */
5516 : /* otherwise. */
5517 : /* -------------------------------------------------------------------- */
5518 1571 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
5519 0 : nCompression = COMPRESSION_NONE;
5520 :
5521 1571 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
5522 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
5523 :
5524 1571 : if( nCompression == COMPRESSION_JPEG
5525 : && nPhotometric == PHOTOMETRIC_YCBCR
5526 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
5527 : "YES") ) )
5528 : {
5529 : int nColorMode;
5530 :
5531 216 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
5532 216 : if( nColorMode != JPEGCOLORMODE_RGB )
5533 216 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
5534 : }
5535 :
5536 : /* -------------------------------------------------------------------- */
5537 : /* Propogate any quality settings. */
5538 : /* -------------------------------------------------------------------- */
5539 1571 : if( GetAccess() == GA_Update )
5540 : {
5541 : // Now, reset zip and jpeg quality.
5542 1273 : if(nJpegQuality > 0 && nCompression == COMPRESSION_JPEG)
5543 : {
5544 : CPLDebug( "GTiff", "Propgate JPEG_QUALITY(%d) in SetDirectory()",
5545 134 : nJpegQuality );
5546 134 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality);
5547 : }
5548 1273 : if(nZLevel > 0 && nCompression == COMPRESSION_ADOBE_DEFLATE)
5549 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, nZLevel);
5550 1273 : if(nLZMAPreset > 0 && nCompression == COMPRESSION_LZMA)
5551 0 : TIFFSetField(hTIFF, TIFFTAG_LZMAPRESET, nLZMAPreset);
5552 : }
5553 :
5554 1571 : return nSetDirResult;
5555 : }
5556 :
5557 : /************************************************************************/
5558 : /* Identify() */
5559 : /************************************************************************/
5560 :
5561 19430 : int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
5562 :
5563 : {
5564 19430 : const char *pszFilename = poOpenInfo->pszFilename;
5565 19430 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
5566 : {
5567 238 : pszFilename += strlen("GTIFF_RAW:");
5568 238 : GDALOpenInfo oOpenInfo( pszFilename, poOpenInfo->eAccess );
5569 238 : return Identify(&oOpenInfo);
5570 : }
5571 :
5572 : /* -------------------------------------------------------------------- */
5573 : /* We have a special hook for handling opening a specific */
5574 : /* directory of a TIFF file. */
5575 : /* -------------------------------------------------------------------- */
5576 19192 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
5577 6 : return TRUE;
5578 :
5579 : /* -------------------------------------------------------------------- */
5580 : /* First we check to see if the file has the expected header */
5581 : /* bytes. */
5582 : /* -------------------------------------------------------------------- */
5583 19186 : if( poOpenInfo->nHeaderBytes < 2 )
5584 11870 : return FALSE;
5585 :
5586 10835 : if( (poOpenInfo->pabyHeader[0] != 'I' || poOpenInfo->pabyHeader[1] != 'I')
5587 3519 : && (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
5588 3364 : return FALSE;
5589 :
5590 : #ifndef BIGTIFF_SUPPORT
5591 : if( (poOpenInfo->pabyHeader[2] == 0x2B && poOpenInfo->pabyHeader[3] == 0) ||
5592 : (poOpenInfo->pabyHeader[2] == 0 && poOpenInfo->pabyHeader[3] == 0x2B) )
5593 : {
5594 : CPLError( CE_Failure, CPLE_OpenFailed,
5595 : "This is a BigTIFF file. BigTIFF is not supported by this\n"
5596 : "version of GDAL and libtiff." );
5597 : return FALSE;
5598 : }
5599 : #endif
5600 :
5601 4227 : if( (poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0)
5602 181 : && (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0)
5603 78 : && (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0)
5604 16 : && (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
5605 0 : return FALSE;
5606 :
5607 3952 : return TRUE;
5608 : }
5609 :
5610 : /************************************************************************/
5611 : /* Open() */
5612 : /************************************************************************/
5613 :
5614 8828 : GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
5615 :
5616 : {
5617 : TIFF *hTIFF;
5618 8828 : int bAllowRGBAInterface = TRUE;
5619 8828 : const char *pszFilename = poOpenInfo->pszFilename;
5620 :
5621 : /* -------------------------------------------------------------------- */
5622 : /* Check if it looks like a TIFF file. */
5623 : /* -------------------------------------------------------------------- */
5624 8828 : if (!Identify(poOpenInfo))
5625 4912 : return NULL;
5626 :
5627 3916 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
5628 : {
5629 238 : bAllowRGBAInterface = FALSE;
5630 238 : pszFilename += strlen("GTIFF_RAW:");
5631 : }
5632 :
5633 : /* -------------------------------------------------------------------- */
5634 : /* We have a special hook for handling opening a specific */
5635 : /* directory of a TIFF file. */
5636 : /* -------------------------------------------------------------------- */
5637 3916 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
5638 6 : return OpenDir( poOpenInfo );
5639 :
5640 3910 : if (!GTiffOneTimeInit())
5641 0 : return NULL;
5642 :
5643 : /* -------------------------------------------------------------------- */
5644 : /* Try opening the dataset. */
5645 : /* -------------------------------------------------------------------- */
5646 :
5647 : /* Disable strip chop for now */
5648 3910 : hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "rc" : "r+c" );
5649 3910 : if( hTIFF == NULL )
5650 0 : return( NULL );
5651 :
5652 : uint32 nXSize, nYSize;
5653 : uint16 nPlanarConfig;
5654 : uint32 nRowsPerStrip;
5655 : uint16 nCompression;
5656 :
5657 3910 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
5658 3910 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
5659 :
5660 3910 : if( nXSize > INT_MAX || nYSize > INT_MAX )
5661 : {
5662 : /* GDAL only supports signed 32bit dimensions */
5663 0 : XTIFFClose( hTIFF );
5664 0 : return( NULL );
5665 : }
5666 :
5667 3910 : if( !TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(nPlanarConfig) ) )
5668 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
5669 :
5670 3910 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
5671 0 : nCompression = COMPRESSION_NONE;
5672 :
5673 3910 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(nRowsPerStrip) ) )
5674 381 : nRowsPerStrip = nYSize;
5675 :
5676 3910 : if (!TIFFIsTiled( hTIFF ) &&
5677 : nCompression == COMPRESSION_NONE &&
5678 : nRowsPerStrip >= nYSize &&
5679 : nPlanarConfig == PLANARCONFIG_CONTIG)
5680 : {
5681 2981 : int bReopenWithStripChop = TRUE;
5682 2981 : if ( nYSize > 128 * 1024 * 1024 )
5683 : {
5684 : uint16 nSamplesPerPixel;
5685 : uint16 nBitsPerSample;
5686 :
5687 1 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel ) )
5688 0 : nSamplesPerPixel = 1;
5689 :
5690 1 : if( !TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)) )
5691 0 : nBitsPerSample = 1;
5692 :
5693 1 : vsi_l_offset nLineSize = (nSamplesPerPixel * (vsi_l_offset)nXSize * nBitsPerSample + 7) / 8;
5694 1 : int nDefaultStripHeight = (int)(8192 / nLineSize);
5695 1 : if (nDefaultStripHeight == 0) nDefaultStripHeight = 1;
5696 1 : vsi_l_offset nStrips = nYSize / nDefaultStripHeight;
5697 :
5698 : /* There is a risk of DoS due to huge amount of memory allocated in ChopUpSingleUncompressedStrip() */
5699 : /* in libtiff */
5700 1 : if (nStrips > 128 * 1024 * 1024 &&
5701 : !CSLTestBoolean(CPLGetConfigOption("GTIFF_FORCE_STRIP_CHOP", "NO")))
5702 : {
5703 : CPLError(CE_Warning, CPLE_AppDefined,
5704 : "Potential denial of service detected. Avoid using strip chop. "
5705 1 : "Set the GTIFF_FORCE_STRIP_CHOP configuration open to go over this test.");
5706 1 : bReopenWithStripChop = FALSE;
5707 : }
5708 : }
5709 :
5710 2981 : if (bReopenWithStripChop)
5711 : {
5712 2980 : CPLDebug("GTiff", "Reopen with strip chop enabled");
5713 2980 : XTIFFClose(hTIFF);
5714 2980 : hTIFF = VSI_TIFFOpen( pszFilename, ( poOpenInfo->eAccess == GA_ReadOnly ) ? "r" : "r+" );
5715 2980 : if( hTIFF == NULL )
5716 0 : return( NULL );
5717 : }
5718 : }
5719 :
5720 : /* -------------------------------------------------------------------- */
5721 : /* Create a corresponding GDALDataset. */
5722 : /* -------------------------------------------------------------------- */
5723 : GTiffDataset *poDS;
5724 :
5725 3910 : poDS = new GTiffDataset();
5726 3910 : poDS->SetDescription( pszFilename );
5727 7820 : poDS->osFilename = pszFilename;
5728 3910 : poDS->poActiveDS = poDS;
5729 :
5730 3910 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
5731 : TIFFCurrentDirOffset(hTIFF), TRUE,
5732 : poOpenInfo->eAccess,
5733 : bAllowRGBAInterface, TRUE,
5734 : poOpenInfo->papszSiblingFiles) != CE_None )
5735 : {
5736 0 : delete poDS;
5737 0 : return NULL;
5738 : }
5739 :
5740 : /* -------------------------------------------------------------------- */
5741 : /* Initialize any PAM information. */
5742 : /* -------------------------------------------------------------------- */
5743 3910 : poDS->TryLoadXML( poOpenInfo->papszSiblingFiles);
5744 3910 : poDS->ApplyPamInfo();
5745 :
5746 : int i;
5747 271143 : for(i=1;i<=poDS->nBands;i++)
5748 : {
5749 267233 : GTiffRasterBand* poBand = (GTiffRasterBand*) poDS->GetRasterBand(i);
5750 :
5751 : /* Load scale, offset and unittype from PAM if available */
5752 267233 : if (!poBand->bHaveOffsetScale)
5753 : {
5754 267225 : poBand->dfScale = poBand->GDALPamRasterBand::GetScale(&poBand->bHaveOffsetScale);
5755 267225 : poBand->dfOffset = poBand->GDALPamRasterBand::GetOffset();
5756 : }
5757 267233 : if (poBand->osUnitType.size() == 0)
5758 : {
5759 267218 : const char* pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
5760 267218 : if (pszUnitType)
5761 267218 : poBand->osUnitType = pszUnitType;
5762 : }
5763 : }
5764 :
5765 3910 : poDS->bMetadataChanged = FALSE;
5766 3910 : poDS->bGeoTIFFInfoChanged = FALSE;
5767 3910 : poDS->bForceUnsetGT = FALSE;
5768 3910 : poDS->bForceUnsetProjection = FALSE;
5769 :
5770 : /* -------------------------------------------------------------------- */
5771 : /* Check for external overviews. */
5772 : /* -------------------------------------------------------------------- */
5773 3910 : poDS->oOvManager.Initialize( poDS, pszFilename, poOpenInfo->papszSiblingFiles );
5774 :
5775 3910 : return poDS;
5776 : }
5777 :
5778 : /************************************************************************/
5779 : /* LoadMDAreaOrPoint() */
5780 : /************************************************************************/
5781 :
5782 : /* This is a light version of LookForProjection(), which saves the */
5783 : /* potential costly cost of GTIFGetOGISDefn(), since we just need to */
5784 : /* access to a raw GeoTIFF key, and not build the full projection object. */
5785 :
5786 4738 : void GTiffDataset::LoadMDAreaOrPoint()
5787 : {
5788 4738 : if( bLookedForProjection || bLookedForMDAreaOrPoint ||
5789 : oGTiffMDMD.GetMetadataItem( GDALMD_AREA_OR_POINT ) != NULL )
5790 4538 : return;
5791 :
5792 200 : bLookedForMDAreaOrPoint = TRUE;
5793 :
5794 200 : if (!SetDirectory())
5795 0 : return;
5796 :
5797 200 : GTIF* hGTIF = GTIFNew(hTIFF);
5798 :
5799 200 : if ( !hGTIF )
5800 : {
5801 : CPLError( CE_Warning, CPLE_AppDefined,
5802 0 : "GeoTIFF tags apparently corrupt, they are being ignored." );
5803 : }
5804 : else
5805 : {
5806 : // Is this a pixel-is-point dataset?
5807 : short nRasterType;
5808 :
5809 200 : if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
5810 : 0, 1 ) == 1 )
5811 : {
5812 89 : if( nRasterType == (short) RasterPixelIsPoint )
5813 8 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
5814 : else
5815 81 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
5816 : }
5817 :
5818 200 : GTIFFree( hGTIF );
5819 : }
5820 : }
5821 :
5822 : /************************************************************************/
5823 : /* LookForProjection() */
5824 : /************************************************************************/
5825 :
5826 4667 : void GTiffDataset::LookForProjection()
5827 :
5828 : {
5829 4667 : if( bLookedForProjection )
5830 3649 : return;
5831 :
5832 1018 : bLookedForProjection = TRUE;
5833 1018 : if (!SetDirectory())
5834 0 : return;
5835 :
5836 : /* -------------------------------------------------------------------- */
5837 : /* Capture the GeoTIFF projection, if available. */
5838 : /* -------------------------------------------------------------------- */
5839 : GTIF *hGTIF;
5840 :
5841 1018 : CPLFree( pszProjection );
5842 1018 : pszProjection = NULL;
5843 :
5844 1018 : hGTIF = GTIFNew(hTIFF);
5845 :
5846 1018 : if ( !hGTIF )
5847 : {
5848 : CPLError( CE_Warning, CPLE_AppDefined,
5849 0 : "GeoTIFF tags apparently corrupt, they are being ignored." );
5850 : }
5851 : else
5852 : {
5853 : GTIFDefn *psGTIFDefn;
5854 :
5855 : #if LIBGEOTIFF_VERSION >= 1410
5856 : psGTIFDefn = GTIFAllocDefn();
5857 : #else
5858 1018 : psGTIFDefn = (GTIFDefn *) CPLCalloc(1,sizeof(GTIFDefn));
5859 : #endif
5860 :
5861 1018 : if( GTIFGetDefn( hGTIF, psGTIFDefn ) )
5862 : {
5863 970 : pszProjection = GTIFGetOGISDefn( hGTIF, psGTIFDefn );
5864 :
5865 : // Should we simplify away vertical CS stuff?
5866 970 : if( EQUALN(pszProjection,"COMPD_CS",8)
5867 : && !CSLTestBoolean( CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
5868 : "NO") ) )
5869 : {
5870 1 : OGRSpatialReference oSRS;
5871 :
5872 1 : CPLDebug( "GTiff", "Got COMPD_CS, but stripping it." );
5873 1 : char *pszWKT = pszProjection;
5874 1 : oSRS.importFromWkt( &pszWKT );
5875 1 : CPLFree( pszProjection );
5876 :
5877 1 : oSRS.StripVertical();
5878 1 : oSRS.exportToWkt( &pszProjection );
5879 : }
5880 : }
5881 :
5882 : // Is this a pixel-is-point dataset?
5883 : short nRasterType;
5884 :
5885 : // check the tif linear unit and the CS linear unit
5886 : #ifdef ESRI_BUILD
5887 : AdjustLinearUnit(psGTIFDefn.UOMLength);
5888 : #endif
5889 :
5890 : #if LIBGEOTIFF_VERSION >= 1410
5891 : GTIFFreeDefn(psGTIFDefn);
5892 : #else
5893 1018 : CPLFree(psGTIFDefn);
5894 : #endif
5895 :
5896 1018 : if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
5897 : 0, 1 ) == 1 )
5898 : {
5899 969 : if( nRasterType == (short) RasterPixelIsPoint )
5900 17 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
5901 : else
5902 952 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
5903 : }
5904 :
5905 1018 : GTIFFree( hGTIF );
5906 : }
5907 :
5908 1018 : if( pszProjection == NULL )
5909 : {
5910 48 : pszProjection = CPLStrdup( "" );
5911 : }
5912 :
5913 1018 : bGeoTIFFInfoChanged = FALSE;
5914 1018 : bForceUnsetGT = FALSE;
5915 1018 : bForceUnsetProjection = FALSE;
5916 : }
5917 :
5918 : /************************************************************************/
5919 : /* AdjustLinearUnit() */
5920 : /* */
5921 : /* The following code is only used in ESRI Builds and there is */
5922 : /* outstanding discussion on whether it is even appropriate */
5923 : /* then. */
5924 : /************************************************************************/
5925 : #ifdef ESRI_BUILD
5926 :
5927 : void GTiffDataset::AdjustLinearUnit(short UOMLength)
5928 : {
5929 : if (!pszProjection || strlen(pszProjection) == 0)
5930 : return;
5931 : if( UOMLength == 9001)
5932 : {
5933 : char* pstr = strstr(pszProjection, "PARAMETER");
5934 : if (!pstr)
5935 : return;
5936 : pstr = strstr(pstr, "UNIT[");
5937 : if (!pstr)
5938 : return;
5939 : pstr = strchr(pstr, ',') + 1;
5940 : if (!pstr)
5941 : return;
5942 : char* pstr1 = strchr(pstr, ']');
5943 : if (!pstr1 || pstr1 - pstr >= 128)
5944 : return;
5945 : char csUnitStr[128];
5946 : strncpy(csUnitStr, pstr, pstr1-pstr);
5947 : csUnitStr[pstr1-pstr] = '\0';
5948 : double csUnit = CPLAtof(csUnitStr);
5949 : if(fabs(csUnit - 1.0) > 0.000001)
5950 : {
5951 : for(long i=0; i<6; i++)
5952 : adfGeoTransform[i] /= csUnit;
5953 : }
5954 : }
5955 : }
5956 :
5957 : #endif /* def ESRI_BUILD */
5958 :
5959 : /************************************************************************/
5960 : /* ApplyPamInfo() */
5961 : /* */
5962 : /* PAM Information, if available, overrides the GeoTIFF */
5963 : /* geotransform and projection definition. Check for them */
5964 : /* now. */
5965 : /************************************************************************/
5966 :
5967 3910 : void GTiffDataset::ApplyPamInfo()
5968 :
5969 : {
5970 : double adfPamGeoTransform[6];
5971 :
5972 3910 : if( GDALPamDataset::GetGeoTransform( adfPamGeoTransform ) == CE_None
5973 0 : && (adfPamGeoTransform[0] != 0.0 || adfPamGeoTransform[1] != 1.0
5974 0 : || adfPamGeoTransform[2] != 0.0 || adfPamGeoTransform[3] != 0.0
5975 0 : || adfPamGeoTransform[4] != 0.0 || adfPamGeoTransform[5] != 1.0 ))
5976 : {
5977 0 : memcpy( adfGeoTransform, adfPamGeoTransform, sizeof(double)*6 );
5978 0 : bGeoTransformValid = TRUE;
5979 : }
5980 :
5981 3910 : const char *pszPamSRS = GDALPamDataset::GetProjectionRef();
5982 :
5983 3910 : if( pszPamSRS != NULL && strlen(pszPamSRS) > 0 )
5984 : {
5985 2 : CPLFree( pszProjection );
5986 2 : pszProjection = CPLStrdup( pszPamSRS );
5987 2 : bLookedForProjection = TRUE;
5988 : }
5989 :
5990 3910 : int nPamGCPCount = GDALPamDataset::GetGCPCount();
5991 3910 : if( nPamGCPCount > 0 )
5992 : {
5993 2 : if( nGCPCount > 0 )
5994 : {
5995 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
5996 0 : CPLFree( pasGCPList );
5997 0 : pasGCPList = NULL;
5998 : }
5999 :
6000 2 : nGCPCount = nPamGCPCount;
6001 2 : pasGCPList = GDALDuplicateGCPs(nGCPCount, GDALPamDataset::GetGCPs());
6002 :
6003 2 : CPLFree( pszProjection );
6004 2 : pszProjection = NULL;
6005 :
6006 2 : const char *pszPamGCPProjection = GDALPamDataset::GetGCPProjection();
6007 2 : if( pszPamGCPProjection != NULL && strlen(pszPamGCPProjection) > 0 )
6008 2 : pszProjection = CPLStrdup(pszPamGCPProjection);
6009 :
6010 2 : bLookedForProjection = TRUE;
6011 : }
6012 :
6013 : /* -------------------------------------------------------------------- */
6014 : /* Copy any PAM metadata into our GeoTIFF context, and with */
6015 : /* the PAM info overriding the GeoTIFF context. */
6016 : /* -------------------------------------------------------------------- */
6017 3910 : char **papszPamDomains = oMDMD.GetDomainList();
6018 :
6019 3926 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
6020 : {
6021 16 : const char *pszDomain = papszPamDomains[iDomain];
6022 16 : char **papszGT_MD = CSLDuplicate(oGTiffMDMD.GetMetadata( pszDomain ));
6023 16 : char **papszPAM_MD = oMDMD.GetMetadata( pszDomain );
6024 :
6025 16 : papszGT_MD = CSLMerge( papszGT_MD, papszPAM_MD );
6026 :
6027 16 : oGTiffMDMD.SetMetadata( papszGT_MD, pszDomain );
6028 16 : CSLDestroy( papszGT_MD );
6029 : }
6030 :
6031 271143 : for( int i = 1; i <= GetRasterCount(); i++)
6032 : {
6033 267233 : GTiffRasterBand* poBand = (GTiffRasterBand *)GetRasterBand(i);
6034 267233 : papszPamDomains = poBand->oMDMD.GetDomainList();
6035 :
6036 267273 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
6037 : {
6038 40 : const char *pszDomain = papszPamDomains[iDomain];
6039 40 : char **papszGT_MD = CSLDuplicate(poBand->oGTiffMDMD.GetMetadata( pszDomain ));
6040 40 : char **papszPAM_MD = poBand->oMDMD.GetMetadata( pszDomain );
6041 :
6042 40 : papszGT_MD = CSLMerge( papszGT_MD, papszPAM_MD );
6043 :
6044 40 : poBand->oGTiffMDMD.SetMetadata( papszGT_MD, pszDomain );
6045 40 : CSLDestroy( papszGT_MD );
6046 : }
6047 : }
6048 3910 : }
6049 :
6050 : /************************************************************************/
6051 : /* OpenDir() */
6052 : /* */
6053 : /* Open a specific directory as encoded into a filename. */
6054 : /************************************************************************/
6055 :
6056 6 : GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
6057 :
6058 : {
6059 6 : int bAllowRGBAInterface = TRUE;
6060 6 : const char* pszFilename = poOpenInfo->pszFilename;
6061 6 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
6062 : {
6063 0 : bAllowRGBAInterface = FALSE;
6064 0 : pszFilename += strlen("GTIFF_RAW:");
6065 : }
6066 :
6067 6 : if( !EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
6068 0 : return NULL;
6069 :
6070 : /* -------------------------------------------------------------------- */
6071 : /* Split out filename, and dir#/offset. */
6072 : /* -------------------------------------------------------------------- */
6073 6 : pszFilename += strlen("GTIFF_DIR:");
6074 6 : int bAbsolute = FALSE;
6075 : toff_t nOffset;
6076 :
6077 6 : if( EQUALN(pszFilename,"off:",4) )
6078 : {
6079 1 : bAbsolute = TRUE;
6080 1 : pszFilename += 4;
6081 : }
6082 :
6083 6 : nOffset = atol(pszFilename);
6084 6 : pszFilename += 1;
6085 :
6086 20 : while( *pszFilename != '\0' && pszFilename[-1] != ':' )
6087 8 : pszFilename++;
6088 :
6089 6 : if( *pszFilename == '\0' || nOffset == 0 )
6090 : {
6091 : CPLError( CE_Failure, CPLE_OpenFailed,
6092 : "Unable to extract offset or filename, should take the form\n"
6093 0 : "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename" );
6094 0 : return NULL;
6095 : }
6096 :
6097 : /* -------------------------------------------------------------------- */
6098 : /* Try opening the dataset. */
6099 : /* -------------------------------------------------------------------- */
6100 : TIFF *hTIFF;
6101 :
6102 6 : if (!GTiffOneTimeInit())
6103 0 : return NULL;
6104 :
6105 6 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
6106 6 : if( hTIFF == NULL )
6107 0 : return( NULL );
6108 :
6109 : /* -------------------------------------------------------------------- */
6110 : /* If a directory was requested by index, advance to it now. */
6111 : /* -------------------------------------------------------------------- */
6112 6 : if( !bAbsolute )
6113 : {
6114 12 : while( nOffset > 1 )
6115 : {
6116 2 : if( TIFFReadDirectory( hTIFF ) == 0 )
6117 : {
6118 0 : XTIFFClose( hTIFF );
6119 : CPLError( CE_Failure, CPLE_OpenFailed,
6120 0 : "Requested directory %lu not found.", (long unsigned int)nOffset );
6121 0 : return NULL;
6122 : }
6123 2 : nOffset--;
6124 : }
6125 :
6126 5 : nOffset = TIFFCurrentDirOffset( hTIFF );
6127 : }
6128 :
6129 : /* -------------------------------------------------------------------- */
6130 : /* Create a corresponding GDALDataset. */
6131 : /* -------------------------------------------------------------------- */
6132 : GTiffDataset *poDS;
6133 :
6134 6 : poDS = new GTiffDataset();
6135 6 : poDS->SetDescription( poOpenInfo->pszFilename );
6136 12 : poDS->osFilename = poOpenInfo->pszFilename;
6137 6 : poDS->poActiveDS = poDS;
6138 :
6139 12 : if( !EQUAL(pszFilename,poOpenInfo->pszFilename)
6140 : && !EQUALN(poOpenInfo->pszFilename,"GTIFF_RAW:",10) )
6141 : {
6142 6 : poDS->SetPhysicalFilename( pszFilename );
6143 6 : poDS->SetSubdatasetName( poOpenInfo->pszFilename );
6144 6 : poDS->osFilename = pszFilename;
6145 : }
6146 :
6147 6 : if (poOpenInfo->eAccess == GA_Update)
6148 : {
6149 : CPLError( CE_Warning, CPLE_AppDefined,
6150 0 : "Opening a specific TIFF directory is not supported in update mode. Switching to read-only" );
6151 : }
6152 :
6153 6 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
6154 : nOffset, FALSE, GA_ReadOnly,
6155 : bAllowRGBAInterface, TRUE,
6156 : poOpenInfo->papszSiblingFiles ) != CE_None )
6157 : {
6158 0 : delete poDS;
6159 0 : return NULL;
6160 : }
6161 : else
6162 : {
6163 6 : poDS->bCloseTIFFHandle = TRUE;
6164 6 : return poDS;
6165 : }
6166 : }
6167 :
6168 : /************************************************************************/
6169 : /* OpenOffset() */
6170 : /* */
6171 : /* Initialize the GTiffDataset based on a passed in file */
6172 : /* handle, and directory offset to utilize. This is called for */
6173 : /* full res, and overview pages. */
6174 : /************************************************************************/
6175 :
6176 4302 : CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
6177 : GTiffDataset **ppoActiveDSRef,
6178 : toff_t nDirOffsetIn,
6179 : int bBaseIn, GDALAccess eAccess,
6180 : int bAllowRGBAInterface,
6181 : int bReadGeoTransform,
6182 : char** papszSiblingFiles )
6183 :
6184 : {
6185 : uint32 nXSize, nYSize;
6186 4302 : int bTreatAsBitmap = FALSE;
6187 4302 : int bTreatAsOdd = FALSE;
6188 :
6189 4302 : this->eAccess = eAccess;
6190 :
6191 4302 : hTIFF = hTIFFIn;
6192 4302 : this->ppoActiveDSRef = ppoActiveDSRef;
6193 :
6194 4302 : nDirOffset = nDirOffsetIn;
6195 :
6196 4302 : if (!SetDirectory( nDirOffsetIn ))
6197 0 : return CE_Failure;
6198 :
6199 4302 : bBase = bBaseIn;
6200 :
6201 4302 : this->eAccess = eAccess;
6202 :
6203 : /* -------------------------------------------------------------------- */
6204 : /* Capture some information from the file that is of interest. */
6205 : /* -------------------------------------------------------------------- */
6206 4302 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
6207 4302 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
6208 4302 : nRasterXSize = nXSize;
6209 4302 : nRasterYSize = nYSize;
6210 :
6211 4302 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel ) )
6212 1 : nBands = 1;
6213 : else
6214 4301 : nBands = nSamplesPerPixel;
6215 :
6216 4302 : if( !TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)) )
6217 1 : nBitsPerSample = 1;
6218 :
6219 4302 : if( !TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(nPlanarConfig) ) )
6220 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
6221 :
6222 4302 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
6223 1 : nPhotometric = PHOTOMETRIC_MINISBLACK;
6224 :
6225 4302 : if( !TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(nSampleFormat) ) )
6226 44 : nSampleFormat = SAMPLEFORMAT_UINT;
6227 :
6228 4302 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
6229 0 : nCompression = COMPRESSION_NONE;
6230 :
6231 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
6232 4302 : if (nCompression != COMPRESSION_NONE &&
6233 : !TIFFIsCODECConfigured(nCompression))
6234 : {
6235 : CPLError( CE_Failure, CPLE_AppDefined,
6236 0 : "Cannot open TIFF file due to missing codec." );
6237 0 : return CE_Failure;
6238 : }
6239 : #endif
6240 :
6241 : /* -------------------------------------------------------------------- */
6242 : /* YCbCr JPEG compressed images should be translated on the fly */
6243 : /* to RGB by libtiff/libjpeg unless specifically requested */
6244 : /* otherwise. */
6245 : /* -------------------------------------------------------------------- */
6246 4302 : if( nCompression == COMPRESSION_JPEG
6247 : && nPhotometric == PHOTOMETRIC_YCBCR
6248 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
6249 : "YES") ) )
6250 : {
6251 : int nColorMode;
6252 :
6253 120 : SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
6254 120 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
6255 : nColorMode != JPEGCOLORMODE_RGB )
6256 102 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
6257 : }
6258 :
6259 : /* -------------------------------------------------------------------- */
6260 : /* Get strip/tile layout. */
6261 : /* -------------------------------------------------------------------- */
6262 4302 : if( TIFFIsTiled(hTIFF) )
6263 : {
6264 719 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(nBlockXSize) );
6265 719 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(nBlockYSize) );
6266 : }
6267 : else
6268 : {
6269 3583 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
6270 : &(nRowsPerStrip) ) )
6271 : {
6272 : CPLError( CE_Warning, CPLE_AppDefined,
6273 0 : "RowsPerStrip not defined ... assuming all one strip." );
6274 0 : nRowsPerStrip = nYSize; /* dummy value */
6275 : }
6276 :
6277 : // If the rows per strip is larger than the file we will get
6278 : // confused. libtiff internally will treat the rowsperstrip as
6279 : // the image height and it is best if we do too. (#4468)
6280 3583 : if (nRowsPerStrip > (uint32)nRasterYSize)
6281 12 : nRowsPerStrip = nRasterYSize;
6282 :
6283 3583 : nBlockXSize = nRasterXSize;
6284 3583 : nBlockYSize = nRowsPerStrip;
6285 : }
6286 :
6287 : nBlocksPerBand =
6288 4302 : DIV_ROUND_UP(nYSize, nBlockYSize) * DIV_ROUND_UP(nXSize, nBlockXSize);
6289 :
6290 : /* -------------------------------------------------------------------- */
6291 : /* Should we handle this using the GTiffBitmapBand? */
6292 : /* -------------------------------------------------------------------- */
6293 4302 : if( nBitsPerSample == 1 && nBands == 1 )
6294 : {
6295 129 : bTreatAsBitmap = TRUE;
6296 :
6297 : // Lets treat large "one row" bitmaps using the scanline api.
6298 129 : if( !TIFFIsTiled(hTIFF)
6299 : && nBlockYSize == nYSize
6300 : && nYSize > 2000
6301 : && bAllowRGBAInterface )
6302 4 : bTreatAsSplitBitmap = TRUE;
6303 : }
6304 :
6305 : /* -------------------------------------------------------------------- */
6306 : /* Should we treat this via the RGBA interface? */
6307 : /* -------------------------------------------------------------------- */
6308 4302 : if( bAllowRGBAInterface &&
6309 : !bTreatAsBitmap && !(nBitsPerSample > 8)
6310 : && (nPhotometric == PHOTOMETRIC_CIELAB ||
6311 : nPhotometric == PHOTOMETRIC_LOGL ||
6312 : nPhotometric == PHOTOMETRIC_LOGLUV ||
6313 : nPhotometric == PHOTOMETRIC_SEPARATED ||
6314 : ( nPhotometric == PHOTOMETRIC_YCBCR
6315 : && nCompression != COMPRESSION_JPEG )) )
6316 : {
6317 : char szMessage[1024];
6318 :
6319 5 : if( TIFFRGBAImageOK( hTIFF, szMessage ) == 1 )
6320 : {
6321 5 : const char* pszSourceColorSpace = NULL;
6322 5 : switch (nPhotometric)
6323 : {
6324 : case PHOTOMETRIC_CIELAB:
6325 1 : pszSourceColorSpace = "CIELAB";
6326 1 : break;
6327 : case PHOTOMETRIC_LOGL:
6328 0 : pszSourceColorSpace = "LOGL";
6329 0 : break;
6330 : case PHOTOMETRIC_LOGLUV:
6331 0 : pszSourceColorSpace = "LOGLUV";
6332 0 : break;
6333 : case PHOTOMETRIC_SEPARATED:
6334 3 : pszSourceColorSpace = "CMYK";
6335 3 : break;
6336 : case PHOTOMETRIC_YCBCR:
6337 1 : pszSourceColorSpace = "YCbCr";
6338 : break;
6339 : }
6340 5 : if (pszSourceColorSpace)
6341 5 : SetMetadataItem( "SOURCE_COLOR_SPACE", pszSourceColorSpace, "IMAGE_STRUCTURE" );
6342 5 : bTreatAsRGBA = TRUE;
6343 5 : nBands = 4;
6344 : }
6345 : else
6346 : {
6347 0 : CPLDebug( "GTiff", "TIFFRGBAImageOK says:\n%s", szMessage );
6348 : }
6349 : }
6350 :
6351 : /* -------------------------------------------------------------------- */
6352 : /* Should we treat this via the split interface? */
6353 : /* -------------------------------------------------------------------- */
6354 4302 : if( !TIFFIsTiled(hTIFF)
6355 : && nBitsPerSample == 8
6356 : && nBlockYSize == nYSize
6357 : && nYSize > 2000
6358 : && !bTreatAsRGBA
6359 : && CSLTestBoolean(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
6360 : {
6361 : /* libtiff 3.9.2 (20091104) and older, libtiff 4.0.0beta5 (also 20091104) */
6362 : /* and older will crash when trying to open a all-in-one-strip */
6363 : /* YCbCr JPEG compressed TIFF (see #3259). */
6364 : #if (TIFFLIB_VERSION <= 20091104 && !defined(BIGTIFF_SUPPORT)) || \
6365 : (TIFFLIB_VERSION <= 20091104 && defined(BIGTIFF_SUPPORT))
6366 : if (nPhotometric == PHOTOMETRIC_YCBCR &&
6367 : nCompression == COMPRESSION_JPEG)
6368 : {
6369 : CPLDebug("GTiff", "Avoid using split band to open all-in-one-strip "
6370 : "YCbCr JPEG compressed TIFF because of older libtiff");
6371 : }
6372 : else
6373 : #endif
6374 10 : bTreatAsSplit = TRUE;
6375 : }
6376 :
6377 : /* -------------------------------------------------------------------- */
6378 : /* Should we treat this via the odd bits interface? */
6379 : /* -------------------------------------------------------------------- */
6380 4302 : if ( nSampleFormat == SAMPLEFORMAT_IEEEFP )
6381 : {
6382 502 : if ( nBitsPerSample == 16 || nBitsPerSample == 24 )
6383 2 : bTreatAsOdd = TRUE;
6384 : }
6385 3800 : else if ( !bTreatAsRGBA && !bTreatAsBitmap
6386 : && nBitsPerSample != 8
6387 : && nBitsPerSample != 16
6388 : && nBitsPerSample != 32
6389 : && nBitsPerSample != 64
6390 : && nBitsPerSample != 128 )
6391 115 : bTreatAsOdd = TRUE;
6392 :
6393 4302 : int bMinIsWhite = nPhotometric == PHOTOMETRIC_MINISWHITE;
6394 :
6395 : /* -------------------------------------------------------------------- */
6396 : /* Capture the color table if there is one. */
6397 : /* -------------------------------------------------------------------- */
6398 : unsigned short *panRed, *panGreen, *panBlue;
6399 :
6400 4302 : if( bTreatAsRGBA
6401 : || TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
6402 : &panRed, &panGreen, &panBlue) == 0 )
6403 : {
6404 : // Build inverted palette if we have inverted photometric.
6405 : // Pixel values remains unchanged. Avoid doing this for *deep*
6406 : // data types (per #1882)
6407 4229 : if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
6408 : {
6409 : GDALColorEntry oEntry;
6410 : int iColor, nColorCount;
6411 :
6412 7 : poColorTable = new GDALColorTable();
6413 7 : nColorCount = 1 << nBitsPerSample;
6414 :
6415 21 : for ( iColor = 0; iColor < nColorCount; iColor++ )
6416 : {
6417 : oEntry.c1 = oEntry.c2 = oEntry.c3 = (short)
6418 14 : ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
6419 14 : oEntry.c4 = 255;
6420 14 : poColorTable->SetColorEntry( iColor, &oEntry );
6421 : }
6422 :
6423 7 : nPhotometric = PHOTOMETRIC_PALETTE;
6424 : }
6425 : else
6426 4215 : poColorTable = NULL;
6427 : }
6428 : else
6429 : {
6430 80 : int nColorCount, nMaxColor = 0;
6431 : GDALColorEntry oEntry;
6432 :
6433 80 : poColorTable = new GDALColorTable();
6434 :
6435 80 : nColorCount = 1 << nBitsPerSample;
6436 :
6437 344420 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6438 : {
6439 344340 : oEntry.c1 = panRed[iColor] / 256;
6440 344340 : oEntry.c2 = panGreen[iColor] / 256;
6441 344340 : oEntry.c3 = panBlue[iColor] / 256;
6442 344340 : oEntry.c4 = 255;
6443 :
6444 344340 : poColorTable->SetColorEntry( iColor, &oEntry );
6445 :
6446 344340 : nMaxColor = MAX(nMaxColor,panRed[iColor]);
6447 344340 : nMaxColor = MAX(nMaxColor,panGreen[iColor]);
6448 344340 : nMaxColor = MAX(nMaxColor,panBlue[iColor]);
6449 : }
6450 :
6451 : // Bug 1384 - Some TIFF files are generated with color map entry
6452 : // values in range 0-255 instead of 0-65535 - try to handle these
6453 : // gracefully.
6454 80 : if( nMaxColor > 0 && nMaxColor < 256 )
6455 : {
6456 0 : CPLDebug( "GTiff", "TIFF ColorTable seems to be improperly scaled, fixing up." );
6457 :
6458 0 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6459 : {
6460 0 : oEntry.c1 = panRed[iColor];
6461 0 : oEntry.c2 = panGreen[iColor];
6462 0 : oEntry.c3 = panBlue[iColor];
6463 0 : oEntry.c4 = 255;
6464 :
6465 0 : poColorTable->SetColorEntry( iColor, &oEntry );
6466 : }
6467 : }
6468 : }
6469 :
6470 : /* -------------------------------------------------------------------- */
6471 : /* Create band information objects. */
6472 : /* -------------------------------------------------------------------- */
6473 272168 : for( int iBand = 0; iBand < nBands; iBand++ )
6474 : {
6475 267866 : if( bTreatAsRGBA )
6476 20 : SetBand( iBand+1, new GTiffRGBABand( this, iBand+1 ) );
6477 267846 : else if( bTreatAsSplitBitmap )
6478 4 : SetBand( iBand+1, new GTiffSplitBitmapBand( this, iBand+1 ) );
6479 267842 : else if( bTreatAsSplit )
6480 28 : SetBand( iBand+1, new GTiffSplitBand( this, iBand+1 ) );
6481 267814 : else if( bTreatAsBitmap )
6482 125 : SetBand( iBand+1, new GTiffBitmapBand( this, iBand+1 ) );
6483 267689 : else if( bTreatAsOdd )
6484 231 : SetBand( iBand+1, new GTiffOddBitsBand( this, iBand+1 ) );
6485 : else
6486 267458 : SetBand( iBand+1, new GTiffRasterBand( this, iBand+1 ) );
6487 : }
6488 :
6489 4302 : if( GetRasterBand(1)->GetRasterDataType() == GDT_Unknown )
6490 : {
6491 : CPLError( CE_Failure, CPLE_NotSupported,
6492 0 : "Unsupported TIFF configuration." );
6493 0 : return CE_Failure;
6494 : }
6495 :
6496 : /* -------------------------------------------------------------------- */
6497 : /* Get the transform or gcps from the GeoTIFF file. */
6498 : /* -------------------------------------------------------------------- */
6499 4302 : if( bReadGeoTransform )
6500 : {
6501 3916 : char *pszTabWKT = NULL;
6502 : double *padfTiePoints, *padfScale, *padfMatrix;
6503 : uint16 nCount;
6504 3916 : bool bPixelIsPoint = false;
6505 : short nRasterType;
6506 : GTIF *psGTIF;
6507 3916 : int bPointGeoIgnore = FALSE;
6508 :
6509 3916 : psGTIF = GTIFNew( hTIFF ); // I wonder how expensive this is?
6510 :
6511 3916 : if( psGTIF )
6512 : {
6513 3915 : if( GTIFKeyGet(psGTIF, GTRasterTypeGeoKey, &nRasterType,
6514 : 0, 1 ) == 1
6515 : && nRasterType == (short) RasterPixelIsPoint )
6516 : {
6517 31 : bPixelIsPoint = true;
6518 : bPointGeoIgnore =
6519 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
6520 31 : "FALSE") );
6521 : }
6522 :
6523 3915 : GTIFFree( psGTIF );
6524 : }
6525 :
6526 3916 : adfGeoTransform[0] = 0.0;
6527 3916 : adfGeoTransform[1] = 1.0;
6528 3916 : adfGeoTransform[2] = 0.0;
6529 3916 : adfGeoTransform[3] = 0.0;
6530 3916 : adfGeoTransform[4] = 0.0;
6531 3916 : adfGeoTransform[5] = 1.0;
6532 :
6533 9470 : if( TIFFGetField(hTIFF,TIFFTAG_GEOPIXELSCALE,&nCount,&padfScale )
6534 : && nCount >= 2
6535 5554 : && padfScale[0] != 0.0 && padfScale[1] != 0.0 )
6536 : {
6537 2777 : adfGeoTransform[1] = padfScale[0];
6538 2777 : adfGeoTransform[5] = - ABS(padfScale[1]);
6539 :
6540 2777 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
6541 : && nCount >= 6 )
6542 : {
6543 : adfGeoTransform[0] =
6544 2777 : padfTiePoints[3] - padfTiePoints[0] * adfGeoTransform[1];
6545 : adfGeoTransform[3] =
6546 2777 : padfTiePoints[4] - padfTiePoints[1] * adfGeoTransform[5];
6547 :
6548 2777 : if( bPixelIsPoint && !bPointGeoIgnore )
6549 : {
6550 15 : adfGeoTransform[0] -= (adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5);
6551 15 : adfGeoTransform[3] -= (adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5);
6552 : }
6553 :
6554 2777 : bGeoTransformValid = TRUE;
6555 : }
6556 : }
6557 :
6558 1139 : else if( TIFFGetField(hTIFF,TIFFTAG_GEOTRANSMATRIX,&nCount,&padfMatrix )
6559 : && nCount == 16 )
6560 : {
6561 14 : adfGeoTransform[0] = padfMatrix[3];
6562 14 : adfGeoTransform[1] = padfMatrix[0];
6563 14 : adfGeoTransform[2] = padfMatrix[1];
6564 14 : adfGeoTransform[3] = padfMatrix[7];
6565 14 : adfGeoTransform[4] = padfMatrix[4];
6566 14 : adfGeoTransform[5] = padfMatrix[5];
6567 :
6568 14 : if( bPixelIsPoint && !bPointGeoIgnore )
6569 : {
6570 4 : adfGeoTransform[0] -= (adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5);
6571 4 : adfGeoTransform[3] -= (adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5);
6572 : }
6573 :
6574 14 : bGeoTransformValid = TRUE;
6575 : }
6576 :
6577 : /* -------------------------------------------------------------------- */
6578 : /* Otherwise try looking for a .tfw, .tifw or .wld file. */
6579 : /* -------------------------------------------------------------------- */
6580 : else
6581 : {
6582 1125 : char* pszWldFilename = NULL;
6583 :
6584 : bGeoTransformValid =
6585 : GDALReadWorldFile2( osFilename, NULL, adfGeoTransform,
6586 1125 : papszSiblingFiles, &pszWldFilename);
6587 :
6588 1125 : if( !bGeoTransformValid )
6589 : {
6590 : bGeoTransformValid =
6591 : GDALReadWorldFile2( osFilename, "wld", adfGeoTransform,
6592 1120 : papszSiblingFiles, &pszWldFilename);
6593 : }
6594 :
6595 1125 : if( !bGeoTransformValid )
6596 : {
6597 : int bTabFileOK =
6598 : GDALReadTabFile2( osFilename, adfGeoTransform,
6599 : &pszTabWKT, &nGCPCount, &pasGCPList,
6600 1115 : papszSiblingFiles, &pszWldFilename );
6601 :
6602 1115 : if( bTabFileOK && nGCPCount == 0 )
6603 2 : bGeoTransformValid = TRUE;
6604 : }
6605 :
6606 1125 : if (pszWldFilename)
6607 : {
6608 12 : osWldFilename = pszWldFilename;
6609 12 : CPLFree(pszWldFilename);
6610 : }
6611 : }
6612 :
6613 : /* -------------------------------------------------------------------- */
6614 : /* Check for GCPs. Note, we will allow there to be GCPs and a */
6615 : /* transform in some circumstances. */
6616 : /* -------------------------------------------------------------------- */
6617 3916 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
6618 : && !bGeoTransformValid )
6619 : {
6620 25 : nGCPCount = nCount / 6;
6621 25 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPCount);
6622 :
6623 129 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
6624 : {
6625 : char szID[32];
6626 :
6627 104 : sprintf( szID, "%d", iGCP+1 );
6628 104 : pasGCPList[iGCP].pszId = CPLStrdup( szID );
6629 104 : pasGCPList[iGCP].pszInfo = CPLStrdup("");
6630 104 : pasGCPList[iGCP].dfGCPPixel = padfTiePoints[iGCP*6+0];
6631 104 : pasGCPList[iGCP].dfGCPLine = padfTiePoints[iGCP*6+1];
6632 104 : pasGCPList[iGCP].dfGCPX = padfTiePoints[iGCP*6+3];
6633 104 : pasGCPList[iGCP].dfGCPY = padfTiePoints[iGCP*6+4];
6634 104 : pasGCPList[iGCP].dfGCPZ = padfTiePoints[iGCP*6+5];
6635 :
6636 104 : if( bPixelIsPoint && !bPointGeoIgnore )
6637 : {
6638 0 : pasGCPList[iGCP].dfGCPPixel -= 0.5;
6639 0 : pasGCPList[iGCP].dfGCPLine -= 0.5;
6640 : }
6641 : }
6642 : }
6643 :
6644 : /* -------------------------------------------------------------------- */
6645 : /* Did we find a tab file? If so we will use it's coordinate */
6646 : /* system and give it precidence. */
6647 : /* -------------------------------------------------------------------- */
6648 3918 : if( pszTabWKT != NULL
6649 2 : && (pszProjection == NULL || pszProjection[0] == '\0') )
6650 : {
6651 2 : CPLFree( pszProjection );
6652 2 : pszProjection = pszTabWKT;
6653 2 : pszTabWKT = NULL;
6654 2 : bLookedForProjection = TRUE;
6655 : }
6656 :
6657 3916 : CPLFree( pszTabWKT );
6658 3916 : bGeoTIFFInfoChanged = FALSE;
6659 3916 : bForceUnsetGT = FALSE;
6660 3916 : bForceUnsetProjection = FALSE;
6661 : }
6662 :
6663 : /* -------------------------------------------------------------------- */
6664 : /* Capture some other potentially interesting information. */
6665 : /* -------------------------------------------------------------------- */
6666 : char *pszText, szWorkMDI[200];
6667 : float fResolution;
6668 : uint16 nShort;
6669 :
6670 4302 : if( TIFFGetField( hTIFF, TIFFTAG_DOCUMENTNAME, &pszText ) )
6671 21 : SetMetadataItem( "TIFFTAG_DOCUMENTNAME", pszText );
6672 :
6673 4302 : if( TIFFGetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, &pszText ) )
6674 6 : SetMetadataItem( "TIFFTAG_IMAGEDESCRIPTION", pszText );
6675 :
6676 4302 : if( TIFFGetField( hTIFF, TIFFTAG_SOFTWARE, &pszText ) )
6677 10 : SetMetadataItem( "TIFFTAG_SOFTWARE", pszText );
6678 :
6679 4302 : if( TIFFGetField( hTIFF, TIFFTAG_DATETIME, &pszText ) )
6680 5 : SetMetadataItem( "TIFFTAG_DATETIME", pszText );
6681 :
6682 4302 : if( TIFFGetField( hTIFF, TIFFTAG_ARTIST, &pszText ) )
6683 2 : SetMetadataItem( "TIFFTAG_ARTIST", pszText );
6684 :
6685 4302 : if( TIFFGetField( hTIFF, TIFFTAG_HOSTCOMPUTER, &pszText ) )
6686 2 : SetMetadataItem( "TIFFTAG_HOSTCOMPUTER", pszText );
6687 :
6688 4302 : if( TIFFGetField( hTIFF, TIFFTAG_COPYRIGHT, &pszText ) )
6689 2 : SetMetadataItem( "TIFFTAG_COPYRIGHT", pszText );
6690 :
6691 4302 : if( TIFFGetField( hTIFF, TIFFTAG_XRESOLUTION, &fResolution ) )
6692 : {
6693 46 : sprintf( szWorkMDI, "%.8g", fResolution );
6694 46 : SetMetadataItem( "TIFFTAG_XRESOLUTION", szWorkMDI );
6695 : }
6696 :
6697 4302 : if( TIFFGetField( hTIFF, TIFFTAG_YRESOLUTION, &fResolution ) )
6698 : {
6699 46 : sprintf( szWorkMDI, "%.8g", fResolution );
6700 46 : SetMetadataItem( "TIFFTAG_YRESOLUTION", szWorkMDI );
6701 : }
6702 :
6703 4302 : if( TIFFGetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, &nShort ) )
6704 : {
6705 0 : sprintf( szWorkMDI, "%d", nShort );
6706 0 : SetMetadataItem( "TIFFTAG_MINSAMPLEVALUE", szWorkMDI );
6707 : }
6708 :
6709 4302 : if( TIFFGetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, &nShort ) )
6710 : {
6711 0 : sprintf( szWorkMDI, "%d", nShort );
6712 0 : SetMetadataItem( "TIFFTAG_MAXSAMPLEVALUE", szWorkMDI );
6713 : }
6714 :
6715 4302 : if( TIFFGetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort ) )
6716 : {
6717 46 : if( nShort == RESUNIT_NONE )
6718 16 : sprintf( szWorkMDI, "%d (unitless)", nShort );
6719 30 : else if( nShort == RESUNIT_INCH )
6720 30 : sprintf( szWorkMDI, "%d (pixels/inch)", nShort );
6721 0 : else if( nShort == RESUNIT_CENTIMETER )
6722 0 : sprintf( szWorkMDI, "%d (pixels/cm)", nShort );
6723 : else
6724 0 : sprintf( szWorkMDI, "%d", nShort );
6725 46 : SetMetadataItem( "TIFFTAG_RESOLUTIONUNIT", szWorkMDI );
6726 : }
6727 :
6728 : int nTagSize;
6729 : void* pData;
6730 4302 : if( TIFFGetField( hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData ) )
6731 : {
6732 2 : char* pszXMP = (char*)VSIMalloc(nTagSize + 1);
6733 2 : if (pszXMP)
6734 : {
6735 2 : memcpy(pszXMP, pData, nTagSize);
6736 2 : pszXMP[nTagSize] = '\0';
6737 :
6738 : char *apszMDList[2];
6739 2 : apszMDList[0] = pszXMP;
6740 2 : apszMDList[1] = NULL;
6741 2 : SetMetadata(apszMDList, "xml:XMP");
6742 :
6743 2 : CPLFree(pszXMP);
6744 : }
6745 : }
6746 :
6747 4302 : if( nCompression == COMPRESSION_NONE )
6748 : /* no compression tag */;
6749 438 : else if( nCompression == COMPRESSION_CCITTRLE )
6750 0 : SetMetadataItem( "COMPRESSION", "CCITTRLE", "IMAGE_STRUCTURE" );
6751 438 : else if( nCompression == COMPRESSION_CCITTFAX3 )
6752 0 : SetMetadataItem( "COMPRESSION", "CCITTFAX3", "IMAGE_STRUCTURE" );
6753 438 : else if( nCompression == COMPRESSION_CCITTFAX4 )
6754 9 : SetMetadataItem( "COMPRESSION", "CCITTFAX4", "IMAGE_STRUCTURE" );
6755 429 : else if( nCompression == COMPRESSION_LZW )
6756 42 : SetMetadataItem( "COMPRESSION", "LZW", "IMAGE_STRUCTURE" );
6757 387 : else if( nCompression == COMPRESSION_OJPEG )
6758 1 : SetMetadataItem( "COMPRESSION", "OJPEG", "IMAGE_STRUCTURE" );
6759 386 : else if( nCompression == COMPRESSION_JPEG )
6760 : {
6761 157 : if ( nPhotometric == PHOTOMETRIC_YCBCR )
6762 120 : SetMetadataItem( "COMPRESSION", "YCbCr JPEG", "IMAGE_STRUCTURE" );
6763 : else
6764 37 : SetMetadataItem( "COMPRESSION", "JPEG", "IMAGE_STRUCTURE" );
6765 : }
6766 229 : else if( nCompression == COMPRESSION_NEXT )
6767 0 : SetMetadataItem( "COMPRESSION", "NEXT", "IMAGE_STRUCTURE" );
6768 229 : else if( nCompression == COMPRESSION_CCITTRLEW )
6769 0 : SetMetadataItem( "COMPRESSION", "CCITTRLEW", "IMAGE_STRUCTURE" );
6770 229 : else if( nCompression == COMPRESSION_PACKBITS )
6771 10 : SetMetadataItem( "COMPRESSION", "PACKBITS", "IMAGE_STRUCTURE" );
6772 219 : else if( nCompression == COMPRESSION_THUNDERSCAN )
6773 0 : SetMetadataItem( "COMPRESSION", "THUNDERSCAN", "IMAGE_STRUCTURE" );
6774 219 : else if( nCompression == COMPRESSION_PIXARFILM )
6775 0 : SetMetadataItem( "COMPRESSION", "PIXARFILM", "IMAGE_STRUCTURE" );
6776 219 : else if( nCompression == COMPRESSION_PIXARLOG )
6777 0 : SetMetadataItem( "COMPRESSION", "PIXARLOG", "IMAGE_STRUCTURE" );
6778 219 : else if( nCompression == COMPRESSION_DEFLATE )
6779 73 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
6780 146 : else if( nCompression == COMPRESSION_ADOBE_DEFLATE )
6781 146 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
6782 0 : else if( nCompression == COMPRESSION_DCS )
6783 0 : SetMetadataItem( "COMPRESSION", "DCS", "IMAGE_STRUCTURE" );
6784 0 : else if( nCompression == COMPRESSION_JBIG )
6785 0 : SetMetadataItem( "COMPRESSION", "JBIG", "IMAGE_STRUCTURE" );
6786 0 : else if( nCompression == COMPRESSION_SGILOG )
6787 0 : SetMetadataItem( "COMPRESSION", "SGILOG", "IMAGE_STRUCTURE" );
6788 0 : else if( nCompression == COMPRESSION_SGILOG24 )
6789 0 : SetMetadataItem( "COMPRESSION", "SGILOG24", "IMAGE_STRUCTURE" );
6790 0 : else if( nCompression == COMPRESSION_JP2000 )
6791 0 : SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
6792 0 : else if( nCompression == COMPRESSION_LZMA )
6793 0 : SetMetadataItem( "COMPRESSION", "LZMA", "IMAGE_STRUCTURE" );
6794 :
6795 : else
6796 : {
6797 0 : CPLString oComp;
6798 : SetMetadataItem( "COMPRESSION",
6799 0 : (const char *) oComp.Printf( "%d", nCompression));
6800 : }
6801 :
6802 4829 : if( nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1 )
6803 527 : SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
6804 : else
6805 3775 : SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
6806 :
6807 4302 : if( (GetRasterBand(1)->GetRasterDataType() == GDT_Byte && nBitsPerSample != 8 ) ||
6808 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 && nBitsPerSample != 16) ||
6809 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 && nBitsPerSample != 32) )
6810 : {
6811 1204 : for (int i = 0; i < nBands; ++i)
6812 : GetRasterBand(i+1)->SetMetadataItem( "NBITS",
6813 : CPLString().Printf( "%d", (int)nBitsPerSample ),
6814 358 : "IMAGE_STRUCTURE" );
6815 : }
6816 :
6817 4302 : if( bMinIsWhite )
6818 8 : SetMetadataItem( "MINISWHITE", "YES", "IMAGE_STRUCTURE" );
6819 :
6820 4302 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
6821 : {
6822 215 : CPLXMLNode *psRoot = CPLParseXMLString( pszText );
6823 215 : CPLXMLNode *psItem = NULL;
6824 :
6825 215 : if( psRoot != NULL && psRoot->eType == CXT_Element
6826 : && EQUAL(psRoot->pszValue,"GDALMetadata") )
6827 215 : psItem = psRoot->psChild;
6828 :
6829 1071 : for( ; psItem != NULL; psItem = psItem->psNext )
6830 : {
6831 : const char *pszKey, *pszValue, *pszRole, *pszDomain;
6832 : char *pszUnescapedValue;
6833 856 : int nBand, bIsXML = FALSE;
6834 :
6835 856 : if( psItem->eType != CXT_Element
6836 : || !EQUAL(psItem->pszValue,"Item") )
6837 0 : continue;
6838 :
6839 856 : pszKey = CPLGetXMLValue( psItem, "name", NULL );
6840 856 : pszValue = CPLGetXMLValue( psItem, NULL, NULL );
6841 856 : nBand = atoi(CPLGetXMLValue( psItem, "sample", "-1" )) + 1;
6842 856 : pszRole = CPLGetXMLValue( psItem, "role", "" );
6843 856 : pszDomain = CPLGetXMLValue( psItem, "domain", "" );
6844 :
6845 856 : if( pszKey == NULL || pszValue == NULL )
6846 37 : continue;
6847 :
6848 819 : if( EQUALN(pszDomain,"xml:",4) )
6849 3 : bIsXML = TRUE;
6850 :
6851 : pszUnescapedValue = CPLUnescapeString( pszValue, NULL,
6852 819 : CPLES_XML );
6853 819 : if( nBand == 0 )
6854 : {
6855 623 : if( bIsXML )
6856 : {
6857 3 : char *apszMD[2] = { pszUnescapedValue, NULL };
6858 3 : SetMetadata( apszMD, pszDomain );
6859 : }
6860 : else
6861 620 : SetMetadataItem( pszKey, pszUnescapedValue, pszDomain );
6862 : }
6863 : else
6864 : {
6865 196 : GDALRasterBand *poBand = GetRasterBand(nBand);
6866 196 : if( poBand != NULL )
6867 : {
6868 196 : if( EQUAL(pszRole,"scale") )
6869 8 : poBand->SetScale( CPLAtofM(pszUnescapedValue) );
6870 188 : else if( EQUAL(pszRole,"offset") )
6871 8 : poBand->SetOffset( CPLAtofM(pszUnescapedValue) );
6872 180 : else if( EQUAL(pszRole,"unittype") )
6873 15 : poBand->SetUnitType( pszUnescapedValue );
6874 165 : else if( EQUAL(pszRole,"description") )
6875 4 : poBand->SetDescription( pszUnescapedValue );
6876 : else
6877 : {
6878 161 : if( bIsXML )
6879 : {
6880 0 : char *apszMD[2] = { pszUnescapedValue, NULL };
6881 0 : poBand->SetMetadata( apszMD, pszDomain );
6882 : }
6883 : else
6884 : poBand->SetMetadataItem(pszKey,pszUnescapedValue,
6885 161 : pszDomain );
6886 : }
6887 : }
6888 : }
6889 819 : CPLFree( pszUnescapedValue );
6890 : }
6891 :
6892 215 : CPLDestroyXMLNode( psRoot );
6893 : }
6894 :
6895 4302 : bMetadataChanged = FALSE;
6896 :
6897 : /* -------------------------------------------------------------------- */
6898 : /* Check for NODATA */
6899 : /* -------------------------------------------------------------------- */
6900 4302 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) )
6901 : {
6902 185 : bNoDataSet = TRUE;
6903 185 : dfNoDataValue = CPLAtofM( pszText );
6904 : }
6905 :
6906 : /* -------------------------------------------------------------------- */
6907 : /* If this is a "base" raster, we should scan for any */
6908 : /* associated overviews, internal mask bands and subdatasets. */
6909 : /* -------------------------------------------------------------------- */
6910 4302 : if( bBase )
6911 : {
6912 : //ScanDirectories();
6913 : }
6914 :
6915 4302 : return( CE_None );
6916 : }
6917 :
6918 : /************************************************************************/
6919 : /* ScanDirectories() */
6920 : /* */
6921 : /* Scan through all the directories finding overviews, masks */
6922 : /* and subdatasets. */
6923 : /************************************************************************/
6924 :
6925 309867 : void GTiffDataset::ScanDirectories()
6926 :
6927 : {
6928 : /* -------------------------------------------------------------------- */
6929 : /* We only scan once. We do not scan for non-base datasets. */
6930 : /* -------------------------------------------------------------------- */
6931 309867 : if( !bScanDeferred )
6932 308527 : return;
6933 :
6934 1340 : bScanDeferred = FALSE;
6935 :
6936 1340 : if( !bBase )
6937 59 : return;
6938 :
6939 1281 : if( TIFFLastDirectory( hTIFF ) )
6940 1143 : return;
6941 :
6942 138 : CPLDebug( "GTiff", "ScanDirectories()" );
6943 :
6944 : /* ==================================================================== */
6945 : /* Scan all directories. */
6946 : /* ==================================================================== */
6947 138 : char **papszSubdatasets = NULL;
6948 138 : int iDirIndex = 0;
6949 :
6950 138 : FlushDirectory();
6951 631 : while( !TIFFLastDirectory( hTIFF )
6952 : && (iDirIndex == 0 || TIFFReadDirectory( hTIFF ) != 0) )
6953 : {
6954 355 : toff_t nThisDir = TIFFCurrentDirOffset(hTIFF);
6955 355 : uint32 nSubType = 0;
6956 :
6957 355 : *ppoActiveDSRef = NULL; // our directory no longer matches this ds
6958 :
6959 355 : iDirIndex++;
6960 :
6961 355 : if( !TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType) )
6962 75 : nSubType = 0;
6963 :
6964 : /* Embedded overview of the main image */
6965 500 : if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
6966 : (nSubType & FILETYPE_MASK) == 0 &&
6967 : iDirIndex != 1 )
6968 : {
6969 : GTiffDataset *poODS;
6970 :
6971 145 : poODS = new GTiffDataset();
6972 290 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
6973 : eAccess ) != CE_None
6974 : || poODS->GetRasterCount() != GetRasterCount() )
6975 : {
6976 0 : delete poODS;
6977 : }
6978 : else
6979 : {
6980 : CPLDebug( "GTiff", "Opened %dx%d overview.\n",
6981 145 : poODS->GetRasterXSize(), poODS->GetRasterYSize());
6982 145 : nOverviewCount++;
6983 : papoOverviewDS = (GTiffDataset **)
6984 : CPLRealloc(papoOverviewDS,
6985 145 : nOverviewCount * (sizeof(void*)));
6986 145 : papoOverviewDS[nOverviewCount-1] = poODS;
6987 145 : poODS->poBaseDS = this;
6988 : }
6989 : }
6990 :
6991 : /* Embedded mask of the main image */
6992 249 : else if ((nSubType & FILETYPE_MASK) != 0 &&
6993 : (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
6994 : poMaskDS == NULL )
6995 : {
6996 39 : poMaskDS = new GTiffDataset();
6997 :
6998 : /* The TIFF6 specification - page 37 - only allows 1 SamplesPerPixel and 1 BitsPerSample
6999 : Here we support either 1 or 8 bit per sample
7000 : and we support either 1 sample per pixel or as many samples as in the main image
7001 : We don't check the value of the PhotometricInterpretation tag, which should be
7002 : set to "Transparency mask" (4) according to the specification (page 36)
7003 : ... But the TIFF6 specification allows image masks to have a higher resolution than
7004 : the main image, what we don't support here
7005 : */
7006 :
7007 78 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir,
7008 : FALSE, eAccess ) != CE_None
7009 : || poMaskDS->GetRasterCount() == 0
7010 : || !(poMaskDS->GetRasterCount() == 1 || poMaskDS->GetRasterCount() == GetRasterCount())
7011 : || poMaskDS->GetRasterXSize() != GetRasterXSize()
7012 : || poMaskDS->GetRasterYSize() != GetRasterYSize()
7013 : || poMaskDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
7014 : {
7015 0 : delete poMaskDS;
7016 0 : poMaskDS = NULL;
7017 : }
7018 : else
7019 : {
7020 39 : CPLDebug( "GTiff", "Opened band mask.\n");
7021 39 : poMaskDS->poBaseDS = this;
7022 :
7023 39 : poMaskDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
7024 : }
7025 : }
7026 :
7027 : /* Embedded mask of an overview */
7028 : /* The TIFF6 specification allows the combination of the FILETYPE_xxxx masks */
7029 203 : else if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
7030 : (nSubType & FILETYPE_MASK) != 0)
7031 : {
7032 32 : GTiffDataset* poDS = new GTiffDataset();
7033 64 : if( poDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
7034 : eAccess ) != CE_None
7035 : || poDS->GetRasterCount() == 0
7036 : || poDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
7037 : {
7038 0 : delete poDS;
7039 : }
7040 : else
7041 : {
7042 : int i;
7043 47 : for(i=0;i<nOverviewCount;i++)
7044 : {
7045 111 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS == NULL &&
7046 32 : poDS->GetRasterXSize() == papoOverviewDS[i]->GetRasterXSize() &&
7047 32 : poDS->GetRasterYSize() == papoOverviewDS[i]->GetRasterYSize() &&
7048 : (poDS->GetRasterCount() == 1 || poDS->GetRasterCount() == GetRasterCount()))
7049 : {
7050 : CPLDebug( "GTiff", "Opened band mask for %dx%d overview.\n",
7051 32 : poDS->GetRasterXSize(), poDS->GetRasterYSize());
7052 32 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS = poDS;
7053 32 : poDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
7054 32 : poDS->poBaseDS = this;
7055 32 : break;
7056 : }
7057 : }
7058 32 : if (i == nOverviewCount)
7059 : {
7060 0 : delete poDS;
7061 : }
7062 : }
7063 : }
7064 139 : else if( nSubType == 0 || nSubType == FILETYPE_PAGE ) {
7065 75 : CPLString osName, osDesc;
7066 : uint32 nXSize, nYSize;
7067 : uint16 nSPP;
7068 :
7069 75 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
7070 75 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
7071 75 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP ) )
7072 0 : nSPP = 1;
7073 :
7074 : osName.Printf( "SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
7075 75 : iDirIndex, iDirIndex, osFilename.c_str() );
7076 : osDesc.Printf( "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
7077 : iDirIndex, iDirIndex,
7078 75 : (int)nXSize, (int)nYSize, nSPP );
7079 :
7080 : papszSubdatasets =
7081 75 : CSLAddString( papszSubdatasets, osName );
7082 : papszSubdatasets =
7083 75 : CSLAddString( papszSubdatasets, osDesc );
7084 : }
7085 :
7086 : // Make sure we are stepping from the expected directory regardless
7087 : // of churn done processing the above.
7088 355 : if( TIFFCurrentDirOffset(hTIFF) != nThisDir )
7089 0 : TIFFSetSubDirectory( hTIFF, nThisDir );
7090 355 : *ppoActiveDSRef = NULL;
7091 : }
7092 :
7093 : /* If we have a mask for the main image, loop over the overviews, and if they */
7094 : /* have a mask, let's set this mask as an overview of the main mask... */
7095 138 : if (poMaskDS != NULL)
7096 : {
7097 : int i;
7098 71 : for(i=0;i<nOverviewCount;i++)
7099 : {
7100 32 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS != NULL)
7101 : {
7102 32 : poMaskDS->nOverviewCount++;
7103 : poMaskDS->papoOverviewDS = (GTiffDataset **)
7104 : CPLRealloc(poMaskDS->papoOverviewDS,
7105 32 : poMaskDS->nOverviewCount * (sizeof(void*)));
7106 32 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] =
7107 32 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS;
7108 : }
7109 : }
7110 : }
7111 :
7112 : /* -------------------------------------------------------------------- */
7113 : /* Only keep track of subdatasets if we have more than one */
7114 : /* subdataset (pair). */
7115 : /* -------------------------------------------------------------------- */
7116 138 : if( CSLCount(papszSubdatasets) > 2 )
7117 : {
7118 1 : oGTiffMDMD.SetMetadata( papszSubdatasets, "SUBDATASETS" );
7119 : }
7120 138 : CSLDestroy( papszSubdatasets );
7121 :
7122 : }
7123 :
7124 :
7125 2434 : static int GTiffGetLZMAPreset(char** papszOptions)
7126 : {
7127 2434 : int nLZMAPreset = -1;
7128 2434 : const char* pszValue = CSLFetchNameValue( papszOptions, "LZMA_PRESET" );
7129 2434 : if( pszValue != NULL )
7130 : {
7131 0 : nLZMAPreset = atoi( pszValue );
7132 0 : if (!(nLZMAPreset >= 0 && nLZMAPreset <= 9))
7133 : {
7134 : CPLError( CE_Warning, CPLE_IllegalArg,
7135 : "LZMA_PRESET=%s value not recognised, ignoring.",
7136 0 : pszValue );
7137 0 : nLZMAPreset = -1;
7138 : }
7139 : }
7140 2434 : return nLZMAPreset;
7141 : }
7142 :
7143 :
7144 2434 : static int GTiffGetZLevel(char** papszOptions)
7145 : {
7146 2434 : int nZLevel = -1;
7147 2434 : const char* pszValue = CSLFetchNameValue( papszOptions, "ZLEVEL" );
7148 2434 : if( pszValue != NULL )
7149 : {
7150 0 : nZLevel = atoi( pszValue );
7151 0 : if (!(nZLevel >= 1 && nZLevel <= 9))
7152 : {
7153 : CPLError( CE_Warning, CPLE_IllegalArg,
7154 : "ZLEVEL=%s value not recognised, ignoring.",
7155 0 : pszValue );
7156 0 : nZLevel = -1;
7157 : }
7158 : }
7159 2434 : return nZLevel;
7160 : }
7161 :
7162 2434 : static int GTiffGetJpegQuality(char** papszOptions)
7163 : {
7164 2434 : int nJpegQuality = -1;
7165 2434 : const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
7166 2434 : if( pszValue != NULL )
7167 : {
7168 28 : nJpegQuality = atoi( pszValue );
7169 28 : if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
7170 : {
7171 : CPLError( CE_Warning, CPLE_IllegalArg,
7172 : "JPEG_QUALITY=%s value not recognised, ignoring.",
7173 0 : pszValue );
7174 0 : nJpegQuality = -1;
7175 : }
7176 : }
7177 2434 : return nJpegQuality;
7178 : }
7179 :
7180 : /************************************************************************/
7181 : /* GTiffCreate() */
7182 : /* */
7183 : /* Shared functionality between GTiffDataset::Create() and */
7184 : /* GTiffCreateCopy() for creating TIFF file based on a set of */
7185 : /* options and a configuration. */
7186 : /************************************************************************/
7187 :
7188 1227 : TIFF *GTiffDataset::CreateLL( const char * pszFilename,
7189 : int nXSize, int nYSize, int nBands,
7190 : GDALDataType eType,
7191 : double dfExtraSpaceForOverviews,
7192 : char **papszParmList )
7193 :
7194 : {
7195 : TIFF *hTIFF;
7196 1227 : int nBlockXSize = 0, nBlockYSize = 0;
7197 1227 : int bTiled = FALSE;
7198 1227 : int nCompression = COMPRESSION_NONE;
7199 1227 : int nPredictor = PREDICTOR_NONE, nJpegQuality = -1, nZLevel = -1,
7200 1227 : nLZMAPreset = -1;
7201 : uint16 nSampleFormat;
7202 : int nPlanar;
7203 : const char *pszValue;
7204 : const char *pszProfile;
7205 1227 : int bCreateBigTIFF = FALSE;
7206 :
7207 1227 : if (!GTiffOneTimeInit())
7208 0 : return NULL;
7209 :
7210 : /* -------------------------------------------------------------------- */
7211 : /* Blow on a few errors. */
7212 : /* -------------------------------------------------------------------- */
7213 1227 : if( nXSize < 1 || nYSize < 1 || nBands < 1 )
7214 : {
7215 : CPLError( CE_Failure, CPLE_AppDefined,
7216 : "Attempt to create %dx%dx%d TIFF file, but width, height and bands\n"
7217 : "must be positive.",
7218 1 : nXSize, nYSize, nBands );
7219 :
7220 1 : return NULL;
7221 : }
7222 :
7223 1226 : if (nBands > 65535)
7224 : {
7225 : CPLError( CE_Failure, CPLE_AppDefined,
7226 : "Attempt to create %dx%dx%d TIFF file, but bands\n"
7227 : "must be lesser or equal to 65535.",
7228 0 : nXSize, nYSize, nBands );
7229 :
7230 0 : return NULL;
7231 : }
7232 :
7233 : /* -------------------------------------------------------------------- */
7234 : /* Setup values based on options. */
7235 : /* -------------------------------------------------------------------- */
7236 1226 : pszProfile = CSLFetchNameValue(papszParmList,"PROFILE");
7237 1226 : if( pszProfile == NULL )
7238 1213 : pszProfile = "GDALGeoTIFF";
7239 :
7240 1226 : if( CSLFetchBoolean( papszParmList, "TILED", FALSE ) )
7241 33 : bTiled = TRUE;
7242 :
7243 1226 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
7244 1226 : if( pszValue != NULL )
7245 17 : nBlockXSize = atoi( pszValue );
7246 :
7247 1226 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
7248 1226 : if( pszValue != NULL )
7249 25 : nBlockYSize = atoi( pszValue );
7250 :
7251 1226 : pszValue = CSLFetchNameValue(papszParmList,"INTERLEAVE");
7252 1226 : if( pszValue != NULL )
7253 : {
7254 28 : if( EQUAL( pszValue, "PIXEL" ) )
7255 13 : nPlanar = PLANARCONFIG_CONTIG;
7256 15 : else if( EQUAL( pszValue, "BAND" ) )
7257 15 : nPlanar = PLANARCONFIG_SEPARATE;
7258 : else
7259 : {
7260 : CPLError( CE_Failure, CPLE_AppDefined,
7261 : "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
7262 0 : pszValue );
7263 0 : return NULL;
7264 : }
7265 : }
7266 : else
7267 : {
7268 1198 : nPlanar = PLANARCONFIG_CONTIG;
7269 : }
7270 :
7271 1226 : pszValue = CSLFetchNameValue( papszParmList, "COMPRESS" );
7272 1226 : if( pszValue != NULL )
7273 : {
7274 68 : nCompression = GTIFFGetCompressionMethod(pszValue, "COMPRESS");
7275 68 : if (nCompression < 0)
7276 0 : return NULL;
7277 : }
7278 :
7279 1226 : pszValue = CSLFetchNameValue( papszParmList, "PREDICTOR" );
7280 1226 : if( pszValue != NULL )
7281 4 : nPredictor = atoi( pszValue );
7282 :
7283 1226 : nZLevel = GTiffGetZLevel(papszParmList);
7284 1226 : nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
7285 1226 : nJpegQuality = GTiffGetJpegQuality(papszParmList);
7286 :
7287 : /* -------------------------------------------------------------------- */
7288 : /* Compute the uncompressed size. */
7289 : /* -------------------------------------------------------------------- */
7290 : double dfUncompressedImageSize;
7291 :
7292 : dfUncompressedImageSize =
7293 1226 : nXSize * ((double)nYSize) * nBands * (GDALGetDataTypeSize(eType)/8);
7294 1226 : dfUncompressedImageSize += dfExtraSpaceForOverviews;
7295 :
7296 1226 : if( nCompression == COMPRESSION_NONE
7297 : && dfUncompressedImageSize > 4200000000.0 )
7298 : {
7299 : #ifndef BIGTIFF_SUPPORT
7300 : CPLError( CE_Failure, CPLE_NotSupported,
7301 : "A %d pixels x %d lines x %d bands %s image would be larger than 4GB\n"
7302 : "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
7303 : "Creation failed.",
7304 : nXSize, nYSize, nBands, GDALGetDataTypeName(eType) );
7305 : return NULL;
7306 : #endif
7307 : }
7308 :
7309 : /* -------------------------------------------------------------------- */
7310 : /* Should the file be created as a bigtiff file? */
7311 : /* -------------------------------------------------------------------- */
7312 1226 : const char *pszBIGTIFF = CSLFetchNameValue(papszParmList, "BIGTIFF");
7313 :
7314 1226 : if( pszBIGTIFF == NULL )
7315 1219 : pszBIGTIFF = "IF_NEEDED";
7316 :
7317 1226 : if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
7318 : {
7319 1220 : if( nCompression == COMPRESSION_NONE
7320 : && dfUncompressedImageSize > 4200000000.0 )
7321 10 : bCreateBigTIFF = TRUE;
7322 : }
7323 6 : else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
7324 : {
7325 4 : if( dfUncompressedImageSize > 2000000000.0 )
7326 1 : bCreateBigTIFF = TRUE;
7327 : }
7328 :
7329 : else
7330 : {
7331 2 : bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
7332 2 : if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE &&
7333 : dfUncompressedImageSize > 4200000000.0 )
7334 : {
7335 : CPLError( CE_Failure, CPLE_NotSupported,
7336 : "The TIFF file will be larger than 4GB, so BigTIFF is necessary.\n"
7337 1 : "Creation failed.");
7338 1 : return NULL;
7339 : }
7340 : }
7341 :
7342 : #ifndef BIGTIFF_SUPPORT
7343 : if( bCreateBigTIFF )
7344 : {
7345 : CPLError( CE_Warning, CPLE_NotSupported,
7346 : "BigTIFF requested, but GDAL built without BigTIFF\n"
7347 : "enabled libtiff, request ignored." );
7348 : bCreateBigTIFF = FALSE;
7349 : }
7350 : #endif
7351 :
7352 1225 : if( bCreateBigTIFF )
7353 12 : CPLDebug( "GTiff", "File being created as a BigTIFF." );
7354 :
7355 : /* -------------------------------------------------------------------- */
7356 : /* Check if the user wishes a particular endianness */
7357 : /* -------------------------------------------------------------------- */
7358 :
7359 1225 : int eEndianness = ENDIANNESS_NATIVE;
7360 1225 : pszValue = CSLFetchNameValue(papszParmList, "ENDIANNESS");
7361 1225 : if ( pszValue == NULL )
7362 1219 : pszValue = CPLGetConfigOption( "GDAL_TIFF_ENDIANNESS", NULL );
7363 1225 : if ( pszValue != NULL )
7364 : {
7365 817 : if (EQUAL(pszValue, "LITTLE"))
7366 6 : eEndianness = ENDIANNESS_LITTLE;
7367 811 : else if (EQUAL(pszValue, "BIG"))
7368 0 : eEndianness = ENDIANNESS_BIG;
7369 811 : else if (EQUAL(pszValue, "INVERTED"))
7370 : {
7371 : #ifdef CPL_LSB
7372 27 : eEndianness = ENDIANNESS_BIG;
7373 : #else
7374 : eEndianness = ENDIANNESS_LITTLE;
7375 : #endif
7376 : }
7377 784 : else if (!EQUAL(pszValue, "NATIVE"))
7378 : {
7379 : CPLError( CE_Warning, CPLE_NotSupported,
7380 0 : "ENDIANNESS=%s not supported. Defaulting to NATIVE", pszValue );
7381 : }
7382 : }
7383 :
7384 : /* -------------------------------------------------------------------- */
7385 : /* Try opening the dataset. */
7386 : /* -------------------------------------------------------------------- */
7387 :
7388 : char szOpeningFlag[5];
7389 1225 : strcpy(szOpeningFlag, "w+");
7390 1225 : if (bCreateBigTIFF)
7391 12 : strcat(szOpeningFlag, "8");
7392 1225 : if (eEndianness == ENDIANNESS_BIG)
7393 27 : strcat(szOpeningFlag, "b");
7394 1198 : else if (eEndianness == ENDIANNESS_LITTLE)
7395 6 : strcat(szOpeningFlag, "l");
7396 1225 : hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag );
7397 1225 : if( hTIFF == NULL )
7398 : {
7399 17 : if( CPLGetLastErrorNo() == 0 )
7400 : CPLError( CE_Failure, CPLE_OpenFailed,
7401 : "Attempt to create new tiff file `%s'\n"
7402 : "failed in XTIFFOpen().\n",
7403 0 : pszFilename );
7404 17 : return NULL;
7405 : }
7406 :
7407 : /* -------------------------------------------------------------------- */
7408 : /* How many bits per sample? We have a special case if NBITS */
7409 : /* specified for GDT_Byte, GDT_UInt16, GDT_UInt32. */
7410 : /* -------------------------------------------------------------------- */
7411 1208 : int nBitsPerSample = GDALGetDataTypeSize(eType);
7412 1208 : if (CSLFetchNameValue(papszParmList, "NBITS") != NULL)
7413 : {
7414 38 : int nMinBits = 0, nMaxBits = 0;
7415 38 : nBitsPerSample = atoi(CSLFetchNameValue(papszParmList, "NBITS"));
7416 38 : if( eType == GDT_Byte )
7417 : {
7418 13 : nMinBits = 1;
7419 13 : nMaxBits = 8;
7420 : }
7421 25 : else if( eType == GDT_UInt16 )
7422 : {
7423 13 : nMinBits = 9;
7424 13 : nMaxBits = 16;
7425 : }
7426 12 : else if( eType == GDT_UInt32 )
7427 : {
7428 12 : nMinBits = 17;
7429 12 : nMaxBits = 32;
7430 : }
7431 : else
7432 : {
7433 : CPLError(CE_Warning, CPLE_NotSupported,
7434 : "NBITS is not supported for data type %s",
7435 0 : GDALGetDataTypeName(eType));
7436 0 : nBitsPerSample = GDALGetDataTypeSize(eType);
7437 : }
7438 :
7439 38 : if (nMinBits != 0)
7440 : {
7441 38 : if (nBitsPerSample < nMinBits)
7442 : {
7443 : CPLError(CE_Warning, CPLE_AppDefined,
7444 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
7445 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMinBits);
7446 0 : nBitsPerSample = nMinBits;
7447 : }
7448 38 : else if (nBitsPerSample > nMaxBits)
7449 : {
7450 : CPLError(CE_Warning, CPLE_AppDefined,
7451 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
7452 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMaxBits);
7453 0 : nBitsPerSample = nMaxBits;
7454 : }
7455 : }
7456 : }
7457 :
7458 : /* -------------------------------------------------------------------- */
7459 : /* Do we have a custom pixel type (just used for signed byte now). */
7460 : /* -------------------------------------------------------------------- */
7461 1208 : const char *pszPixelType = CSLFetchNameValue( papszParmList, "PIXELTYPE" );
7462 1208 : if( pszPixelType == NULL )
7463 1206 : pszPixelType = "";
7464 :
7465 : /* -------------------------------------------------------------------- */
7466 : /* Setup some standard flags. */
7467 : /* -------------------------------------------------------------------- */
7468 1208 : TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
7469 1208 : TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
7470 1208 : TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerSample );
7471 :
7472 1333 : if( (eType == GDT_Byte && EQUAL(pszPixelType,"SIGNEDBYTE"))
7473 : || eType == GDT_Int16 || eType == GDT_Int32 )
7474 125 : nSampleFormat = SAMPLEFORMAT_INT;
7475 1185 : else if( eType == GDT_CInt16 || eType == GDT_CInt32 )
7476 102 : nSampleFormat = SAMPLEFORMAT_COMPLEXINT;
7477 1120 : else if( eType == GDT_Float32 || eType == GDT_Float64 )
7478 139 : nSampleFormat = SAMPLEFORMAT_IEEEFP;
7479 950 : else if( eType == GDT_CFloat32 || eType == GDT_CFloat64 )
7480 108 : nSampleFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
7481 : else
7482 734 : nSampleFormat = SAMPLEFORMAT_UINT;
7483 :
7484 1208 : TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
7485 1208 : TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nBands );
7486 1208 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanar );
7487 :
7488 : /* -------------------------------------------------------------------- */
7489 : /* Setup Photometric Interpretation. Take this value from the user */
7490 : /* passed option or guess correct value otherwise. */
7491 : /* -------------------------------------------------------------------- */
7492 1208 : int nSamplesAccountedFor = 1;
7493 1208 : int bForceColorTable = FALSE;
7494 :
7495 1208 : pszValue = CSLFetchNameValue(papszParmList,"PHOTOMETRIC");
7496 1208 : if( pszValue != NULL )
7497 : {
7498 32 : if( EQUAL( pszValue, "MINISBLACK" ) )
7499 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7500 32 : else if( EQUAL( pszValue, "MINISWHITE" ) )
7501 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE );
7502 30 : else if( EQUAL( pszValue, "PALETTE" ))
7503 : {
7504 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
7505 3 : nSamplesAccountedFor = 1;
7506 3 : bForceColorTable = TRUE;
7507 : }
7508 27 : else if( EQUAL( pszValue, "RGB" ))
7509 : {
7510 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7511 2 : nSamplesAccountedFor = 3;
7512 : }
7513 25 : else if( EQUAL( pszValue, "CMYK" ))
7514 : {
7515 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED );
7516 2 : nSamplesAccountedFor = 4;
7517 : }
7518 23 : else if( EQUAL( pszValue, "YCBCR" ))
7519 : {
7520 : /* Because of subsampling, setting YCBCR without JPEG compression leads */
7521 : /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
7522 : /* aware of subsampling so that it doesn't overrun buffer size returned */
7523 : /* by libtiff */
7524 23 : if ( nCompression != COMPRESSION_JPEG )
7525 : {
7526 : CPLError(CE_Failure, CPLE_NotSupported,
7527 0 : "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
7528 0 : XTIFFClose(hTIFF);
7529 0 : return NULL;
7530 : }
7531 :
7532 23 : if ( nPlanar == PLANARCONFIG_SEPARATE )
7533 : {
7534 : CPLError(CE_Failure, CPLE_NotSupported,
7535 0 : "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
7536 0 : XTIFFClose(hTIFF);
7537 0 : return NULL;
7538 : }
7539 :
7540 : /* YCBCR strictly requires 3 bands. Not less, not more */
7541 : /* Issue an explicit error message as libtiff one is a bit cryptic : */
7542 : /* TIFFVStripSize64:Invalid td_samplesperpixel value */
7543 23 : if ( nBands != 3 )
7544 : {
7545 : CPLError(CE_Failure, CPLE_NotSupported,
7546 0 : "PHOTOMETRIC=YCBCR requires a source raster with only 3 bands (RGB)");
7547 0 : XTIFFClose(hTIFF);
7548 0 : return NULL;
7549 : }
7550 :
7551 23 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR );
7552 23 : nSamplesAccountedFor = 3;
7553 : }
7554 0 : else if( EQUAL( pszValue, "CIELAB" ))
7555 : {
7556 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
7557 0 : nSamplesAccountedFor = 3;
7558 : }
7559 0 : else if( EQUAL( pszValue, "ICCLAB" ))
7560 : {
7561 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ICCLAB );
7562 0 : nSamplesAccountedFor = 3;
7563 : }
7564 0 : else if( EQUAL( pszValue, "ITULAB" ))
7565 : {
7566 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB );
7567 0 : nSamplesAccountedFor = 3;
7568 : }
7569 : else
7570 : {
7571 : CPLError( CE_Warning, CPLE_IllegalArg,
7572 : "PHOTOMETRIC=%s value not recognised, ignoring.\n"
7573 : "Set the Photometric Interpretation as MINISBLACK.",
7574 0 : pszValue );
7575 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7576 : }
7577 :
7578 32 : if ( nBands < nSamplesAccountedFor )
7579 : {
7580 : CPLError( CE_Warning, CPLE_IllegalArg,
7581 : "PHOTOMETRIC=%s value does not correspond to number "
7582 : "of bands (%d), ignoring.\n"
7583 : "Set the Photometric Interpretation as MINISBLACK.",
7584 0 : pszValue, nBands );
7585 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7586 : }
7587 : }
7588 : else
7589 : {
7590 : /*
7591 : * If image contains 3 or 4 bands and datatype is Byte then we will
7592 : * assume it is RGB. In all other cases assume it is MINISBLACK.
7593 : */
7594 1233 : if( nBands == 3 && eType == GDT_Byte )
7595 : {
7596 57 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7597 57 : nSamplesAccountedFor = 3;
7598 : }
7599 1149 : else if( nBands == 4 && eType == GDT_Byte )
7600 : {
7601 : uint16 v[1];
7602 :
7603 : v[0] = GTiffGetAlphaValue(CSLFetchNameValue(papszParmList,"ALPHA"),
7604 30 : DEFAULT_ALPHA_TYPE);
7605 :
7606 30 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
7607 30 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
7608 30 : nSamplesAccountedFor = 4;
7609 : }
7610 : else
7611 : {
7612 1089 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
7613 1089 : nSamplesAccountedFor = 1;
7614 : }
7615 : }
7616 :
7617 : /* -------------------------------------------------------------------- */
7618 : /* If there are extra samples, we need to mark them with an */
7619 : /* appropriate extrasamples definition here. */
7620 : /* -------------------------------------------------------------------- */
7621 1208 : if( nBands > nSamplesAccountedFor )
7622 : {
7623 : uint16 *v;
7624 : int i;
7625 65 : int nExtraSamples = nBands - nSamplesAccountedFor;
7626 :
7627 65 : v = (uint16 *) CPLMalloc( sizeof(uint16) * nExtraSamples );
7628 :
7629 : v[0] = GTiffGetAlphaValue(CSLFetchNameValue(papszParmList, "ALPHA"),
7630 65 : EXTRASAMPLE_UNSPECIFIED);
7631 :
7632 131180 : for( i = 1; i < nExtraSamples; i++ )
7633 131115 : v[i] = EXTRASAMPLE_UNSPECIFIED;
7634 :
7635 65 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, v );
7636 :
7637 65 : CPLFree(v);
7638 : }
7639 :
7640 : /* Set the compression method before asking the default strip size */
7641 : /* This is usefull when translating to a JPEG-In-TIFF file where */
7642 : /* the default strip size is 8 or 16 depending on the photometric value */
7643 1208 : TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompression );
7644 :
7645 : /* -------------------------------------------------------------------- */
7646 : /* Setup tiling/stripping flags. */
7647 : /* -------------------------------------------------------------------- */
7648 1208 : if( bTiled )
7649 : {
7650 33 : if( nBlockXSize == 0 )
7651 17 : nBlockXSize = 256;
7652 :
7653 33 : if( nBlockYSize == 0 )
7654 17 : nBlockYSize = 256;
7655 :
7656 33 : if (!TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ) ||
7657 : !TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ))
7658 : {
7659 0 : XTIFFClose(hTIFF);
7660 0 : return NULL;
7661 : }
7662 : }
7663 : else
7664 : {
7665 : uint32 nRowsPerStrip;
7666 :
7667 1175 : if( nBlockYSize == 0 )
7668 1166 : nRowsPerStrip = MIN(nYSize, (int)TIFFDefaultStripSize(hTIFF,0));
7669 : else
7670 9 : nRowsPerStrip = nBlockYSize;
7671 :
7672 1175 : TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nRowsPerStrip );
7673 : }
7674 :
7675 : /* -------------------------------------------------------------------- */
7676 : /* Set compression related tags. */
7677 : /* -------------------------------------------------------------------- */
7678 1208 : if ( nCompression == COMPRESSION_LZW ||
7679 : nCompression == COMPRESSION_ADOBE_DEFLATE )
7680 29 : TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor );
7681 1208 : if (nCompression == COMPRESSION_ADOBE_DEFLATE
7682 : && nZLevel != -1)
7683 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
7684 1222 : else if( nCompression == COMPRESSION_JPEG
7685 : && nJpegQuality != -1 )
7686 14 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
7687 1194 : else if( nCompression == COMPRESSION_LZMA && nLZMAPreset != -1)
7688 0 : TIFFSetField( hTIFF, TIFFTAG_LZMAPRESET, nLZMAPreset );
7689 :
7690 : /* -------------------------------------------------------------------- */
7691 : /* If we forced production of a file with photometric=palette, */
7692 : /* we need to push out a default color table. */
7693 : /* -------------------------------------------------------------------- */
7694 1208 : if( bForceColorTable )
7695 : {
7696 : int nColors;
7697 :
7698 3 : if( eType == GDT_Byte )
7699 3 : nColors = 256;
7700 : else
7701 0 : nColors = 65536;
7702 :
7703 : unsigned short *panTRed, *panTGreen, *panTBlue;
7704 :
7705 3 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7706 3 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7707 3 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
7708 :
7709 771 : for( int iColor = 0; iColor < nColors; iColor++ )
7710 : {
7711 768 : if( eType == GDT_Byte )
7712 : {
7713 768 : panTRed[iColor] = (unsigned short) (257 * iColor);
7714 768 : panTGreen[iColor] = (unsigned short) (257 * iColor);
7715 768 : panTBlue[iColor] = (unsigned short) (257 * iColor);
7716 : }
7717 : else
7718 : {
7719 0 : panTRed[iColor] = (unsigned short) iColor;
7720 0 : panTGreen[iColor] = (unsigned short) iColor;
7721 0 : panTBlue[iColor] = (unsigned short) iColor;
7722 : }
7723 : }
7724 :
7725 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
7726 3 : panTRed, panTGreen, panTBlue );
7727 :
7728 3 : CPLFree( panTRed );
7729 3 : CPLFree( panTGreen );
7730 3 : CPLFree( panTBlue );
7731 : }
7732 :
7733 1208 : return( hTIFF );
7734 : }
7735 :
7736 : /************************************************************************/
7737 : /* Create() */
7738 : /* */
7739 : /* Create a new GeoTIFF or TIFF file. */
7740 : /************************************************************************/
7741 :
7742 978 : GDALDataset *GTiffDataset::Create( const char * pszFilename,
7743 : int nXSize, int nYSize, int nBands,
7744 : GDALDataType eType,
7745 : char **papszParmList )
7746 :
7747 : {
7748 : GTiffDataset * poDS;
7749 : TIFF *hTIFF;
7750 :
7751 : /* -------------------------------------------------------------------- */
7752 : /* Create the underlying TIFF file. */
7753 : /* -------------------------------------------------------------------- */
7754 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
7755 978 : eType, 0, papszParmList );
7756 :
7757 978 : if( hTIFF == NULL )
7758 2 : return NULL;
7759 :
7760 : /* -------------------------------------------------------------------- */
7761 : /* Create the new GTiffDataset object. */
7762 : /* -------------------------------------------------------------------- */
7763 976 : poDS = new GTiffDataset();
7764 976 : poDS->hTIFF = hTIFF;
7765 976 : poDS->poActiveDS = poDS;
7766 976 : poDS->ppoActiveDSRef = &(poDS->poActiveDS);
7767 :
7768 976 : poDS->nRasterXSize = nXSize;
7769 976 : poDS->nRasterYSize = nYSize;
7770 976 : poDS->eAccess = GA_Update;
7771 976 : poDS->bCrystalized = FALSE;
7772 976 : poDS->nSamplesPerPixel = (uint16) nBands;
7773 1952 : poDS->osFilename = pszFilename;
7774 :
7775 : /* Avoid premature crystalization that will cause directory re-writting */
7776 : /* if GetProjectionRef() or GetGeoTransform() are called on the newly created GeoTIFF */
7777 976 : poDS->bLookedForProjection = TRUE;
7778 :
7779 976 : TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->nSampleFormat) );
7780 976 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->nPlanarConfig) );
7781 976 : TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) );
7782 976 : TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->nBitsPerSample) );
7783 976 : TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(poDS->nCompression) );
7784 :
7785 976 : if( TIFFIsTiled(hTIFF) )
7786 : {
7787 23 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(poDS->nBlockXSize) );
7788 23 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(poDS->nBlockYSize) );
7789 : }
7790 : else
7791 : {
7792 953 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
7793 : &(poDS->nRowsPerStrip) ) )
7794 0 : poDS->nRowsPerStrip = 1; /* dummy value */
7795 :
7796 953 : poDS->nBlockXSize = nXSize;
7797 953 : poDS->nBlockYSize = MIN((int)poDS->nRowsPerStrip,nYSize);
7798 : }
7799 :
7800 : poDS->nBlocksPerBand =
7801 : DIV_ROUND_UP(nYSize, poDS->nBlockYSize)
7802 976 : * DIV_ROUND_UP(nXSize, poDS->nBlockXSize);
7803 :
7804 976 : if( CSLFetchNameValue( papszParmList, "PROFILE" ) != NULL )
7805 4 : poDS->osProfile = CSLFetchNameValue( papszParmList, "PROFILE" );
7806 :
7807 : /* -------------------------------------------------------------------- */
7808 : /* YCbCr JPEG compressed images should be translated on the fly */
7809 : /* to RGB by libtiff/libjpeg unless specifically requested */
7810 : /* otherwise. */
7811 : /* -------------------------------------------------------------------- */
7812 976 : if( poDS->nCompression == COMPRESSION_JPEG
7813 : && poDS->nPhotometric == PHOTOMETRIC_YCBCR
7814 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
7815 : "YES") ) )
7816 : {
7817 : int nColorMode;
7818 :
7819 13 : poDS->SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
7820 13 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
7821 : nColorMode != JPEGCOLORMODE_RGB )
7822 13 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
7823 : }
7824 :
7825 : /* -------------------------------------------------------------------- */
7826 : /* Read palette back as a color table if it has one. */
7827 : /* -------------------------------------------------------------------- */
7828 : unsigned short *panRed, *panGreen, *panBlue;
7829 :
7830 976 : if( poDS->nPhotometric == PHOTOMETRIC_PALETTE
7831 : && TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
7832 : &panRed, &panGreen, &panBlue) )
7833 : {
7834 : int nColorCount;
7835 : GDALColorEntry oEntry;
7836 :
7837 3 : poDS->poColorTable = new GDALColorTable();
7838 :
7839 3 : nColorCount = 1 << poDS->nBitsPerSample;
7840 :
7841 771 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
7842 : {
7843 768 : oEntry.c1 = panRed[iColor] / 256;
7844 768 : oEntry.c2 = panGreen[iColor] / 256;
7845 768 : oEntry.c3 = panBlue[iColor] / 256;
7846 768 : oEntry.c4 = 255;
7847 :
7848 768 : poDS->poColorTable->SetColorEntry( iColor, &oEntry );
7849 : }
7850 : }
7851 :
7852 : /* -------------------------------------------------------------------- */
7853 : /* Do we want to ensure all blocks get written out on close to */
7854 : /* avoid sparse files? */
7855 : /* -------------------------------------------------------------------- */
7856 976 : if( !CSLFetchBoolean( papszParmList, "SPARSE_OK", FALSE ) )
7857 958 : poDS->bFillEmptyTiles = TRUE;
7858 :
7859 : /* -------------------------------------------------------------------- */
7860 : /* Preserve creation options for consulting later (for instance */
7861 : /* to decide if a TFW file should be written). */
7862 : /* -------------------------------------------------------------------- */
7863 976 : poDS->papszCreationOptions = CSLDuplicate( papszParmList );
7864 :
7865 976 : poDS->nZLevel = GTiffGetZLevel(papszParmList);
7866 976 : poDS->nLZMAPreset = GTiffGetLZMAPreset(papszParmList);
7867 976 : poDS->nJpegQuality = GTiffGetJpegQuality(papszParmList);
7868 :
7869 : #if !defined(BIGTIFF_SUPPORT)
7870 : /* -------------------------------------------------------------------- */
7871 : /* If we are writing jpeg compression we need to write some */
7872 : /* imagery to force the jpegtables to get created. This is, */
7873 : /* likely only needed with libtiff >= 3.9.3 (#3633) */
7874 : /* -------------------------------------------------------------------- */
7875 : if( poDS->nCompression == COMPRESSION_JPEG
7876 : && strstr(TIFFLIB_VERSION_STR, "Version 3.9") != NULL )
7877 : {
7878 : CPLDebug( "GDAL",
7879 : "Writing zero block to force creation of JPEG tables." );
7880 : if( TIFFIsTiled( hTIFF ) )
7881 : {
7882 : int cc = TIFFTileSize( hTIFF );
7883 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
7884 : TIFFWriteEncodedTile(hTIFF, 0, pabyZeros, cc);
7885 : CPLFree( pabyZeros );
7886 : }
7887 : else
7888 : {
7889 : int cc = TIFFStripSize( hTIFF );
7890 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
7891 : TIFFWriteEncodedStrip(hTIFF, 0, pabyZeros, cc);
7892 : CPLFree( pabyZeros );
7893 : }
7894 : poDS->bDontReloadFirstBlock = TRUE;
7895 : }
7896 : #endif
7897 :
7898 : /* -------------------------------------------------------------------- */
7899 : /* Create band information objects. */
7900 : /* -------------------------------------------------------------------- */
7901 : int iBand;
7902 :
7903 133259 : for( iBand = 0; iBand < nBands; iBand++ )
7904 : {
7905 264543 : if( poDS->nBitsPerSample == 8 ||
7906 : poDS->nBitsPerSample == 16 ||
7907 : poDS->nBitsPerSample == 32 ||
7908 : poDS->nBitsPerSample == 64 ||
7909 : poDS->nBitsPerSample == 128)
7910 132260 : poDS->SetBand( iBand+1, new GTiffRasterBand( poDS, iBand+1 ) );
7911 : else
7912 : {
7913 23 : poDS->SetBand( iBand+1, new GTiffOddBitsBand( poDS, iBand+1 ) );
7914 : poDS->GetRasterBand( iBand+1 )->
7915 : SetMetadataItem( "NBITS",
7916 : CPLString().Printf("%d",poDS->nBitsPerSample),
7917 46 : "IMAGE_STRUCTURE" );
7918 : }
7919 : }
7920 :
7921 976 : poDS->oOvManager.Initialize( poDS, pszFilename );
7922 :
7923 976 : return( poDS );
7924 : }
7925 :
7926 : /************************************************************************/
7927 : /* CreateCopy() */
7928 : /************************************************************************/
7929 :
7930 : GDALDataset *
7931 250 : GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
7932 : int bStrict, char ** papszOptions,
7933 : GDALProgressFunc pfnProgress, void * pProgressData )
7934 :
7935 : {
7936 : TIFF *hTIFF;
7937 250 : int nXSize = poSrcDS->GetRasterXSize();
7938 250 : int nYSize = poSrcDS->GetRasterYSize();
7939 250 : int nBands = poSrcDS->GetRasterCount();
7940 : int iBand;
7941 250 : CPLErr eErr = CE_None;
7942 : uint16 nPlanarConfig;
7943 : uint16 nBitsPerSample;
7944 : GDALRasterBand *poPBand;
7945 :
7946 250 : if( poSrcDS->GetRasterCount() == 0 )
7947 : {
7948 : CPLError( CE_Failure, CPLE_AppDefined,
7949 1 : "Unable to export GeoTIFF files with zero bands." );
7950 1 : return NULL;
7951 : }
7952 :
7953 249 : poPBand = poSrcDS->GetRasterBand(1);
7954 249 : GDALDataType eType = poPBand->GetRasterDataType();
7955 :
7956 : /* -------------------------------------------------------------------- */
7957 : /* Check, whether all bands in input dataset has the same type. */
7958 : /* -------------------------------------------------------------------- */
7959 392 : for ( iBand = 2; iBand <= nBands; iBand++ )
7960 : {
7961 143 : if ( eType != poSrcDS->GetRasterBand(iBand)->GetRasterDataType() )
7962 : {
7963 0 : if ( bStrict )
7964 : {
7965 : CPLError( CE_Failure, CPLE_AppDefined,
7966 : "Unable to export GeoTIFF file with different datatypes per\n"
7967 0 : "different bands. All bands should have the same types in TIFF." );
7968 0 : return NULL;
7969 : }
7970 : else
7971 : {
7972 : CPLError( CE_Warning, CPLE_AppDefined,
7973 : "Unable to export GeoTIFF file with different datatypes per\n"
7974 0 : "different bands. All bands should have the same types in TIFF." );
7975 : }
7976 : }
7977 : }
7978 :
7979 249 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
7980 0 : return NULL;
7981 :
7982 : /* -------------------------------------------------------------------- */
7983 : /* Capture the profile. */
7984 : /* -------------------------------------------------------------------- */
7985 : const char *pszProfile;
7986 : int bGeoTIFF;
7987 :
7988 249 : pszProfile = CSLFetchNameValue(papszOptions,"PROFILE");
7989 249 : if( pszProfile == NULL )
7990 240 : pszProfile = "GDALGeoTIFF";
7991 :
7992 249 : if( !EQUAL(pszProfile,"BASELINE")
7993 : && !EQUAL(pszProfile,"GeoTIFF")
7994 : && !EQUAL(pszProfile,"GDALGeoTIFF") )
7995 : {
7996 : CPLError( CE_Failure, CPLE_AppDefined,
7997 : "PROFILE=%s not supported in GTIFF driver.",
7998 0 : pszProfile );
7999 0 : return NULL;
8000 : }
8001 :
8002 249 : if( EQUAL(pszProfile,"BASELINE") )
8003 6 : bGeoTIFF = FALSE;
8004 : else
8005 243 : bGeoTIFF = TRUE;
8006 :
8007 : /* -------------------------------------------------------------------- */
8008 : /* Special handling for NBITS. Copy from band metadata if found. */
8009 : /* -------------------------------------------------------------------- */
8010 249 : char **papszCreateOptions = CSLDuplicate( papszOptions );
8011 :
8012 254 : if( poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
8013 5 : && atoi(poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) > 0
8014 : && CSLFetchNameValue( papszCreateOptions, "NBITS") == NULL )
8015 : {
8016 : papszCreateOptions =
8017 : CSLSetNameValue( papszCreateOptions, "NBITS",
8018 : poPBand->GetMetadataItem( "NBITS",
8019 3 : "IMAGE_STRUCTURE" ) );
8020 : }
8021 :
8022 407 : if( CSLFetchNameValue( papszOptions, "PIXELTYPE" ) == NULL
8023 : && eType == GDT_Byte
8024 158 : && poPBand->GetMetadataItem( "PIXELTYPE", "IMAGE_STRUCTURE" ) )
8025 : {
8026 : papszCreateOptions =
8027 : CSLSetNameValue( papszCreateOptions, "PIXELTYPE",
8028 : poPBand->GetMetadataItem(
8029 0 : "PIXELTYPE", "IMAGE_STRUCTURE" ) );
8030 : }
8031 :
8032 249 : int nSrcOverviews = poSrcDS->GetRasterBand(1)->GetOverviewCount();
8033 249 : double dfExtraSpaceForOverviews = 0;
8034 249 : if (nSrcOverviews != 0 &&
8035 : CSLFetchBoolean(papszOptions, "COPY_SRC_OVERVIEWS", FALSE))
8036 : {
8037 : int i;
8038 18 : for(i=0;i<nSrcOverviews;i++)
8039 : {
8040 13 : dfExtraSpaceForOverviews += ((double)poSrcDS->GetRasterBand(1)->GetOverview(i)->GetXSize()) *
8041 26 : poSrcDS->GetRasterBand(1)->GetOverview(i)->GetYSize();
8042 : }
8043 5 : dfExtraSpaceForOverviews *= nBands * (GDALGetDataTypeSize(eType) / 8);
8044 : }
8045 :
8046 : /* -------------------------------------------------------------------- */
8047 : /* Should we use optimized way of copying from an input JPEG */
8048 : /* dataset ? */
8049 : /* -------------------------------------------------------------------- */
8050 249 : int bCopyFromJPEG = FALSE;
8051 249 : int bDirectCopyFromJPEG = FALSE;
8052 :
8053 : /* Note: JPEG_DIRECT_COPY is not defined by default, because it is mainly */
8054 : /* usefull for debugging purposes */
8055 : #ifdef JPEG_DIRECT_COPY
8056 : if (CSLFetchBoolean(papszCreateOptions, "JPEG_DIRECT_COPY", FALSE) &&
8057 : GTIFF_CanDirectCopyFromJPEG(poSrcDS, papszCreateOptions))
8058 : {
8059 : CPLDebug("GTiff", "Using special direct copy mode from a JPEG dataset");
8060 :
8061 : bDirectCopyFromJPEG = TRUE;
8062 : }
8063 : #endif
8064 :
8065 : #ifdef HAVE_LIBJPEG
8066 : /* when CreateCopy'ing() from a JPEG dataset, and asking for COMPRESS=JPEG, */
8067 : /* use DCT coefficients (unless other options are incompatible, like strip/tile dimensions, */
8068 : /* specifying JPEG_QUALITY option, incompatible PHOTOMETRIC with the source colorspace, etc...) */
8069 : /* to avoid the lossy steps involved by uncompression/recompression */
8070 249 : if (!bDirectCopyFromJPEG && GTIFF_CanCopyFromJPEG(poSrcDS, papszCreateOptions))
8071 : {
8072 8 : CPLDebug("GTiff", "Using special copy mode from a JPEG dataset");
8073 :
8074 8 : bCopyFromJPEG = TRUE;
8075 : }
8076 : #endif
8077 :
8078 : /* -------------------------------------------------------------------- */
8079 : /* Create the file. */
8080 : /* -------------------------------------------------------------------- */
8081 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
8082 249 : eType, dfExtraSpaceForOverviews, papszCreateOptions );
8083 :
8084 249 : CSLDestroy( papszCreateOptions );
8085 :
8086 249 : if( hTIFF == NULL )
8087 17 : return NULL;
8088 :
8089 232 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
8090 232 : TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample );
8091 :
8092 : /* -------------------------------------------------------------------- */
8093 : /* Are we really producing an RGBA image? If so, set the */
8094 : /* associated alpha information. */
8095 : /* -------------------------------------------------------------------- */
8096 : int bForcePhotometric =
8097 232 : CSLFetchNameValue(papszOptions,"PHOTOMETRIC") != NULL;
8098 :
8099 239 : if( nBands == 4 && !bForcePhotometric
8100 7 : && poSrcDS->GetRasterBand(4)->GetColorInterpretation()==GCI_AlphaBand)
8101 : {
8102 : uint16 v[1];
8103 :
8104 : v[0] = GTiffGetAlphaValue(CSLFetchNameValue(papszOptions, "ALPHA"),
8105 5 : DEFAULT_ALPHA_TYPE);
8106 :
8107 5 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
8108 5 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
8109 : }
8110 :
8111 : /* -------------------------------------------------------------------- */
8112 : /* If the output is jpeg compressed, and the input is RGB make */
8113 : /* sure we note that. */
8114 : /* -------------------------------------------------------------------- */
8115 : uint16 nCompression;
8116 :
8117 232 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
8118 0 : nCompression = COMPRESSION_NONE;
8119 :
8120 232 : if( nCompression == COMPRESSION_JPEG )
8121 : {
8122 35 : if( nBands >= 3
8123 15 : && (poSrcDS->GetRasterBand(1)->GetColorInterpretation()
8124 : == GCI_YCbCr_YBand)
8125 0 : && (poSrcDS->GetRasterBand(2)->GetColorInterpretation()
8126 : == GCI_YCbCr_CbBand)
8127 0 : && (poSrcDS->GetRasterBand(3)->GetColorInterpretation()
8128 : == GCI_YCbCr_CrBand) )
8129 : {
8130 : /* do nothing ... */
8131 : }
8132 : else
8133 : {
8134 : /* we assume RGB if it isn't explicitly YCbCr */
8135 20 : CPLDebug( "GTiff", "Setting JPEGCOLORMODE_RGB" );
8136 20 : TIFFSetField( hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
8137 : }
8138 : }
8139 :
8140 : /* -------------------------------------------------------------------- */
8141 : /* Does the source image consist of one band, with a palette? */
8142 : /* If so, copy over. */
8143 : /* -------------------------------------------------------------------- */
8144 232 : if( (nBands == 1 || nBands == 2) && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
8145 : && eType == GDT_Byte )
8146 : {
8147 : unsigned short anTRed[256], anTGreen[256], anTBlue[256];
8148 : GDALColorTable *poCT;
8149 :
8150 4 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
8151 :
8152 1028 : for( int iColor = 0; iColor < 256; iColor++ )
8153 : {
8154 1024 : if( iColor < poCT->GetColorEntryCount() )
8155 : {
8156 : GDALColorEntry sRGB;
8157 :
8158 477 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
8159 :
8160 477 : anTRed[iColor] = (unsigned short) (257 * sRGB.c1);
8161 477 : anTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
8162 477 : anTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
8163 : }
8164 : else
8165 : {
8166 547 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
8167 : }
8168 : }
8169 :
8170 4 : if( !bForcePhotometric )
8171 4 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
8172 4 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, anTRed, anTGreen, anTBlue );
8173 : }
8174 399 : else if( (nBands == 1 || nBands == 2)
8175 171 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
8176 : && eType == GDT_UInt16 )
8177 : {
8178 : unsigned short *panTRed, *panTGreen, *panTBlue;
8179 : GDALColorTable *poCT;
8180 :
8181 1 : panTRed = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
8182 1 : panTGreen = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
8183 1 : panTBlue = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
8184 :
8185 1 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
8186 :
8187 65537 : for( int iColor = 0; iColor < 65536; iColor++ )
8188 : {
8189 65536 : if( iColor < poCT->GetColorEntryCount() )
8190 : {
8191 : GDALColorEntry sRGB;
8192 :
8193 65536 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
8194 :
8195 65536 : panTRed[iColor] = (unsigned short) (256 * sRGB.c1);
8196 65536 : panTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
8197 65536 : panTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
8198 : }
8199 : else
8200 : {
8201 0 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
8202 : }
8203 : }
8204 :
8205 1 : if( !bForcePhotometric )
8206 1 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
8207 1 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue );
8208 :
8209 1 : CPLFree( panTRed );
8210 1 : CPLFree( panTGreen );
8211 1 : CPLFree( panTBlue );
8212 : }
8213 227 : else if( poSrcDS->GetRasterBand(1)->GetColorTable() != NULL )
8214 : CPLError( CE_Warning, CPLE_AppDefined,
8215 : "Unable to export color table to GeoTIFF file. Color tables\n"
8216 0 : "can only be written to 1 band or 2 bands Byte or UInt16 GeoTIFF files." );
8217 :
8218 238 : if( nBands == 2
8219 6 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
8220 : && (eType == GDT_Byte || eType == GDT_UInt16) )
8221 : {
8222 1 : uint16 v[1] = { EXTRASAMPLE_UNASSALPHA };
8223 :
8224 1 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v );
8225 : }
8226 :
8227 : /* -------------------------------------------------------------------- */
8228 : /* Transfer some TIFF specific metadata, if available. */
8229 : /* The return value will tell us if we need to try again later with*/
8230 : /* PAM because the profile doesn't allow to write some metadata */
8231 : /* as TIFF tag */
8232 : /* -------------------------------------------------------------------- */
8233 : int bHasWrittenMDInGeotiffTAG =
8234 : GTiffDataset::WriteMetadata( poSrcDS, hTIFF, FALSE, pszProfile,
8235 232 : pszFilename, papszOptions );
8236 :
8237 : /* -------------------------------------------------------------------- */
8238 : /* Write NoData value, if exist. */
8239 : /* -------------------------------------------------------------------- */
8240 232 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
8241 : {
8242 : int bSuccess;
8243 : double dfNoData;
8244 :
8245 224 : dfNoData = poSrcDS->GetRasterBand(1)->GetNoDataValue( &bSuccess );
8246 224 : if ( bSuccess )
8247 29 : GTiffDataset::WriteNoDataValue( hTIFF, dfNoData );
8248 : }
8249 :
8250 : /* -------------------------------------------------------------------- */
8251 : /* Are we addressing PixelIsPoint mode? */
8252 : /* -------------------------------------------------------------------- */
8253 232 : bool bPixelIsPoint = false;
8254 232 : int bPointGeoIgnore = FALSE;
8255 :
8256 353 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
8257 121 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
8258 : GDALMD_AOP_POINT) )
8259 : {
8260 6 : bPixelIsPoint = true;
8261 : bPointGeoIgnore =
8262 : CSLTestBoolean( CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE",
8263 6 : "FALSE") );
8264 : }
8265 :
8266 : /* -------------------------------------------------------------------- */
8267 : /* Write affine transform if it is meaningful. */
8268 : /* -------------------------------------------------------------------- */
8269 232 : const char *pszProjection = NULL;
8270 : double adfGeoTransform[6];
8271 :
8272 412 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
8273 164 : && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
8274 16 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
8275 0 : || adfGeoTransform[4] != 0.0 || adfGeoTransform[5] != 1.0 ))
8276 : {
8277 156 : if( bGeoTIFF )
8278 : {
8279 452 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
8280 150 : && adfGeoTransform[5] < 0.0 )
8281 : {
8282 :
8283 : double adfPixelScale[3], adfTiePoints[6];
8284 :
8285 150 : adfPixelScale[0] = adfGeoTransform[1];
8286 150 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
8287 150 : adfPixelScale[2] = 0.0;
8288 :
8289 150 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
8290 :
8291 150 : adfTiePoints[0] = 0.0;
8292 150 : adfTiePoints[1] = 0.0;
8293 150 : adfTiePoints[2] = 0.0;
8294 150 : adfTiePoints[3] = adfGeoTransform[0];
8295 150 : adfTiePoints[4] = adfGeoTransform[3];
8296 150 : adfTiePoints[5] = 0.0;
8297 :
8298 150 : if( bPixelIsPoint && !bPointGeoIgnore )
8299 : {
8300 4 : adfTiePoints[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
8301 4 : adfTiePoints[4] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
8302 : }
8303 :
8304 150 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
8305 : }
8306 : else
8307 : {
8308 : double adfMatrix[16];
8309 :
8310 2 : memset(adfMatrix,0,sizeof(double) * 16);
8311 :
8312 2 : adfMatrix[0] = adfGeoTransform[1];
8313 2 : adfMatrix[1] = adfGeoTransform[2];
8314 2 : adfMatrix[3] = adfGeoTransform[0];
8315 2 : adfMatrix[4] = adfGeoTransform[4];
8316 2 : adfMatrix[5] = adfGeoTransform[5];
8317 2 : adfMatrix[7] = adfGeoTransform[3];
8318 2 : adfMatrix[15] = 1.0;
8319 :
8320 2 : if( bPixelIsPoint && !bPointGeoIgnore )
8321 : {
8322 0 : adfMatrix[3] += adfGeoTransform[1] * 0.5 + adfGeoTransform[2] * 0.5;
8323 0 : adfMatrix[7] += adfGeoTransform[4] * 0.5 + adfGeoTransform[5] * 0.5;
8324 : }
8325 :
8326 2 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
8327 : }
8328 :
8329 152 : pszProjection = poSrcDS->GetProjectionRef();
8330 : }
8331 :
8332 : /* -------------------------------------------------------------------- */
8333 : /* Do we need a TFW file? */
8334 : /* -------------------------------------------------------------------- */
8335 156 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE ) )
8336 1 : GDALWriteWorldFile( pszFilename, "tfw", adfGeoTransform );
8337 155 : else if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
8338 1 : GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
8339 : }
8340 :
8341 : /* -------------------------------------------------------------------- */
8342 : /* Otherwise write tiepoints if they are available. */
8343 : /* -------------------------------------------------------------------- */
8344 76 : else if( poSrcDS->GetGCPCount() > 0 && bGeoTIFF )
8345 : {
8346 3 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
8347 : double *padfTiePoints;
8348 :
8349 : padfTiePoints = (double *)
8350 3 : CPLMalloc(6*sizeof(double)*poSrcDS->GetGCPCount());
8351 :
8352 15 : for( int iGCP = 0; iGCP < poSrcDS->GetGCPCount(); iGCP++ )
8353 : {
8354 :
8355 12 : padfTiePoints[iGCP*6+0] = pasGCPs[iGCP].dfGCPPixel;
8356 12 : padfTiePoints[iGCP*6+1] = pasGCPs[iGCP].dfGCPLine;
8357 12 : padfTiePoints[iGCP*6+2] = 0;
8358 12 : padfTiePoints[iGCP*6+3] = pasGCPs[iGCP].dfGCPX;
8359 12 : padfTiePoints[iGCP*6+4] = pasGCPs[iGCP].dfGCPY;
8360 12 : padfTiePoints[iGCP*6+5] = pasGCPs[iGCP].dfGCPZ;
8361 :
8362 12 : if( bPixelIsPoint && !bPointGeoIgnore )
8363 : {
8364 0 : padfTiePoints[iGCP*6+0] += 0.5;
8365 0 : padfTiePoints[iGCP*6+1] += 0.5;
8366 : }
8367 : }
8368 :
8369 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
8370 3 : 6*poSrcDS->GetGCPCount(), padfTiePoints );
8371 3 : CPLFree( padfTiePoints );
8372 :
8373 3 : pszProjection = poSrcDS->GetGCPProjection();
8374 :
8375 3 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE )
8376 : || CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
8377 : {
8378 : CPLError(CE_Warning, CPLE_AppDefined,
8379 0 : "TFW=ON or WORLDFILE=ON creation options are ignored when GCPs are available");
8380 : }
8381 : }
8382 :
8383 : else
8384 73 : pszProjection = poSrcDS->GetProjectionRef();
8385 :
8386 : /* -------------------------------------------------------------------- */
8387 : /* Write the projection information, if possible. */
8388 : /* -------------------------------------------------------------------- */
8389 232 : if( pszProjection != NULL && strlen(pszProjection) > 0 && bGeoTIFF )
8390 : {
8391 : GTIF *psGTIF;
8392 :
8393 153 : psGTIF = GTIFNew( hTIFF );
8394 153 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
8395 :
8396 271 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
8397 118 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
8398 : GDALMD_AOP_POINT) )
8399 : {
8400 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
8401 6 : RasterPixelIsPoint);
8402 : }
8403 :
8404 153 : GTIFWriteKeys( psGTIF );
8405 153 : GTIFFree( psGTIF );
8406 : }
8407 :
8408 232 : int bDontReloadFirstBlock = FALSE;
8409 :
8410 : #ifdef HAVE_LIBJPEG
8411 232 : if (bCopyFromJPEG)
8412 : {
8413 : GTIFF_CopyFromJPEG_WriteAdditionalTags(hTIFF,
8414 8 : poSrcDS);
8415 : }
8416 : #else
8417 : if (0)
8418 : {
8419 : }
8420 : #endif
8421 :
8422 : #if !defined(BIGTIFF_SUPPORT)
8423 : /* -------------------------------------------------------------------- */
8424 : /* If we are writing jpeg compression we need to write some */
8425 : /* imagery to force the jpegtables to get created. This is, */
8426 : /* likely only needed with libtiff >= 3.9.3 (#3633) */
8427 : /* -------------------------------------------------------------------- */
8428 : else if( nCompression == COMPRESSION_JPEG
8429 : && strstr(TIFFLIB_VERSION_STR, "Version 3.9") != NULL )
8430 : {
8431 : CPLDebug( "GDAL",
8432 : "Writing zero block to force creation of JPEG tables." );
8433 : if( TIFFIsTiled( hTIFF ) )
8434 : {
8435 : int cc = TIFFTileSize( hTIFF );
8436 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
8437 : TIFFWriteEncodedTile(hTIFF, 0, pabyZeros, cc);
8438 : CPLFree( pabyZeros );
8439 : }
8440 : else
8441 : {
8442 : int cc = TIFFStripSize( hTIFF );
8443 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
8444 : TIFFWriteEncodedStrip(hTIFF, 0, pabyZeros, cc);
8445 : CPLFree( pabyZeros );
8446 : }
8447 : bDontReloadFirstBlock = TRUE;
8448 : }
8449 : #endif
8450 :
8451 : /* -------------------------------------------------------------------- */
8452 : /* Cleanup */
8453 : /* -------------------------------------------------------------------- */
8454 :
8455 232 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffCreateCopy()");
8456 232 : TIFFWriteDirectory( hTIFF );
8457 232 : TIFFFlush( hTIFF );
8458 232 : XTIFFClose( hTIFF );
8459 232 : hTIFF = NULL;
8460 :
8461 232 : if( eErr != CE_None )
8462 : {
8463 0 : VSIUnlink( pszFilename );
8464 0 : return NULL;
8465 : }
8466 :
8467 : /* -------------------------------------------------------------------- */
8468 : /* Re-open as a dataset and copy over missing metadata using */
8469 : /* PAM facilities. */
8470 : /* -------------------------------------------------------------------- */
8471 : GTiffDataset *poDS;
8472 232 : CPLString osFileName("GTIFF_RAW:");
8473 :
8474 232 : osFileName += pszFilename;
8475 :
8476 232 : GDALOpenInfo oOpenInfo( osFileName, GA_Update );
8477 232 : poDS = (GTiffDataset *) Open(&oOpenInfo);
8478 232 : if( poDS == NULL )
8479 : {
8480 0 : oOpenInfo.eAccess = GA_ReadOnly;
8481 0 : poDS = (GTiffDataset *) Open(&oOpenInfo);
8482 : }
8483 :
8484 232 : if ( poDS == NULL )
8485 : {
8486 0 : VSIUnlink( pszFilename );
8487 0 : return NULL;
8488 : }
8489 :
8490 232 : poDS->osProfile = pszProfile;
8491 232 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT & ~GCIF_MASK );
8492 232 : poDS->papszCreationOptions = CSLDuplicate( papszOptions );
8493 232 : poDS->bDontReloadFirstBlock = bDontReloadFirstBlock;
8494 :
8495 : /* -------------------------------------------------------------------- */
8496 : /* CloneInfo() doesn't merge metadata, it just replaces it totally */
8497 : /* So we have to merge it */
8498 : /* -------------------------------------------------------------------- */
8499 :
8500 232 : char **papszSRC_MD = poSrcDS->GetMetadata();
8501 232 : char **papszDST_MD = CSLDuplicate(poDS->GetMetadata());
8502 :
8503 232 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
8504 :
8505 232 : poDS->SetMetadata( papszDST_MD );
8506 232 : CSLDestroy( papszDST_MD );
8507 :
8508 : /* Depending on the PHOTOMETRIC tag, the TIFF file may not have */
8509 : /* the same band count as the source. Will fail later in GDALDatasetCopyWholeRaster anyway... */
8510 597 : for( int nBand = 1;
8511 : nBand <= MIN(poDS->GetRasterCount(), poSrcDS->GetRasterCount()) ;
8512 : nBand++ )
8513 : {
8514 365 : GDALRasterBand* poSrcBand = poSrcDS->GetRasterBand(nBand);
8515 365 : GDALRasterBand* poDstBand = poDS->GetRasterBand(nBand);
8516 365 : char **papszSRC_MD = poSrcBand->GetMetadata();
8517 365 : char **papszDST_MD = CSLDuplicate(poDstBand->GetMetadata());
8518 :
8519 365 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
8520 :
8521 365 : poDstBand->SetMetadata( papszDST_MD );
8522 365 : CSLDestroy( papszDST_MD );
8523 :
8524 : char** papszCatNames;
8525 365 : papszCatNames = poSrcBand->GetCategoryNames();
8526 365 : if (NULL != papszCatNames)
8527 0 : poDstBand->SetCategoryNames( papszCatNames );
8528 : }
8529 :
8530 232 : hTIFF = (TIFF*) poDS->GetInternalHandle(NULL);
8531 :
8532 : /* -------------------------------------------------------------------- */
8533 : /* Handle forcing xml:ESRI data to be written to PAM. */
8534 : /* -------------------------------------------------------------------- */
8535 232 : if( CSLTestBoolean(CPLGetConfigOption( "ESRI_XML_PAM", "NO" )) )
8536 : {
8537 1 : char **papszESRIMD = poSrcDS->GetMetadata("xml:ESRI");
8538 1 : if( papszESRIMD )
8539 : {
8540 1 : poDS->SetMetadata( papszESRIMD, "xml:ESRI");
8541 : }
8542 : }
8543 :
8544 : /* -------------------------------------------------------------------- */
8545 : /* Second chance : now that we have a PAM dataset, it is possible */
8546 : /* to write metadata that we couldn't be writen as TIFF tag */
8547 : /* -------------------------------------------------------------------- */
8548 232 : if (!bHasWrittenMDInGeotiffTAG)
8549 : GTiffDataset::WriteMetadata( poDS, hTIFF, TRUE, pszProfile,
8550 4 : pszFilename, papszOptions, TRUE /* don't write RPC and IMD file again */);
8551 :
8552 : /* To avoid unnecessary directory rewriting */
8553 232 : poDS->bMetadataChanged = FALSE;
8554 232 : poDS->bGeoTIFFInfoChanged = FALSE;
8555 232 : poDS->bForceUnsetGT = FALSE;
8556 232 : poDS->bForceUnsetProjection = FALSE;
8557 :
8558 : /* We must re-set the compression level at this point, since it has */
8559 : /* been lost a few lines above when closing the newly create TIFF file */
8560 : /* The TIFFTAG_ZIPQUALITY & TIFFTAG_JPEGQUALITY are not store in the TIFF file. */
8561 : /* They are just TIFF session parameters */
8562 :
8563 232 : poDS->nZLevel = GTiffGetZLevel(papszOptions);
8564 232 : poDS->nLZMAPreset = GTiffGetLZMAPreset(papszOptions);
8565 232 : poDS->nJpegQuality = GTiffGetJpegQuality(papszOptions);
8566 :
8567 232 : if (nCompression == COMPRESSION_ADOBE_DEFLATE)
8568 : {
8569 4 : if (poDS->nZLevel != -1)
8570 : {
8571 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, poDS->nZLevel );
8572 : }
8573 : }
8574 228 : else if( nCompression == COMPRESSION_JPEG)
8575 : {
8576 20 : if (poDS->nJpegQuality != -1)
8577 : {
8578 3 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, poDS->nJpegQuality );
8579 : }
8580 : }
8581 208 : else if( nCompression == COMPRESSION_LZMA)
8582 : {
8583 0 : if (poDS->nLZMAPreset != -1)
8584 : {
8585 0 : TIFFSetField( hTIFF, TIFFTAG_LZMAPRESET, poDS->nLZMAPreset );
8586 : }
8587 : }
8588 :
8589 : /* Precreate (internal) mask, so that the IBuildOverviews() below */
8590 : /* has a chance to create also the overviews of the mask */
8591 232 : int nMaskFlags = poSrcDS->GetRasterBand(1)->GetMaskFlags();
8592 232 : if( eErr == CE_None
8593 : && !(nMaskFlags & (GMF_ALL_VALID|GMF_ALPHA|GMF_NODATA) )
8594 : && (nMaskFlags & GMF_PER_DATASET) )
8595 : {
8596 3 : eErr = poDS->CreateMaskBand( nMaskFlags );
8597 : }
8598 :
8599 : /* -------------------------------------------------------------------- */
8600 : /* Create and then copy existing overviews if requested */
8601 : /* We do it such that all the IFDs are at the beginning of the file, */
8602 : /* and that the imagery data for the smallest overview is written */
8603 : /* first, that way the file is more usable when embedded in a */
8604 : /* compressed stream. */
8605 : /* -------------------------------------------------------------------- */
8606 :
8607 : /* For scaled progress due to overview copying */
8608 232 : double dfTotalPixels = ((double)nXSize) * nYSize;
8609 232 : double dfCurPixels = 0;
8610 :
8611 232 : if (eErr == CE_None &&
8612 : nSrcOverviews != 0 &&
8613 : CSLFetchBoolean(papszOptions, "COPY_SRC_OVERVIEWS", FALSE))
8614 : {
8615 5 : eErr = poDS->CreateOverviewsFromSrcOverviews(poSrcDS);
8616 :
8617 5 : if (poDS->nOverviewCount != nSrcOverviews)
8618 : {
8619 : CPLError(CE_Failure, CPLE_AppDefined,
8620 : "Did only manage to instanciate %d overview levels, whereas source contains %d",
8621 0 : poDS->nOverviewCount, nSrcOverviews);
8622 0 : eErr = CE_Failure;
8623 : }
8624 :
8625 : int i;
8626 18 : for(i=0;i<nSrcOverviews;i++)
8627 : {
8628 13 : GDALRasterBand* poOvrBand = poSrcDS->GetRasterBand(1)->GetOverview(i);
8629 : dfTotalPixels += ((double)poOvrBand->GetXSize()) *
8630 13 : poOvrBand->GetYSize();
8631 : }
8632 :
8633 5 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
8634 5 : if (nCompression != COMPRESSION_NONE)
8635 0 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
8636 : /* Now copy the imagery */
8637 17 : for(i=0;eErr == CE_None && i<nSrcOverviews;i++)
8638 : {
8639 : /* Begin with the smallest overview */
8640 12 : int iOvrLevel = nSrcOverviews-1-i;
8641 :
8642 : /* Create a fake dataset with the source overview level so that */
8643 : /* GDALDatasetCopyWholeRaster can cope with it */
8644 12 : GDALDataset* poSrcOvrDS = new GDALOverviewDS(poSrcDS, iOvrLevel);
8645 :
8646 : GDALRasterBand* poOvrBand =
8647 24 : poSrcDS->GetRasterBand(1)->GetOverview(iOvrLevel);
8648 : double dfNextCurPixels = dfCurPixels +
8649 12 : ((double)poOvrBand->GetXSize()) * poOvrBand->GetYSize();
8650 :
8651 : void* pScaledData = GDALCreateScaledProgress( dfCurPixels / dfTotalPixels,
8652 : dfNextCurPixels / dfTotalPixels,
8653 12 : pfnProgress, pProgressData);
8654 :
8655 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcOvrDS,
8656 12 : (GDALDatasetH) poDS->papoOverviewDS[iOvrLevel],
8657 : papszCopyWholeRasterOptions,
8658 24 : GDALScaledProgress, pScaledData );
8659 :
8660 12 : dfCurPixels = dfNextCurPixels;
8661 12 : GDALDestroyScaledProgress(pScaledData);
8662 :
8663 12 : delete poSrcOvrDS;
8664 12 : poDS->papoOverviewDS[iOvrLevel]->FlushCache();
8665 :
8666 : /* Copy mask of the overview */
8667 12 : if (eErr == CE_None && poDS->poMaskDS != NULL)
8668 : {
8669 2 : eErr = GDALRasterBandCopyWholeRaster( poOvrBand->GetMaskBand(),
8670 2 : poDS->papoOverviewDS[iOvrLevel]->poMaskDS->GetRasterBand(1),
8671 : papszCopyWholeRasterOptions,
8672 4 : GDALDummyProgress, NULL);
8673 2 : poDS->papoOverviewDS[iOvrLevel]->poMaskDS->FlushCache();
8674 : }
8675 : }
8676 : }
8677 :
8678 : /* -------------------------------------------------------------------- */
8679 : /* Copy actual imagery. */
8680 : /* -------------------------------------------------------------------- */
8681 : void* pScaledData = GDALCreateScaledProgress( dfCurPixels / dfTotalPixels,
8682 : 1.0,
8683 232 : pfnProgress, pProgressData);
8684 :
8685 232 : int bTryCopy = TRUE;
8686 :
8687 : #ifdef HAVE_LIBJPEG
8688 232 : if (bCopyFromJPEG)
8689 : {
8690 : eErr = GTIFF_CopyFromJPEG(poDS, poSrcDS,
8691 : pfnProgress, pProgressData,
8692 8 : bTryCopy);
8693 :
8694 : /* In case of failure in the decompression step, try normal copy */
8695 8 : if (bTryCopy)
8696 0 : eErr = CE_None;
8697 : }
8698 : #endif
8699 :
8700 : #ifdef JPEG_DIRECT_COPY
8701 : if (bDirectCopyFromJPEG)
8702 : {
8703 : eErr = GTIFF_DirectCopyFromJPEG(poDS, poSrcDS,
8704 : pfnProgress, pProgressData,
8705 : bTryCopy);
8706 :
8707 : /* In case of failure in the reading step, try normal copy */
8708 : if (bTryCopy)
8709 : eErr = CE_None;
8710 : }
8711 : #endif
8712 :
8713 235 : if (bTryCopy && (poDS->bTreatAsSplit || poDS->bTreatAsSplitBitmap))
8714 : {
8715 : /* For split bands, we use TIFFWriteScanline() interface */
8716 3 : CPLAssert(poDS->nBitsPerSample == 8 || poDS->nBitsPerSample == 1);
8717 :
8718 5 : if (poDS->nPlanarConfig == PLANARCONFIG_CONTIG && poDS->nBands > 1)
8719 : {
8720 : int j;
8721 2 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
8722 7050 : for(j=0;j<nYSize && eErr == CE_None;j++)
8723 : {
8724 : eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1,
8725 : pabyScanline, nXSize, 1,
8726 7048 : GDT_Byte, nBands, NULL, poDS->nBands, 0, 1);
8727 7048 : if (eErr == CE_None &&
8728 : TIFFWriteScanline( hTIFF, pabyScanline, j, 0) == -1)
8729 : {
8730 : CPLError( CE_Failure, CPLE_AppDefined,
8731 0 : "TIFFWriteScanline() failed." );
8732 0 : eErr = CE_Failure;
8733 : }
8734 7048 : if( !GDALScaledProgress( (j+1) * 1.0 / nYSize, NULL, pScaledData ) )
8735 0 : eErr = CE_Failure;
8736 : }
8737 2 : CPLFree(pabyScanline);
8738 : }
8739 : else
8740 : {
8741 : int iBand, j;
8742 1 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
8743 1 : eErr = CE_None;
8744 4 : for(iBand=1;iBand<=nBands && eErr == CE_None;iBand++)
8745 : {
8746 15003 : for(j=0;j<nYSize && eErr == CE_None;j++)
8747 : {
8748 : eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
8749 : GF_Read, 0, j, nXSize, 1,
8750 : pabyScanline, nXSize, 1,
8751 15000 : GDT_Byte, 0, 0);
8752 15000 : if (poDS->bTreatAsSplitBitmap)
8753 : {
8754 0 : for(int i=0;i<nXSize;i++)
8755 : {
8756 0 : GByte byVal = pabyScanline[i];
8757 0 : if ((i & 0x7) == 0)
8758 0 : pabyScanline[i >> 3] = 0;
8759 0 : if (byVal)
8760 0 : pabyScanline[i >> 3] |= (0x80 >> (i & 0x7));
8761 : }
8762 : }
8763 15000 : if (eErr == CE_None &&
8764 : TIFFWriteScanline( hTIFF, pabyScanline, j, (uint16) (iBand-1)) == -1)
8765 : {
8766 : CPLError( CE_Failure, CPLE_AppDefined,
8767 0 : "TIFFWriteScanline() failed." );
8768 0 : eErr = CE_Failure;
8769 : }
8770 15000 : if( !GDALScaledProgress( (j+1 + (iBand - 1) * nYSize) * 1.0 /
8771 : (nBands * nYSize), NULL, pScaledData ) )
8772 0 : eErr = CE_Failure;
8773 : }
8774 : }
8775 1 : CPLFree(pabyScanline);
8776 : }
8777 :
8778 : /* Necessary to be able to read the file without re-opening */
8779 : #if defined(HAVE_TIFFGETSIZEPROC)
8780 3 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
8781 :
8782 3 : TIFFFlushData( hTIFF );
8783 :
8784 3 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
8785 3 : if( (nNewDirOffset % 2) == 1 )
8786 3 : nNewDirOffset++;
8787 : #endif
8788 :
8789 3 : TIFFFlush( hTIFF );
8790 :
8791 : #if defined(HAVE_TIFFGETSIZEPROC)
8792 3 : if( poDS->nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
8793 : {
8794 1 : poDS->nDirOffset = nNewDirOffset;
8795 1 : CPLDebug( "GTiff", "directory moved during flush." );
8796 : }
8797 : #endif
8798 : }
8799 229 : else if (bTryCopy && eErr == CE_None)
8800 : {
8801 220 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
8802 220 : if (nCompression != COMPRESSION_NONE)
8803 20 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
8804 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
8805 : (GDALDatasetH) poDS,
8806 : papszCopyWholeRasterOptions,
8807 220 : GDALScaledProgress, pScaledData );
8808 : }
8809 :
8810 232 : GDALDestroyScaledProgress(pScaledData);
8811 :
8812 232 : if (eErr == CE_None)
8813 : {
8814 230 : if (poDS->poMaskDS)
8815 : {
8816 3 : const char* papszOptions[2] = { "COMPRESSED=YES", NULL };
8817 : eErr = GDALRasterBandCopyWholeRaster(
8818 3 : poSrcDS->GetRasterBand(1)->GetMaskBand(),
8819 3 : poDS->GetRasterBand(1)->GetMaskBand(),
8820 : (char**)papszOptions,
8821 9 : GDALDummyProgress, NULL);
8822 : }
8823 : else
8824 227 : eErr = GDALDriver::DefaultCopyMasks( poSrcDS, poDS, bStrict );
8825 : }
8826 :
8827 232 : if( eErr == CE_Failure )
8828 : {
8829 2 : delete poDS;
8830 2 : poDS = NULL;
8831 :
8832 2 : if (CSLTestBoolean(CPLGetConfigOption("GTIFF_DELETE_ON_ERROR", "YES")))
8833 1 : VSIUnlink( pszFilename ); // should really delete more carefully.
8834 : }
8835 :
8836 232 : return poDS;
8837 : }
8838 :
8839 : /************************************************************************/
8840 : /* GetProjectionRef() */
8841 : /************************************************************************/
8842 :
8843 3603 : const char *GTiffDataset::GetProjectionRef()
8844 :
8845 : {
8846 3603 : if( nGCPCount == 0 )
8847 : {
8848 3573 : LookForProjection();
8849 :
8850 3573 : if( EQUAL(pszProjection,"") )
8851 111 : return GDALPamDataset::GetProjectionRef();
8852 : else
8853 3462 : return( pszProjection );
8854 : }
8855 : else
8856 30 : return "";
8857 : }
8858 :
8859 : /************************************************************************/
8860 : /* SetProjection() */
8861 : /************************************************************************/
8862 :
8863 750 : CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
8864 :
8865 : {
8866 750 : LookForProjection();
8867 :
8868 750 : if( !EQUALN(pszNewProjection,"GEOGCS",6)
8869 : && !EQUALN(pszNewProjection,"PROJCS",6)
8870 : && !EQUALN(pszNewProjection,"LOCAL_CS",8)
8871 : && !EQUALN(pszNewProjection,"COMPD_CS",8)
8872 : && !EQUALN(pszNewProjection,"GEOCCS",6)
8873 : && !EQUAL(pszNewProjection,"") )
8874 : {
8875 : CPLError( CE_Failure, CPLE_AppDefined,
8876 : "Only OGC WKT Projections supported for writing to GeoTIFF.\n"
8877 : "%s not supported.",
8878 0 : pszNewProjection );
8879 :
8880 0 : return CE_Failure;
8881 : }
8882 :
8883 : bForceUnsetProjection = (
8884 : EQUAL(pszNewProjection, "") &&
8885 : pszProjection != NULL &&
8886 750 : !EQUAL(pszProjection, "") );
8887 :
8888 750 : CPLFree( pszProjection );
8889 750 : pszProjection = CPLStrdup( pszNewProjection );
8890 :
8891 750 : bGeoTIFFInfoChanged = TRUE;
8892 :
8893 750 : return CE_None;
8894 : }
8895 :
8896 : /************************************************************************/
8897 : /* GetGeoTransform() */
8898 : /************************************************************************/
8899 :
8900 2441 : CPLErr GTiffDataset::GetGeoTransform( double * padfTransform )
8901 :
8902 : {
8903 2441 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
8904 :
8905 2441 : if( !bGeoTransformValid )
8906 108 : return CE_Failure;
8907 : else
8908 2333 : return CE_None;
8909 : }
8910 :
8911 : /************************************************************************/
8912 : /* SetGeoTransform() */
8913 : /************************************************************************/
8914 :
8915 714 : CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
8916 :
8917 : {
8918 714 : if( GetAccess() == GA_Update )
8919 : {
8920 : bForceUnsetGT = (
8921 714 : padfTransform[0] == 0.0 &&
8922 9 : padfTransform[1] == 1.0 &&
8923 9 : padfTransform[2] == 0.0 &&
8924 9 : padfTransform[3] == 0.0 &&
8925 2 : padfTransform[4] == 0.0 &&
8926 2 : padfTransform[5] == 1.0 &&
8927 2 : !(adfGeoTransform[0] == 0.0 &&
8928 1 : adfGeoTransform[1] == 1.0 &&
8929 1 : adfGeoTransform[2] == 0.0 &&
8930 1 : adfGeoTransform[3] == 0.0 &&
8931 1 : adfGeoTransform[4] == 0.0 &&
8932 751 : adfGeoTransform[5] == 1.0) );
8933 :
8934 714 : memcpy( adfGeoTransform, padfTransform, sizeof(double)*6 );
8935 714 : bGeoTransformValid = TRUE;
8936 714 : bGeoTIFFInfoChanged = TRUE;
8937 :
8938 714 : return( CE_None );
8939 : }
8940 : else
8941 : {
8942 : CPLError( CE_Failure, CPLE_NotSupported,
8943 0 : "Attempt to call SetGeoTransform() on a read-only GeoTIFF file." );
8944 0 : return CE_Failure;
8945 : }
8946 : }
8947 :
8948 : /************************************************************************/
8949 : /* GetGCPCount() */
8950 : /************************************************************************/
8951 :
8952 1292 : int GTiffDataset::GetGCPCount()
8953 :
8954 : {
8955 1292 : return nGCPCount;
8956 : }
8957 :
8958 : /************************************************************************/
8959 : /* GetGCPProjection() */
8960 : /************************************************************************/
8961 :
8962 67 : const char *GTiffDataset::GetGCPProjection()
8963 :
8964 : {
8965 67 : if( nGCPCount > 0 )
8966 : {
8967 63 : LookForProjection();
8968 : }
8969 67 : if (pszProjection != NULL)
8970 67 : return pszProjection;
8971 : else
8972 0 : return "";
8973 : }
8974 :
8975 : /************************************************************************/
8976 : /* GetGCPs() */
8977 : /************************************************************************/
8978 :
8979 37 : const GDAL_GCP *GTiffDataset::GetGCPs()
8980 :
8981 : {
8982 37 : return pasGCPList;
8983 : }
8984 :
8985 : /************************************************************************/
8986 : /* SetGCPs() */
8987 : /************************************************************************/
8988 :
8989 2 : CPLErr GTiffDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
8990 : const char *pszGCPProjection )
8991 : {
8992 2 : if( GetAccess() == GA_Update )
8993 : {
8994 2 : bLookedForProjection = TRUE;
8995 :
8996 2 : if( this->nGCPCount > 0 )
8997 : {
8998 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
8999 0 : CPLFree( this->pasGCPList );
9000 : }
9001 :
9002 2 : this->nGCPCount = nGCPCount;
9003 2 : this->pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPList);
9004 :
9005 2 : CPLFree( this->pszProjection );
9006 2 : this->pszProjection = CPLStrdup( pszGCPProjection );
9007 2 : bGeoTIFFInfoChanged = TRUE;
9008 :
9009 2 : return CE_None;
9010 : }
9011 : else
9012 : {
9013 : CPLError( CE_Failure, CPLE_NotSupported,
9014 0 : "SetGCPs() is only supported on newly created GeoTIFF files." );
9015 0 : return CE_Failure;
9016 : }
9017 : }
9018 :
9019 : /************************************************************************/
9020 : /* GetMetadata() */
9021 : /************************************************************************/
9022 :
9023 6398 : char **GTiffDataset::GetMetadata( const char * pszDomain )
9024 :
9025 : {
9026 6398 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
9027 0 : return GDALPamDataset::GetMetadata( pszDomain );
9028 :
9029 8327 : else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
9030 1929 : LoadRPCRPB();
9031 :
9032 5677 : else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
9033 1208 : LoadIMDPVL();
9034 :
9035 3435 : else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
9036 174 : ScanDirectories();
9037 :
9038 3089 : else if( pszDomain != NULL && EQUAL(pszDomain,"EXIF") )
9039 2 : LoadEXIFMetadata();
9040 :
9041 3085 : else if( pszDomain == NULL || EQUAL(pszDomain, "") )
9042 2652 : LoadMDAreaOrPoint(); /* to set GDALMD_AREA_OR_POINT */
9043 :
9044 6398 : return oGTiffMDMD.GetMetadata( pszDomain );
9045 : }
9046 :
9047 : /************************************************************************/
9048 : /* SetMetadata() */
9049 : /************************************************************************/
9050 562 : CPLErr GTiffDataset::SetMetadata( char ** papszMD, const char *pszDomain )
9051 :
9052 : {
9053 562 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
9054 562 : bMetadataChanged = TRUE;
9055 :
9056 562 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
9057 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT) != NULL )
9058 : {
9059 : const char* pszPrevValue =
9060 417 : GetMetadataItem(GDALMD_AREA_OR_POINT);
9061 : const char* pszNewValue =
9062 417 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT);
9063 417 : if (pszPrevValue == NULL || pszNewValue == NULL ||
9064 : !EQUAL(pszPrevValue, pszNewValue))
9065 : {
9066 273 : LookForProjection();
9067 273 : bGeoTIFFInfoChanged = TRUE;
9068 : }
9069 : }
9070 :
9071 562 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
9072 : }
9073 :
9074 : /************************************************************************/
9075 : /* GetMetadataItem() */
9076 : /************************************************************************/
9077 :
9078 26374 : const char *GTiffDataset::GetMetadataItem( const char * pszName,
9079 : const char * pszDomain )
9080 :
9081 : {
9082 26374 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
9083 3 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
9084 :
9085 26373 : else if( pszDomain != NULL && EQUAL(pszDomain,"RPC") )
9086 2 : LoadRPCRPB();
9087 :
9088 26371 : else if( pszDomain != NULL && EQUAL(pszDomain,"IMD") )
9089 2 : LoadIMDPVL();
9090 :
9091 26367 : else if( pszDomain != NULL && EQUAL(pszDomain,"SUBDATASETS") )
9092 0 : ScanDirectories();
9093 :
9094 26368 : else if( pszDomain != NULL && EQUAL(pszDomain,"EXIF") )
9095 1 : LoadEXIFMetadata();
9096 :
9097 26366 : else if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
9098 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
9099 : {
9100 2086 : LoadMDAreaOrPoint(); /* to set GDALMD_AREA_OR_POINT */
9101 : }
9102 :
9103 26371 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
9104 : }
9105 :
9106 : /************************************************************************/
9107 : /* SetMetadataItem() */
9108 : /************************************************************************/
9109 :
9110 5717 : CPLErr GTiffDataset::SetMetadataItem( const char *pszName,
9111 : const char *pszValue,
9112 : const char *pszDomain )
9113 :
9114 : {
9115 5717 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
9116 5717 : bMetadataChanged = TRUE;
9117 :
9118 5717 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
9119 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
9120 : {
9121 8 : LookForProjection();
9122 8 : bGeoTIFFInfoChanged = TRUE;
9123 : }
9124 :
9125 5717 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
9126 : }
9127 :
9128 : /************************************************************************/
9129 : /* GetInternalHandle() */
9130 : /************************************************************************/
9131 :
9132 316 : void *GTiffDataset::GetInternalHandle( const char * /* pszHandleName */ )
9133 :
9134 : {
9135 316 : return hTIFF;
9136 : }
9137 :
9138 :
9139 : /************************************************************************/
9140 : /* FindRPBFile() */
9141 : /************************************************************************/
9142 :
9143 2268 : int GTiffDataset::FindRPBFile()
9144 : {
9145 : osRPBFile = GDALFindAssociatedFile( osFilename, "RPB",
9146 2268 : oOvManager.GetSiblingFiles(), 0 );
9147 :
9148 2268 : return osRPBFile != "";
9149 : }
9150 :
9151 : /************************************************************************/
9152 : /* FindIMDFile() */
9153 : /************************************************************************/
9154 :
9155 2094 : int GTiffDataset::FindIMDFile()
9156 : {
9157 : osIMDFile = GDALFindAssociatedFile( osFilename, "IMD",
9158 2094 : oOvManager.GetSiblingFiles(), 0 );
9159 :
9160 2094 : return osIMDFile != "";
9161 : }
9162 :
9163 : /************************************************************************/
9164 : /* FindPVLFile() */
9165 : /************************************************************************/
9166 :
9167 2086 : int GTiffDataset::FindPVLFile()
9168 : {
9169 : osPVLFile = GDALFindAssociatedFile( osFilename, "PVL",
9170 2086 : oOvManager.GetSiblingFiles(), 0 );
9171 :
9172 2086 : return osPVLFile != "";
9173 : }
9174 :
9175 : /************************************************************************/
9176 : /* FindRPCFile() */
9177 : /************************************************************************/
9178 :
9179 2260 : int GTiffDataset::FindRPCFile()
9180 : {
9181 2260 : CPLString osSrcPath = osFilename;
9182 2260 : CPLString soPt(".");
9183 2260 : size_t found = osSrcPath.rfind(soPt);
9184 2260 : if (found == CPLString::npos)
9185 42 : return FALSE;
9186 2218 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
9187 2218 : CPLString osTarget = osSrcPath;
9188 :
9189 2218 : char** papszSiblingFiles = oOvManager.GetSiblingFiles();
9190 2218 : if( papszSiblingFiles == NULL )
9191 : {
9192 : VSIStatBufL sStatBuf;
9193 :
9194 953 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
9195 : {
9196 953 : osSrcPath = osFilename;
9197 953 : osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
9198 953 : osTarget = osSrcPath;
9199 :
9200 953 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
9201 : {
9202 953 : osSrcPath = osFilename;
9203 953 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
9204 953 : osTarget = osSrcPath;
9205 :
9206 953 : if( VSIStatExL( osTarget, &sStatBuf, VSI_STAT_EXISTS_FLAG ) != 0 )
9207 : {
9208 953 : return FALSE;
9209 : }
9210 : }
9211 : }
9212 : }
9213 : else
9214 : {
9215 : int iSibling = CSLFindString( papszSiblingFiles,
9216 1265 : CPLGetFilename(osTarget) );
9217 1265 : if( iSibling < 0 )
9218 1264 : return FALSE;
9219 :
9220 1 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
9221 1 : osTarget += papszSiblingFiles[iSibling];
9222 : }
9223 :
9224 1 : osRPCFile = osTarget;
9225 1 : return TRUE;
9226 : }
9227 :
9228 : /************************************************************************/
9229 : /* LoadRPCRPB() */
9230 : /************************************************************************/
9231 :
9232 2915 : void GTiffDataset::LoadRPCRPB()
9233 : {
9234 2915 : if (bHasSearchedRPC)
9235 647 : return;
9236 :
9237 2268 : bHasSearchedRPC = TRUE;
9238 :
9239 2268 : char **papszRPCMD = NULL;
9240 : /* Read Digital Globe .RPB file */
9241 2268 : if (FindRPBFile())
9242 8 : papszRPCMD = GDALLoadRPBFile( osRPBFile.c_str(), NULL );
9243 :
9244 : /* Read GeoEye _rpc.txt file */
9245 2268 : if(papszRPCMD == NULL && FindRPCFile())
9246 1 : papszRPCMD = GDALLoadRPCFile( osRPCFile.c_str(), NULL );
9247 :
9248 2268 : if( papszRPCMD != NULL )
9249 : {
9250 9 : oGTiffMDMD.SetMetadata( papszRPCMD, "RPC" );
9251 9 : CSLDestroy( papszRPCMD );
9252 : }
9253 : else
9254 2259 : ReadRPCTag();
9255 : }
9256 :
9257 : /************************************************************************/
9258 : /* LoadIMDPVL() */
9259 : /************************************************************************/
9260 :
9261 2194 : void GTiffDataset::LoadIMDPVL()
9262 : {
9263 2194 : if (!bHasSearchedIMD)
9264 : {
9265 2094 : bHasSearchedIMD = TRUE;
9266 :
9267 2094 : if (FindIMDFile())
9268 : {
9269 8 : char **papszIMDMD = GDALLoadIMDFile( osIMDFile.c_str(), NULL );
9270 :
9271 8 : if( papszIMDMD != NULL )
9272 : {
9273 : papszIMDMD = CSLSetNameValue( papszIMDMD,
9274 8 : "md_type", "imd" );
9275 8 : oGTiffMDMD.SetMetadata( papszIMDMD, "IMD" );
9276 8 : CSLDestroy( papszIMDMD );
9277 : }
9278 : }
9279 : }
9280 : //the imd has priority
9281 2194 : if (!bHasSearchedPVL && osIMDFile.empty())
9282 : {
9283 2086 : bHasSearchedPVL = TRUE;
9284 :
9285 2086 : if (FindPVLFile())
9286 : {
9287 : /* -------------------------------------------------------------------- */
9288 : /* Read file and parse. */
9289 : /* -------------------------------------------------------------------- */
9290 0 : CPLKeywordParser oParser;
9291 :
9292 0 : VSILFILE *fp = VSIFOpenL( osPVLFile.c_str(), "r" );
9293 :
9294 0 : if( fp == NULL )
9295 : return;
9296 :
9297 0 : if( !oParser.Ingest( fp ) )
9298 : {
9299 0 : VSIFCloseL( fp );
9300 : return;
9301 : }
9302 :
9303 0 : VSIFCloseL( fp );
9304 :
9305 : /* -------------------------------------------------------------------- */
9306 : /* Consider version changing. */
9307 : /* -------------------------------------------------------------------- */
9308 0 : char **papszPVLMD = CSLDuplicate( oParser.GetAllKeywords() );
9309 :
9310 0 : if( papszPVLMD != NULL )
9311 : {
9312 : papszPVLMD = CSLSetNameValue( papszPVLMD,
9313 0 : "md_type", "pvl" );
9314 :
9315 0 : oGTiffMDMD.SetMetadata( papszPVLMD, "IMD" );
9316 0 : CSLDestroy( papszPVLMD );
9317 0 : }
9318 : }
9319 : }
9320 : }
9321 :
9322 : /************************************************************************/
9323 : /* LoadEXIFMetadata() */
9324 : /************************************************************************/
9325 :
9326 3 : void GTiffDataset::LoadEXIFMetadata()
9327 : {
9328 3 : if (bEXIFMetadataLoaded)
9329 0 : return;
9330 3 : bEXIFMetadataLoaded = TRUE;
9331 :
9332 3 : if (!SetDirectory())
9333 0 : return;
9334 :
9335 3 : VSILFILE* fp = (VSILFILE*) TIFFClientdata( hTIFF );
9336 :
9337 : GByte abyHeader[2];
9338 3 : VSIFSeekL(fp, 0, SEEK_SET);
9339 3 : VSIFReadL(abyHeader, 1, 2, fp);
9340 :
9341 3 : int bLittleEndian = abyHeader[0] == 'I' && abyHeader[1] == 'I';
9342 3 : int bSwabflag = bLittleEndian ^ CPL_IS_LSB;
9343 :
9344 3 : char** papszMetadata = NULL;
9345 : toff_t nOffset;
9346 :
9347 3 : if (TIFFGetField(hTIFF, TIFFTAG_EXIFIFD, &nOffset))
9348 : {
9349 2 : int nExifOffset = (int)nOffset, nInterOffset = 0, nGPSOffset = 0;
9350 : EXIFExtractMetadata(papszMetadata,
9351 : fp, (int)nOffset,
9352 : bSwabflag, 0,
9353 2 : nExifOffset, nInterOffset, nGPSOffset);
9354 : }
9355 :
9356 3 : if (TIFFGetField(hTIFF, TIFFTAG_GPSIFD, &nOffset))
9357 : {
9358 2 : int nExifOffset = 0, nInterOffset = 0, nGPSOffset = (int)nOffset;
9359 : EXIFExtractMetadata(papszMetadata,
9360 : fp, (int)nOffset,
9361 : bSwabflag, 0,
9362 2 : nExifOffset, nInterOffset, nGPSOffset);
9363 : }
9364 :
9365 3 : oGTiffMDMD.SetMetadata( papszMetadata, "EXIF" );
9366 3 : CSLDestroy( papszMetadata );
9367 : }
9368 :
9369 : /************************************************************************/
9370 : /* GetFileList() */
9371 : /************************************************************************/
9372 :
9373 984 : char **GTiffDataset::GetFileList()
9374 :
9375 : {
9376 984 : char **papszFileList = GDALPamDataset::GetFileList();
9377 :
9378 984 : LoadRPCRPB();
9379 984 : LoadIMDPVL();
9380 :
9381 984 : if (osIMDFile.size() != 0)
9382 4 : papszFileList = CSLAddString( papszFileList, osIMDFile );
9383 984 : if (osPVLFile.size() != 0)
9384 0 : papszFileList = CSLAddString( papszFileList, osPVLFile );
9385 984 : if (osRPBFile.size() != 0)
9386 2 : papszFileList = CSLAddString( papszFileList, osRPBFile );
9387 984 : if (osRPCFile.size() != 0)
9388 0 : papszFileList = CSLAddString( papszFileList, osRPCFile );
9389 :
9390 984 : if (osWldFilename.size() != 0 &&
9391 : CSLFindString(papszFileList, osWldFilename) == -1)
9392 : {
9393 3 : papszFileList = CSLAddString( papszFileList, osWldFilename );
9394 : }
9395 :
9396 984 : return papszFileList;
9397 : }
9398 :
9399 : /************************************************************************/
9400 : /* CreateMaskBand() */
9401 : /************************************************************************/
9402 :
9403 35 : CPLErr GTiffDataset::CreateMaskBand(int nFlags)
9404 : {
9405 35 : ScanDirectories();
9406 :
9407 35 : if (poMaskDS != NULL)
9408 : {
9409 : CPLError(CE_Failure, CPLE_AppDefined,
9410 0 : "This TIFF dataset has already an internal mask band");
9411 0 : return CE_Failure;
9412 : }
9413 35 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
9414 : {
9415 : toff_t nOffset;
9416 : int bIsTiled;
9417 29 : int bIsOverview = FALSE;
9418 : uint32 nSubType;
9419 : int nCompression;
9420 :
9421 29 : if (nFlags != GMF_PER_DATASET)
9422 : {
9423 : CPLError(CE_Failure, CPLE_AppDefined,
9424 0 : "The only flag value supported for internal mask is GMF_PER_DATASET");
9425 0 : return CE_Failure;
9426 : }
9427 :
9428 29 : if( strstr(GDALGetMetadataItem(GDALGetDriverByName( "GTiff" ),
9429 : GDAL_DMD_CREATIONOPTIONLIST, NULL ),
9430 : "<Value>DEFLATE</Value>") != NULL )
9431 29 : nCompression = COMPRESSION_ADOBE_DEFLATE;
9432 : else
9433 0 : nCompression = COMPRESSION_PACKBITS;
9434 :
9435 : /* -------------------------------------------------------------------- */
9436 : /* If we don't have read access, then create the mask externally. */
9437 : /* -------------------------------------------------------------------- */
9438 29 : if( GetAccess() != GA_Update )
9439 : {
9440 : CPLError( CE_Warning, CPLE_AppDefined,
9441 : "File open for read-only accessing, "
9442 0 : "creating mask externally." );
9443 :
9444 0 : return GDALPamDataset::CreateMaskBand(nFlags);
9445 : }
9446 :
9447 29 : if (poBaseDS)
9448 : {
9449 12 : if (!poBaseDS->SetDirectory())
9450 0 : return CE_Failure;
9451 : }
9452 29 : if (!SetDirectory())
9453 0 : return CE_Failure;
9454 :
9455 29 : if( TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
9456 : {
9457 12 : bIsOverview = (nSubType & FILETYPE_REDUCEDIMAGE) != 0;
9458 :
9459 12 : if ((nSubType & FILETYPE_MASK) != 0)
9460 : {
9461 : CPLError( CE_Failure, CPLE_AppDefined,
9462 0 : "Cannot create a mask on a TIFF mask IFD !" );
9463 0 : return CE_Failure;
9464 : }
9465 : }
9466 :
9467 29 : bIsTiled = TIFFIsTiled(hTIFF);
9468 :
9469 29 : FlushDirectory();
9470 :
9471 : nOffset = GTIFFWriteDirectory(hTIFF,
9472 : (bIsOverview) ? FILETYPE_REDUCEDIMAGE | FILETYPE_MASK : FILETYPE_MASK,
9473 : nRasterXSize, nRasterYSize,
9474 : 1, PLANARCONFIG_CONTIG, 1,
9475 : nBlockXSize, nBlockYSize,
9476 : bIsTiled, nCompression,
9477 : PHOTOMETRIC_MASK, PREDICTOR_NONE,
9478 29 : SAMPLEFORMAT_UINT, NULL, NULL, NULL, 0, NULL, "");
9479 29 : if (nOffset == 0)
9480 0 : return CE_Failure;
9481 :
9482 29 : poMaskDS = new GTiffDataset();
9483 29 : poMaskDS->bPromoteTo8Bits = CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
9484 29 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nOffset,
9485 : FALSE, GA_Update ) != CE_None)
9486 : {
9487 0 : delete poMaskDS;
9488 0 : poMaskDS = NULL;
9489 0 : return CE_Failure;
9490 : }
9491 :
9492 29 : return CE_None;
9493 : }
9494 : else
9495 : {
9496 6 : return GDALPamDataset::CreateMaskBand(nFlags);
9497 : }
9498 : }
9499 :
9500 : /************************************************************************/
9501 : /* CreateMaskBand() */
9502 : /************************************************************************/
9503 :
9504 12 : CPLErr GTiffRasterBand::CreateMaskBand(int nFlags)
9505 : {
9506 12 : poGDS->ScanDirectories();
9507 :
9508 12 : if (poGDS->poMaskDS != NULL)
9509 : {
9510 : CPLError(CE_Failure, CPLE_AppDefined,
9511 0 : "This TIFF dataset has already an internal mask band");
9512 0 : return CE_Failure;
9513 : }
9514 12 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
9515 : {
9516 12 : return poGDS->CreateMaskBand(nFlags);
9517 : }
9518 : else
9519 : {
9520 0 : return GDALPamRasterBand::CreateMaskBand(nFlags);
9521 : }
9522 : }
9523 :
9524 : /************************************************************************/
9525 : /* PrepareTIFFErrorFormat() */
9526 : /* */
9527 : /* sometimes the "module" has stuff in it that has special */
9528 : /* meaning in a printf() style format, so we try to escape it. */
9529 : /* For now we hope the only thing we have to escape is %'s. */
9530 : /************************************************************************/
9531 :
9532 29 : static char *PrepareTIFFErrorFormat( const char *module, const char *fmt )
9533 :
9534 : {
9535 : char *pszModFmt;
9536 : int iIn, iOut;
9537 :
9538 29 : pszModFmt = (char *) CPLMalloc( strlen(module)*2 + strlen(fmt) + 2 );
9539 346 : for( iOut = 0, iIn = 0; module[iIn] != '\0'; iIn++ )
9540 : {
9541 317 : if( module[iIn] == '%' )
9542 : {
9543 0 : pszModFmt[iOut++] = '%';
9544 0 : pszModFmt[iOut++] = '%';
9545 : }
9546 : else
9547 317 : pszModFmt[iOut++] = module[iIn];
9548 : }
9549 29 : pszModFmt[iOut] = '\0';
9550 29 : strcat( pszModFmt, ":" );
9551 29 : strcat( pszModFmt, fmt );
9552 :
9553 29 : return pszModFmt;
9554 : }
9555 :
9556 : /************************************************************************/
9557 : /* GTiffWarningHandler() */
9558 : /************************************************************************/
9559 : void
9560 8 : GTiffWarningHandler(const char* module, const char* fmt, va_list ap )
9561 : {
9562 : char *pszModFmt;
9563 :
9564 8 : if( strstr(fmt,"nknown field") != NULL )
9565 0 : return;
9566 :
9567 8 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
9568 8 : if( strstr(fmt, "does not end in null byte") != NULL )
9569 : {
9570 2 : CPLString osMsg;
9571 2 : osMsg.vPrintf(pszModFmt, ap);
9572 2 : CPLDebug( "GTiff", "%s", osMsg.c_str() );
9573 : }
9574 : else
9575 6 : CPLErrorV( CE_Warning, CPLE_AppDefined, pszModFmt, ap );
9576 8 : CPLFree( pszModFmt );
9577 : }
9578 :
9579 : /************************************************************************/
9580 : /* GTiffErrorHandler() */
9581 : /************************************************************************/
9582 : void
9583 21 : GTiffErrorHandler(const char* module, const char* fmt, va_list ap )
9584 : {
9585 : char *pszModFmt;
9586 :
9587 21 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
9588 21 : CPLErrorV( CE_Failure, CPLE_AppDefined, pszModFmt, ap );
9589 21 : CPLFree( pszModFmt );
9590 21 : }
9591 :
9592 : /************************************************************************/
9593 : /* GTiffTagExtender() */
9594 : /* */
9595 : /* Install tags specially known to GDAL. */
9596 : /************************************************************************/
9597 :
9598 : static TIFFExtendProc _ParentExtender = NULL;
9599 :
9600 13503 : static void GTiffTagExtender(TIFF *tif)
9601 :
9602 : {
9603 : static const TIFFFieldInfo xtiffFieldInfo[] = {
9604 : { TIFFTAG_GDAL_METADATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
9605 : TRUE, FALSE, (char*) "GDALMetadata" },
9606 : { TIFFTAG_GDAL_NODATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
9607 : TRUE, FALSE, (char*) "GDALNoDataValue" },
9608 : { TIFFTAG_RPCCOEFFICIENT, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
9609 : TRUE, TRUE, (char*) "RPCCoefficient" }
9610 : };
9611 :
9612 13503 : if (_ParentExtender)
9613 0 : (*_ParentExtender)(tif);
9614 :
9615 : TIFFMergeFieldInfo( tif, xtiffFieldInfo,
9616 13503 : sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]) );
9617 13503 : }
9618 :
9619 : /************************************************************************/
9620 : /* GTiffOneTimeInit() */
9621 : /* */
9622 : /* This is stuff that is initialized for the TIFF library just */
9623 : /* once. We deliberately defer the initialization till the */
9624 : /* first time we are likely to call into libtiff to avoid */
9625 : /* unnecessary paging in of the library for GDAL apps that */
9626 : /* don't use it. */
9627 : /************************************************************************/
9628 : #if defined(HAVE_DLFCN_H) && !defined(WIN32)
9629 : #include <dlfcn.h>
9630 : #endif
9631 :
9632 : static void* hGTiffOneTimeInitMutex = NULL;
9633 :
9634 5222 : int GTiffOneTimeInit()
9635 :
9636 : {
9637 : static int bInitIsOk = TRUE;
9638 : static int bOneTimeInitDone = FALSE;
9639 5222 : CPLMutexHolder oHolder( &hGTiffOneTimeInitMutex);
9640 5222 : if( bOneTimeInitDone )
9641 4775 : return bInitIsOk;
9642 :
9643 447 : bOneTimeInitDone = TRUE;
9644 :
9645 : /* This is a frequent configuration error that is difficult to track down */
9646 : /* for people unaware of the issue : GDAL built against internal libtiff (4.X) */
9647 : /* but used by an application that links with external libtiff (3.X) */
9648 : /* Note: on my conf, the order that cause GDAL to crash - and that is detected */
9649 : /* by the following code - is "-ltiff -lgdal". "-lgdal -ltiff" works for the */
9650 : /* GTiff driver but probably breaks the application that believes it uses libtiff 3.X */
9651 : /* but we cannot detect that... */
9652 : #if defined(BIGTIFF_SUPPORT) && !defined(RENAME_INTERNAL_LIBTIFF_SYMBOLS)
9653 : #if defined(HAVE_DLFCN_H) && !defined(WIN32)
9654 : const char* (*pfnVersion)(void);
9655 : pfnVersion = (const char* (*)(void)) dlsym(RTLD_DEFAULT, "TIFFGetVersion");
9656 : if (pfnVersion)
9657 : {
9658 : const char* pszVersion = pfnVersion();
9659 : if (pszVersion && strstr(pszVersion, "Version 3.") != NULL)
9660 : {
9661 : CPLError(CE_Warning, CPLE_AppDefined,
9662 : "libtiff version mismatch : You're linking against libtiff 3.X, but GDAL has been compiled against libtiff >= 4.0.0");
9663 : }
9664 : }
9665 : #endif
9666 : #endif
9667 :
9668 447 : _ParentExtender = TIFFSetTagExtender(GTiffTagExtender);
9669 :
9670 447 : TIFFSetWarningHandler( GTiffWarningHandler );
9671 447 : TIFFSetErrorHandler( GTiffErrorHandler );
9672 :
9673 : // This only really needed if we are linked to an external libgeotiff
9674 : // with its own (lame) file searching logic.
9675 447 : LibgeotiffOneTimeInit();
9676 :
9677 447 : return TRUE;
9678 : }
9679 :
9680 : /************************************************************************/
9681 : /* GDALDeregister_GTiff() */
9682 : /************************************************************************/
9683 :
9684 : static
9685 550 : void GDALDeregister_GTiff( GDALDriver * )
9686 :
9687 : {
9688 550 : CSVDeaccess( NULL );
9689 :
9690 : #if defined(LIBGEOTIFF_VERSION) && LIBGEOTIFF_VERSION > 1150
9691 550 : GTIFDeaccessCSV();
9692 : #endif
9693 :
9694 550 : if( hGTiffOneTimeInitMutex != NULL )
9695 : {
9696 441 : CPLDestroyMutex(hGTiffOneTimeInitMutex);
9697 441 : hGTiffOneTimeInitMutex = NULL;
9698 : }
9699 :
9700 550 : LibgeotiffOneTimeCleanupMutex();
9701 550 : }
9702 :
9703 : /************************************************************************/
9704 : /* GTIFFGetCompressionMethod() */
9705 : /************************************************************************/
9706 :
9707 80 : int GTIFFGetCompressionMethod(const char* pszValue, const char* pszVariableName)
9708 : {
9709 80 : int nCompression = COMPRESSION_NONE;
9710 80 : if( EQUAL( pszValue, "NONE" ) )
9711 1 : nCompression = COMPRESSION_NONE;
9712 79 : else if( EQUAL( pszValue, "JPEG" ) )
9713 42 : nCompression = COMPRESSION_JPEG;
9714 37 : else if( EQUAL( pszValue, "LZW" ) )
9715 17 : nCompression = COMPRESSION_LZW;
9716 20 : else if( EQUAL( pszValue, "PACKBITS" ))
9717 2 : nCompression = COMPRESSION_PACKBITS;
9718 34 : else if( EQUAL( pszValue, "DEFLATE" ) || EQUAL( pszValue, "ZIP" ))
9719 16 : nCompression = COMPRESSION_ADOBE_DEFLATE;
9720 2 : else if( EQUAL( pszValue, "FAX3" )
9721 : || EQUAL( pszValue, "CCITTFAX3" ))
9722 0 : nCompression = COMPRESSION_CCITTFAX3;
9723 4 : else if( EQUAL( pszValue, "FAX4" )
9724 : || EQUAL( pszValue, "CCITTFAX4" ))
9725 2 : nCompression = COMPRESSION_CCITTFAX4;
9726 0 : else if( EQUAL( pszValue, "CCITTRLE" ) )
9727 0 : nCompression = COMPRESSION_CCITTRLE;
9728 0 : else if( EQUAL( pszValue, "LZMA" ) )
9729 0 : nCompression = COMPRESSION_LZMA;
9730 : else
9731 : CPLError( CE_Warning, CPLE_IllegalArg,
9732 : "%s=%s value not recognised, ignoring.",
9733 0 : pszVariableName,pszValue );
9734 :
9735 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
9736 80 : if (nCompression != COMPRESSION_NONE &&
9737 : !TIFFIsCODECConfigured((uint16) nCompression))
9738 : {
9739 : CPLError( CE_Failure, CPLE_AppDefined,
9740 0 : "Cannot create TIFF file due to missing codec for %s.", pszValue );
9741 0 : return -1;
9742 : }
9743 : #endif
9744 :
9745 80 : return nCompression;
9746 : }
9747 : /************************************************************************/
9748 : /* GDALRegister_GTiff() */
9749 : /************************************************************************/
9750 :
9751 610 : void GDALRegister_GTiff()
9752 :
9753 : {
9754 610 : if( GDALGetDriverByName( "GTiff" ) == NULL )
9755 : {
9756 : GDALDriver *poDriver;
9757 : char szCreateOptions[3072];
9758 : char szOptionalCompressItems[500];
9759 588 : int bHasJPEG = FALSE, bHasLZW = FALSE, bHasDEFLATE = FALSE, bHasLZMA = FALSE;
9760 :
9761 588 : poDriver = new GDALDriver();
9762 :
9763 : /* -------------------------------------------------------------------- */
9764 : /* Determine which compression codecs are available that we */
9765 : /* want to advertise. If we are using an old libtiff we won't */
9766 : /* be able to find out so we just assume all are available. */
9767 : /* -------------------------------------------------------------------- */
9768 : strcpy( szOptionalCompressItems,
9769 588 : " <Value>NONE</Value>" );
9770 :
9771 : #if TIFFLIB_VERSION <= 20040919
9772 : strcat( szOptionalCompressItems,
9773 : " <Value>PACKBITS</Value>"
9774 : " <Value>JPEG</Value>"
9775 : " <Value>LZW</Value>"
9776 : " <Value>DEFLATE</Value>" );
9777 : bHasLZW = bHasDEFLATE = TRUE;
9778 : #else
9779 588 : TIFFCodec *c, *codecs = TIFFGetConfiguredCODECs();
9780 :
9781 10584 : for( c = codecs; c->name; c++ )
9782 : {
9783 9996 : if( c->scheme == COMPRESSION_PACKBITS )
9784 : strcat( szOptionalCompressItems,
9785 588 : " <Value>PACKBITS</Value>" );
9786 9408 : else if( c->scheme == COMPRESSION_JPEG )
9787 : {
9788 588 : bHasJPEG = TRUE;
9789 : strcat( szOptionalCompressItems,
9790 588 : " <Value>JPEG</Value>" );
9791 : }
9792 8820 : else if( c->scheme == COMPRESSION_LZW )
9793 : {
9794 588 : bHasLZW = TRUE;
9795 : strcat( szOptionalCompressItems,
9796 588 : " <Value>LZW</Value>" );
9797 : }
9798 8232 : else if( c->scheme == COMPRESSION_ADOBE_DEFLATE )
9799 : {
9800 588 : bHasDEFLATE = TRUE;
9801 : strcat( szOptionalCompressItems,
9802 588 : " <Value>DEFLATE</Value>" );
9803 : }
9804 7644 : else if( c->scheme == COMPRESSION_CCITTRLE )
9805 : strcat( szOptionalCompressItems,
9806 588 : " <Value>CCITTRLE</Value>" );
9807 7056 : else if( c->scheme == COMPRESSION_CCITTFAX3 )
9808 : strcat( szOptionalCompressItems,
9809 588 : " <Value>CCITTFAX3</Value>" );
9810 6468 : else if( c->scheme == COMPRESSION_CCITTFAX4 )
9811 : strcat( szOptionalCompressItems,
9812 588 : " <Value>CCITTFAX4</Value>" );
9813 5880 : else if( c->scheme == COMPRESSION_LZMA )
9814 : {
9815 588 : bHasLZMA = TRUE;
9816 : strcat( szOptionalCompressItems,
9817 588 : " <Value>LZMA</Value>" );
9818 : }
9819 : }
9820 588 : _TIFFfree( codecs );
9821 : #endif
9822 :
9823 : /* -------------------------------------------------------------------- */
9824 : /* Build full creation option list. */
9825 : /* -------------------------------------------------------------------- */
9826 : sprintf( szCreateOptions, "%s%s%s",
9827 : "<CreationOptionList>"
9828 : " <Option name='COMPRESS' type='string-select'>",
9829 : szOptionalCompressItems,
9830 588 : " </Option>");
9831 588 : if (bHasLZW || bHasDEFLATE)
9832 : strcat( szCreateOptions, ""
9833 588 : " <Option name='PREDICTOR' type='int' description='Predictor Type'/>");
9834 588 : if (bHasJPEG)
9835 : {
9836 : strcat( szCreateOptions, ""
9837 588 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>" );
9838 : #ifdef JPEG_DIRECT_COPY
9839 : strcat( szCreateOptions, ""
9840 : " <Option name='JPEG_DIRECT_COPY' type='boolean' description='To copy without any decompression/recompression a JPEG source file' default='NO'/>");
9841 : #endif
9842 : }
9843 588 : if (bHasDEFLATE)
9844 : strcat( szCreateOptions, ""
9845 588 : " <Option name='ZLEVEL' type='int' description='DEFLATE compression level 1-9' default='6'/>");
9846 588 : if (bHasLZMA)
9847 : strcat( szCreateOptions, ""
9848 588 : " <Option name='LZMA_PRESET' type='int' description='LZMA compression level 0(fast)-9(slow)' default='6'/>");
9849 : strcat( szCreateOptions, ""
9850 : " <Option name='NBITS' type='int' description='BITS for sub-byte files (1-7), sub-uint16 (9-15), sub-uint32 (17-31)'/>"
9851 : " <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
9852 : " <Value>BAND</Value>"
9853 : " <Value>PIXEL</Value>"
9854 : " </Option>"
9855 : " <Option name='TILED' type='boolean' description='Switch to tiled format'/>"
9856 : " <Option name='TFW' type='boolean' description='Write out world file'/>"
9857 : " <Option name='RPB' type='boolean' description='Write out .RPB (RPC) file'/>"
9858 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
9859 : " <Option name='BLOCKYSIZE' type='int' description='Tile/Strip Height'/>"
9860 : " <Option name='PHOTOMETRIC' type='string-select'>"
9861 : " <Value>MINISBLACK</Value>"
9862 : " <Value>MINISWHITE</Value>"
9863 : " <Value>PALETTE</Value>"
9864 : " <Value>RGB</Value>"
9865 : " <Value>CMYK</Value>"
9866 : " <Value>YCBCR</Value>"
9867 : " <Value>CIELAB</Value>"
9868 : " <Value>ICCLAB</Value>"
9869 : " <Value>ITULAB</Value>"
9870 : " </Option>"
9871 : " <Option name='SPARSE_OK' type='boolean' description='Can newly created files have missing blocks?' default='FALSE'/>"
9872 : " <Option name='ALPHA' type='string-select' description='Mark first extrasample as being alpha'>"
9873 : " <Value>NON-PREMULTIPLIED</Value>"
9874 : " <Value>PREMULTIPLIED</Value>"
9875 : " <Value>UNSPECIFIED</Value>"
9876 : " <Value aliasOf='NON-PREMULTIPLIED'>YES</Value>"
9877 : " <Value aliasOf='UNSPECIFIED'>NO</Value>"
9878 : " </Option>"
9879 : " <Option name='PROFILE' type='string-select' default='GDALGeoTIFF'>"
9880 : " <Value>GDALGeoTIFF</Value>"
9881 : " <Value>GeoTIFF</Value>"
9882 : " <Value>BASELINE</Value>"
9883 : " </Option>"
9884 : " <Option name='PIXELTYPE' type='string-select'>"
9885 : " <Value>DEFAULT</Value>"
9886 : " <Value>SIGNEDBYTE</Value>"
9887 : " </Option>"
9888 : #ifdef BIGTIFF_SUPPORT
9889 : " <Option name='BIGTIFF' type='string-select' description='Force creation of BigTIFF file'>"
9890 : " <Value>YES</Value>"
9891 : " <Value>NO</Value>"
9892 : " <Value>IF_NEEDED</Value>"
9893 : " <Value>IF_SAFER</Value>"
9894 : " </Option>"
9895 : #endif
9896 : " <Option name='ENDIANNESS' type='string-select' default='NATIVE' description='Force endianness of created file. For DEBUG purpose mostly'>"
9897 : " <Value>NATIVE</Value>"
9898 : " <Value>INVERTED</Value>"
9899 : " <Value>LITTLE</Value>"
9900 : " <Value>BIG</Value>"
9901 : " </Option>"
9902 : " <Option name='COPY_SRC_OVERVIEWS' type='boolean' default='NO' description='Force copy of overviews of source dataset (CreateCopy())'/>"
9903 588 : "</CreationOptionList>" );
9904 :
9905 : /* -------------------------------------------------------------------- */
9906 : /* Set the driver details. */
9907 : /* -------------------------------------------------------------------- */
9908 588 : poDriver->SetDescription( "GTiff" );
9909 588 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoTIFF" );
9910 588 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_gtiff.html" );
9911 588 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/tiff" );
9912 588 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "tif" );
9913 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
9914 : "Byte UInt16 Int16 UInt32 Int32 Float32 "
9915 588 : "Float64 CInt16 CInt32 CFloat32 CFloat64" );
9916 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
9917 588 : szCreateOptions );
9918 588 : poDriver->SetMetadataItem( GDAL_DMD_SUBDATASETS, "YES" );
9919 588 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
9920 :
9921 588 : poDriver->pfnOpen = GTiffDataset::Open;
9922 588 : poDriver->pfnCreate = GTiffDataset::Create;
9923 588 : poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
9924 588 : poDriver->pfnUnloadDriver = GDALDeregister_GTiff;
9925 588 : poDriver->pfnIdentify = GTiffDataset::Identify;
9926 :
9927 588 : GetGDALDriverManager()->RegisterDriver( poDriver );
9928 : }
9929 610 : }
|