1 : /******************************************************************************
2 : * $Id: geotiff.cpp 19997 2010-07-09 17:43:54Z 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 : #include "gdal_pam.h"
31 : #define CPL_SERV_H_INCLUDED
32 :
33 : #include "tiffio.h"
34 : #include "xtiffio.h"
35 : #include "geotiff.h"
36 : #include "geo_normalize.h"
37 : #include "geovalues.h"
38 : #include "cpl_string.h"
39 : #include "cpl_csv.h"
40 : #include "cpl_minixml.h"
41 : #include "gt_overview.h"
42 : #include "ogr_spatialref.h"
43 :
44 : CPL_CVSID("$Id: geotiff.cpp 19997 2010-07-09 17:43:54Z rouault $");
45 :
46 : CPL_C_START
47 : char CPL_DLL * GTIFGetOGISDefn( GTIF *, GTIFDefn * );
48 : int CPL_DLL GTIFSetFromOGISDefn( GTIF *, const char * );
49 : const char * GDALDefaultCSVFilename( const char *pszBasename );
50 : GUInt32 HalfToFloat( GUInt16 );
51 : GUInt32 TripleToFloat( GUInt32 );
52 : void GTiffOneTimeInit();
53 : void GTIFFGetOverviewBlockSize(int* pnBlockXSize, int* pnBlockYSize);
54 : CPL_C_END
55 :
56 : #define TIFFTAG_GDAL_METADATA 42112
57 : #define TIFFTAG_GDAL_NODATA 42113
58 : #define TIFFTAG_RPCCOEFFICIENT 50844
59 :
60 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20081217 && defined(BIGTIFF_SUPPORT)
61 : # define HAVE_UNSETFIELD
62 : #endif
63 :
64 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20041016
65 : /* We need at least TIFF 3.7.0 for TIFFGetSizeProc and TIFFClientdata */
66 : # define HAVE_TIFFGETSIZEPROC
67 : #endif
68 :
69 : #if !defined(PREDICTOR_NONE)
70 : #define PREDICTOR_NONE 1
71 : #endif
72 :
73 : TIFF* VSI_TIFFOpen(const char* name, const char* mode);
74 :
75 :
76 : /************************************************************************/
77 : /* IsPowerOfTwo() */
78 : /************************************************************************/
79 :
80 127 : static int IsPowerOfTwo(unsigned int i)
81 : {
82 127 : int nBitSet = 0;
83 1274 : while(i != 0)
84 : {
85 1020 : if ((i & 1))
86 127 : nBitSet ++;
87 1020 : i >>= 1;
88 : }
89 127 : return nBitSet == 1;
90 : }
91 :
92 : /************************************************************************/
93 : /* GTIFFGetOverviewBlockSize() */
94 : /************************************************************************/
95 :
96 127 : void GTIFFGetOverviewBlockSize(int* pnBlockXSize, int* pnBlockYSize)
97 : {
98 : static int bHasWarned = FALSE;
99 127 : const char* pszVal = CPLGetConfigOption("GDAL_TIFF_OVR_BLOCKSIZE", "128");
100 127 : int nOvrBlockSize = atoi(pszVal);
101 127 : if (nOvrBlockSize < 64 || nOvrBlockSize > 4096 ||
102 : !IsPowerOfTwo(nOvrBlockSize))
103 : {
104 0 : if (!bHasWarned)
105 : {
106 : CPLError(CE_Warning, CPLE_NotSupported,
107 : "Wrong value for GDAL_TIFF_OVR_BLOCKSIZE : %s. "
108 : "Should be a power of 2 between 64 and 4096. Defaulting to 128",
109 0 : pszVal);
110 0 : bHasWarned = TRUE;
111 : }
112 0 : nOvrBlockSize = 128;
113 : }
114 :
115 127 : *pnBlockXSize = nOvrBlockSize;
116 127 : *pnBlockYSize = nOvrBlockSize;
117 127 : }
118 :
119 : enum
120 : {
121 : ENDIANNESS_NATIVE,
122 : ENDIANNESS_LITTLE,
123 : ENDIANNESS_BIG
124 : };
125 :
126 : /************************************************************************/
127 : /* ==================================================================== */
128 : /* GTiffDataset */
129 : /* ==================================================================== */
130 : /************************************************************************/
131 :
132 : class GTiffRasterBand;
133 : class GTiffRGBABand;
134 : class GTiffBitmapBand;
135 :
136 : class GTiffDataset : public GDALPamDataset
137 : {
138 : friend class GTiffRasterBand;
139 : friend class GTiffSplitBand;
140 : friend class GTiffRGBABand;
141 : friend class GTiffBitmapBand;
142 : friend class GTiffSplitBitmapBand;
143 : friend class GTiffOddBitsBand;
144 :
145 : TIFF *hTIFF;
146 : GTiffDataset **ppoActiveDSRef;
147 : GTiffDataset *poActiveDS; /* only used in actual base */
148 :
149 : toff_t nDirOffset;
150 : int bBase;
151 : int bCloseTIFFHandle; /* usefull for closing TIFF handle opened by GTIFF_DIR: */
152 :
153 : uint16 nPlanarConfig;
154 : uint16 nSamplesPerPixel;
155 : uint16 nBitsPerSample;
156 : uint32 nRowsPerStrip;
157 : uint16 nPhotometric;
158 : uint16 nSampleFormat;
159 : uint16 nCompression;
160 :
161 : int nBlocksPerBand;
162 :
163 : uint32 nBlockXSize;
164 : uint32 nBlockYSize;
165 :
166 : int nLoadedBlock; /* or tile */
167 : int bLoadedBlockDirty;
168 : GByte *pabyBlockBuf;
169 :
170 : CPLErr LoadBlockBuf( int nBlockId, int bReadFromDisk = TRUE );
171 : CPLErr FlushBlockBuf();
172 :
173 : char *pszProjection;
174 : int bLookedForProjection;
175 :
176 : void LookForProjection();
177 :
178 : double adfGeoTransform[6];
179 : int bGeoTransformValid;
180 :
181 : int bTreatAsRGBA;
182 : int bCrystalized;
183 :
184 : void Crystalize();
185 :
186 : GDALColorTable *poColorTable;
187 :
188 : void WriteGeoTIFFInfo();
189 : int SetDirectory( toff_t nDirOffset = 0 );
190 :
191 : int nOverviewCount;
192 : GTiffDataset **papoOverviewDS;
193 :
194 : int nGCPCount;
195 : GDAL_GCP *pasGCPList;
196 :
197 : int IsBlockAvailable( int nBlockId );
198 :
199 : int bGeoTIFFInfoChanged;
200 : int bNoDataSet;
201 : double dfNoDataValue;
202 :
203 : int bMetadataChanged;
204 :
205 : int bNeedsRewrite;
206 :
207 : void ApplyPamInfo();
208 : void PushMetadataToPam();
209 :
210 : GDALMultiDomainMetadata oGTiffMDMD;
211 :
212 : CPLString osProfile;
213 : char **papszCreationOptions;
214 :
215 : int bLoadingOtherBands;
216 :
217 : static void WriteRPCTag( TIFF *, char ** );
218 : void ReadRPCTag();
219 :
220 : void* pabyTempWriteBuffer;
221 : int nTempWriteBufferSize;
222 : int WriteEncodedTile(uint32 tile, void* data, int bPreserveDataBuffer);
223 : int WriteEncodedStrip(uint32 strip, void* data, int bPreserveDataBuffer);
224 :
225 : GTiffDataset* poMaskDS;
226 : GTiffDataset* poBaseDS;
227 :
228 : CPLString osFilename;
229 :
230 : int bFillEmptyTiles;
231 : void FillEmptyTiles(void);
232 :
233 : void FlushDirectory();
234 : CPLErr CleanOverviews();
235 :
236 : /* Used for the all-in-on-strip case */
237 : int nLastLineRead;
238 : int nLastBandRead;
239 : int bTreatAsSplit;
240 : int bTreatAsSplitBitmap;
241 :
242 : int bClipWarn;
243 :
244 : CPLString osRPBFile;
245 : int FindRPBFile(char** papszSiblingFiles);
246 : CPLString osRPCFile;
247 : int FindRPCFile(char** papszSiblingFiles);
248 : CPLString osIMDFile;
249 : int FindIMDFile(char** papszSiblingFiles);
250 :
251 : public:
252 : GTiffDataset();
253 : ~GTiffDataset();
254 :
255 : virtual const char *GetProjectionRef(void);
256 : virtual CPLErr SetProjection( const char * );
257 : virtual CPLErr GetGeoTransform( double * );
258 : virtual CPLErr SetGeoTransform( double * );
259 :
260 : virtual int GetGCPCount();
261 : virtual const char *GetGCPProjection();
262 : virtual const GDAL_GCP *GetGCPs();
263 : CPLErr SetGCPs( int, const GDAL_GCP *, const char * );
264 :
265 : virtual char **GetFileList(void);
266 :
267 : virtual CPLErr IBuildOverviews( const char *, int, int *, int, int *,
268 : GDALProgressFunc, void * );
269 :
270 : CPLErr OpenOffset( TIFF *, GTiffDataset **ppoActiveDSRef,
271 : toff_t nDirOffset, int bBaseIn, GDALAccess,
272 : int bAllowRGBAInterface = TRUE, int bReadGeoTransform = FALSE,
273 : char** papszSiblingFiles = NULL);
274 :
275 : static GDALDataset *OpenDir( GDALOpenInfo * );
276 : static GDALDataset *Open( GDALOpenInfo * );
277 : static int Identify( GDALOpenInfo * );
278 : static GDALDataset *Create( const char * pszFilename,
279 : int nXSize, int nYSize, int nBands,
280 : GDALDataType eType, char ** papszParmList );
281 : static GDALDataset *CreateCopy( const char * pszFilename,
282 : GDALDataset *poSrcDS,
283 : int bStrict, char ** papszOptions,
284 : GDALProgressFunc pfnProgress,
285 : void * pProgressData );
286 : virtual void FlushCache( void );
287 :
288 : virtual CPLErr SetMetadata( char **, const char * = "" );
289 : virtual char **GetMetadata( const char * pszDomain = "" );
290 : virtual CPLErr SetMetadataItem( const char*, const char*,
291 : const char* = "" );
292 : virtual const char *GetMetadataItem( const char * pszName,
293 : const char * pszDomain = "" );
294 : virtual void *GetInternalHandle( const char * );
295 :
296 : virtual CPLErr CreateMaskBand( int nFlags );
297 :
298 : // only needed by createcopy and close code.
299 : static int WriteMetadata( GDALDataset *, TIFF *, int, const char *,
300 : const char *, char **, int bExcludeRPBandIMGFileWriting = FALSE );
301 : static void WriteNoDataValue( TIFF *, double );
302 :
303 : static TIFF * CreateLL( const char * pszFilename,
304 : int nXSize, int nYSize, int nBands,
305 : GDALDataType eType, char **papszParmList );
306 :
307 : CPLErr WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data, int bPreserveDataBuffer);
308 : };
309 :
310 : /************************************************************************/
311 : /* ==================================================================== */
312 : /* GTiffRasterBand */
313 : /* ==================================================================== */
314 : /************************************************************************/
315 :
316 : class GTiffRasterBand : public GDALPamRasterBand
317 399204 : {
318 : friend class GTiffDataset;
319 :
320 : GDALColorInterp eBandInterp;
321 :
322 : int bHaveOffsetScale;
323 : double dfOffset;
324 : double dfScale;
325 : CPLString osUnitType;
326 :
327 : protected:
328 : GTiffDataset *poGDS;
329 : GDALMultiDomainMetadata oGTiffMDMD;
330 :
331 : int bNoDataSet;
332 : double dfNoDataValue;
333 :
334 : void NullBlock( void *pData );
335 :
336 : public:
337 : GTiffRasterBand( GTiffDataset *, int );
338 :
339 : // should override RasterIO eventually.
340 :
341 : virtual CPLErr IReadBlock( int, int, void * );
342 : virtual CPLErr IWriteBlock( int, int, void * );
343 :
344 : virtual GDALColorInterp GetColorInterpretation();
345 : virtual GDALColorTable *GetColorTable();
346 : virtual CPLErr SetColorTable( GDALColorTable * );
347 : virtual double GetNoDataValue( int * );
348 : virtual CPLErr SetNoDataValue( double );
349 :
350 : virtual double GetOffset( int *pbSuccess = NULL );
351 : virtual CPLErr SetOffset( double dfNewValue );
352 : virtual double GetScale( int *pbSuccess = NULL );
353 : virtual CPLErr SetScale( double dfNewValue );
354 : virtual const char* GetUnitType();
355 : virtual CPLErr SetUnitType( const char *pszNewValue );
356 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
357 :
358 : virtual CPLErr SetMetadata( char **, const char * = "" );
359 : virtual char **GetMetadata( const char * pszDomain = "" );
360 : virtual CPLErr SetMetadataItem( const char*, const char*,
361 : const char* = "" );
362 : virtual const char *GetMetadataItem( const char * pszName,
363 : const char * pszDomain = "" );
364 : virtual int GetOverviewCount();
365 : virtual GDALRasterBand *GetOverview( int );
366 :
367 : virtual GDALRasterBand *GetMaskBand();
368 : virtual int GetMaskFlags();
369 : virtual CPLErr CreateMaskBand( int nFlags );
370 : };
371 :
372 : /************************************************************************/
373 : /* GTiffRasterBand() */
374 : /************************************************************************/
375 :
376 399204 : GTiffRasterBand::GTiffRasterBand( GTiffDataset *poDS, int nBand )
377 :
378 : {
379 399204 : poGDS = poDS;
380 :
381 399204 : this->poDS = poDS;
382 399204 : this->nBand = nBand;
383 :
384 399204 : bHaveOffsetScale = FALSE;
385 399204 : dfOffset = 0.0;
386 399204 : dfScale = 1.0;
387 :
388 : /* -------------------------------------------------------------------- */
389 : /* Get the GDAL data type. */
390 : /* -------------------------------------------------------------------- */
391 399204 : uint16 nSampleFormat = poDS->nSampleFormat;
392 :
393 399204 : eDataType = GDT_Unknown;
394 :
395 399204 : if( poDS->nBitsPerSample <= 8 )
396 : {
397 396207 : eDataType = GDT_Byte;
398 396207 : if( nSampleFormat == SAMPLEFORMAT_INT )
399 5 : SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
400 :
401 : }
402 2997 : else if( poDS->nBitsPerSample <= 16 )
403 : {
404 691 : if( nSampleFormat == SAMPLEFORMAT_INT )
405 294 : eDataType = GDT_Int16;
406 : else
407 397 : eDataType = GDT_UInt16;
408 : }
409 2306 : else if( poDS->nBitsPerSample == 32 )
410 : {
411 1313 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
412 215 : eDataType = GDT_CInt16;
413 1098 : else if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
414 590 : eDataType = GDT_Float32;
415 508 : else if( nSampleFormat == SAMPLEFORMAT_INT )
416 253 : eDataType = GDT_Int32;
417 : else
418 255 : eDataType = GDT_UInt32;
419 : }
420 993 : else if( poDS->nBitsPerSample == 64 )
421 : {
422 695 : if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
423 255 : eDataType = GDT_Float64;
424 440 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
425 226 : eDataType = GDT_CFloat32;
426 214 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
427 214 : eDataType = GDT_CInt32;
428 : }
429 298 : else if( poDS->nBitsPerSample == 128 )
430 : {
431 230 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
432 230 : eDataType = GDT_CFloat64;
433 : }
434 :
435 : /* -------------------------------------------------------------------- */
436 : /* Try to work out band color interpretation. */
437 : /* -------------------------------------------------------------------- */
438 399300 : if( poDS->poColorTable != NULL && nBand == 1 )
439 96 : eBandInterp = GCI_PaletteIndex;
440 399108 : else if( poDS->nPhotometric == PHOTOMETRIC_RGB
441 : || (poDS->nPhotometric == PHOTOMETRIC_YCBCR
442 : && poDS->nCompression == COMPRESSION_JPEG
443 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
444 : "YES") )) )
445 : {
446 1267 : if( nBand == 1 )
447 396 : eBandInterp = GCI_RedBand;
448 871 : else if( nBand == 2 )
449 396 : eBandInterp = GCI_GreenBand;
450 475 : else if( nBand == 3 )
451 396 : eBandInterp = GCI_BlueBand;
452 : else
453 : {
454 : uint16 *v;
455 79 : uint16 count = 0;
456 :
457 79 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v) )
458 : {
459 141 : if( nBand - 3 <= count && v[nBand-4] == EXTRASAMPLE_ASSOCALPHA )
460 62 : eBandInterp = GCI_AlphaBand;
461 : else
462 17 : eBandInterp = GCI_Undefined;
463 : }
464 0 : else if( nBand == 4 )
465 0 : eBandInterp = GCI_AlphaBand;
466 : else
467 0 : eBandInterp = GCI_Undefined;
468 : }
469 : }
470 397841 : else if( poDS->nPhotometric == PHOTOMETRIC_YCBCR )
471 : {
472 0 : if( nBand == 1 )
473 0 : eBandInterp = GCI_YCbCr_YBand;
474 0 : else if( nBand == 2 )
475 0 : eBandInterp = GCI_YCbCr_CbBand;
476 0 : else if( nBand == 3 )
477 0 : eBandInterp = GCI_YCbCr_CrBand;
478 : else
479 : {
480 : uint16 *v;
481 0 : uint16 count = 0;
482 :
483 0 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v) )
484 : {
485 0 : if( nBand - 3 <= count && v[nBand-4] == EXTRASAMPLE_ASSOCALPHA )
486 0 : eBandInterp = GCI_AlphaBand;
487 : else
488 0 : eBandInterp = GCI_Undefined;
489 : }
490 0 : else if( nBand == 4 )
491 0 : eBandInterp = GCI_AlphaBand;
492 : else
493 0 : eBandInterp = GCI_Undefined;
494 : }
495 : }
496 397841 : else if( poDS->nPhotometric == PHOTOMETRIC_SEPARATED )
497 : {
498 40 : if( nBand == 1 )
499 10 : eBandInterp = GCI_CyanBand;
500 30 : else if( nBand == 2 )
501 10 : eBandInterp = GCI_MagentaBand;
502 20 : else if( nBand == 3 )
503 10 : eBandInterp = GCI_YellowBand;
504 : else
505 10 : eBandInterp = GCI_BlackBand;
506 : }
507 401875 : else if( poDS->nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1 )
508 4074 : eBandInterp = GCI_GrayIndex;
509 : else
510 : {
511 : uint16 *v;
512 393727 : uint16 count = 0;
513 :
514 393727 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v ) )
515 : {
516 : int nBaseSamples;
517 393602 : nBaseSamples = poDS->nSamplesPerPixel - count;
518 :
519 393609 : if( nBand > nBaseSamples
520 : && v[nBand-nBaseSamples-1] == EXTRASAMPLE_ASSOCALPHA )
521 7 : eBandInterp = GCI_AlphaBand;
522 : else
523 393595 : eBandInterp = GCI_Undefined;
524 : }
525 : else
526 125 : eBandInterp = GCI_Undefined;
527 : }
528 :
529 : /* -------------------------------------------------------------------- */
530 : /* Establish block size for strip or tiles. */
531 : /* -------------------------------------------------------------------- */
532 399204 : nBlockXSize = poDS->nBlockXSize;
533 399204 : nBlockYSize = poDS->nBlockYSize;
534 :
535 399204 : bNoDataSet = FALSE;
536 399204 : dfNoDataValue = -9999.0;
537 399204 : }
538 :
539 : /************************************************************************/
540 : /* IReadBlock() */
541 : /************************************************************************/
542 :
543 : CPLErr GTiffRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
544 82260 : void * pImage )
545 :
546 : {
547 : int nBlockBufSize, nBlockId, nBlockIdBand0;
548 82260 : CPLErr eErr = CE_None;
549 :
550 82260 : if (!poGDS->SetDirectory())
551 0 : return CE_Failure;
552 :
553 82260 : if( TIFFIsTiled(poGDS->hTIFF) )
554 10164 : nBlockBufSize = TIFFTileSize( poGDS->hTIFF );
555 : else
556 : {
557 72096 : CPLAssert( nBlockXOff == 0 );
558 72096 : nBlockBufSize = TIFFStripSize( poGDS->hTIFF );
559 : }
560 :
561 82260 : nBlockIdBand0 = nBlockXOff + nBlockYOff * nBlocksPerRow;
562 82260 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
563 478 : nBlockId = nBlockIdBand0 + (nBand-1) * poGDS->nBlocksPerBand;
564 : else
565 81782 : nBlockId = nBlockIdBand0;
566 :
567 : /* -------------------------------------------------------------------- */
568 : /* The bottom most partial tiles and strips are sometimes only */
569 : /* partially encoded. This code reduces the requested data so */
570 : /* an error won't be reported in this case. (#1179) */
571 : /* -------------------------------------------------------------------- */
572 82260 : int nBlockReqSize = nBlockBufSize;
573 :
574 82260 : if( (nBlockYOff+1) * nBlockYSize > nRasterYSize )
575 : {
576 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
577 1179 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
578 : }
579 :
580 : /* -------------------------------------------------------------------- */
581 : /* Handle the case of a strip or tile that doesn't exist yet. */
582 : /* Just set to zeros and return. */
583 : /* -------------------------------------------------------------------- */
584 82260 : if( !poGDS->IsBlockAvailable(nBlockId) )
585 : {
586 1942 : NullBlock( pImage );
587 1942 : return CE_None;
588 : }
589 :
590 : /* -------------------------------------------------------------------- */
591 : /* Handle simple case (separate, onesampleperpixel) */
592 : /* -------------------------------------------------------------------- */
593 80318 : if( poGDS->nBands == 1
594 : || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
595 : {
596 12014 : if( nBlockReqSize < nBlockBufSize )
597 375 : memset( pImage, 0, nBlockBufSize );
598 :
599 12014 : if( TIFFIsTiled( poGDS->hTIFF ) )
600 : {
601 8531 : if( TIFFReadEncodedTile( poGDS->hTIFF, nBlockId, pImage,
602 : nBlockReqSize ) == -1 )
603 : {
604 0 : memset( pImage, 0, nBlockBufSize );
605 : CPLError( CE_Failure, CPLE_AppDefined,
606 0 : "TIFFReadEncodedTile() failed.\n" );
607 :
608 0 : eErr = CE_Failure;
609 : }
610 : }
611 : else
612 : {
613 3483 : if( TIFFReadEncodedStrip( poGDS->hTIFF, nBlockId, pImage,
614 : nBlockReqSize ) == -1 )
615 : {
616 0 : memset( pImage, 0, nBlockBufSize );
617 : CPLError( CE_Failure, CPLE_AppDefined,
618 0 : "TIFFReadEncodedStrip() failed.\n" );
619 :
620 0 : eErr = CE_Failure;
621 : }
622 : }
623 :
624 12014 : return eErr;
625 : }
626 :
627 : /* -------------------------------------------------------------------- */
628 : /* Load desired block */
629 : /* -------------------------------------------------------------------- */
630 68304 : eErr = poGDS->LoadBlockBuf( nBlockId );
631 68304 : if( eErr != CE_None )
632 : {
633 : memset( pImage, 0,
634 : nBlockXSize * nBlockYSize
635 0 : * (GDALGetDataTypeSize(eDataType) / 8) );
636 0 : return eErr;
637 : }
638 :
639 : /* -------------------------------------------------------------------- */
640 : /* Special case for YCbCr subsampled data. */
641 : /* -------------------------------------------------------------------- */
642 : #ifdef notdef
643 : if( (eBandInterp == GCI_YCbCr_YBand
644 : || eBandInterp == GCI_YCbCr_CbBand
645 : || eBandInterp == GCI_YCbCr_CrBand)
646 : && poGDS->nBitsPerSample == 8 )
647 : {
648 : uint16 hs, vs;
649 : int iX, iY;
650 :
651 : TIFFGetFieldDefaulted( poGDS->hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
652 : &hs, &vs);
653 :
654 : for( iY = 0; iY < nBlockYSize; iY++ )
655 : {
656 : for( iX = 0; iX < nBlockXSize; iX++ )
657 : {
658 : int iBlock = (iY / vs) * (nBlockXSize/hs) + (iX / hs);
659 : GByte *pabySrcBlock = poGDS->pabyBlockBuf +
660 : (vs * hs + 2) * iBlock;
661 :
662 : if( eBandInterp == GCI_YCbCr_YBand )
663 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
664 : pabySrcBlock[(iX % hs) + (iY % vs) * hs];
665 : else if( eBandInterp == GCI_YCbCr_CbBand )
666 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
667 : pabySrcBlock[vs * hs + 0];
668 : else if( eBandInterp == GCI_YCbCr_CrBand )
669 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
670 : pabySrcBlock[vs * hs + 1];
671 : }
672 : }
673 :
674 : return CE_None;
675 : }
676 : #endif
677 :
678 : /* -------------------------------------------------------------------- */
679 : /* Handle simple case of eight bit data, and pixel interleaving. */
680 : /* -------------------------------------------------------------------- */
681 68304 : if( poGDS->nBitsPerSample == 8 )
682 : {
683 : int i, nBlockPixels;
684 : GByte *pabyImage;
685 68165 : GByte *pabyImageDest = (GByte*)pImage;
686 68165 : int nBands = poGDS->nBands;
687 :
688 68165 : pabyImage = poGDS->pabyBlockBuf + nBand - 1;
689 :
690 68165 : nBlockPixels = nBlockXSize * nBlockYSize;
691 :
692 : /* ==================================================================== */
693 : /* Optimization for high number of words to transfer and some */
694 : /* typical band numbers : we unroll the loop. */
695 : /* ==================================================================== */
696 : #define COPY_TO_DST_BUFFER(nBands) \
697 : if (nBlockPixels > 100) \
698 : { \
699 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
700 : { \
701 : pabyImageDest[0] = pabyImage[0*nBands]; \
702 : pabyImageDest[1] = pabyImage[1*nBands]; \
703 : pabyImageDest[2] = pabyImage[2*nBands]; \
704 : pabyImageDest[3] = pabyImage[3*nBands]; \
705 : pabyImageDest[4] = pabyImage[4*nBands]; \
706 : pabyImageDest[5] = pabyImage[5*nBands]; \
707 : pabyImageDest[6] = pabyImage[6*nBands]; \
708 : pabyImageDest[7] = pabyImage[7*nBands]; \
709 : pabyImageDest[8] = pabyImage[8*nBands]; \
710 : pabyImageDest[9] = pabyImage[9*nBands]; \
711 : pabyImageDest[10] = pabyImage[10*nBands]; \
712 : pabyImageDest[11] = pabyImage[11*nBands]; \
713 : pabyImageDest[12] = pabyImage[12*nBands]; \
714 : pabyImageDest[13] = pabyImage[13*nBands]; \
715 : pabyImageDest[14] = pabyImage[14*nBands]; \
716 : pabyImageDest[15] = pabyImage[15*nBands]; \
717 : pabyImageDest += 16; \
718 : pabyImage += 16*nBands; \
719 : } \
720 : nBlockPixels = nBlockPixels % 16; \
721 : } \
722 : for( i = 0; i < nBlockPixels; i++ ) \
723 : { \
724 : pabyImageDest[i] = *pabyImage; \
725 : pabyImage += nBands; \
726 : }
727 :
728 68165 : switch (nBands)
729 : {
730 2113 : case 3: COPY_TO_DST_BUFFER(3); break;
731 452 : case 4: COPY_TO_DST_BUFFER(4); break;
732 : default:
733 : {
734 507415 : for( i = 0; i < nBlockPixels; i++ )
735 : {
736 441815 : pabyImageDest[i] = *pabyImage;
737 441815 : pabyImage += nBands;
738 : }
739 : }
740 : }
741 : }
742 :
743 : else
744 : {
745 : int i, nBlockPixels, nWordBytes;
746 : GByte *pabyImage;
747 :
748 139 : nWordBytes = poGDS->nBitsPerSample / 8;
749 139 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
750 :
751 139 : nBlockPixels = nBlockXSize * nBlockYSize;
752 566627 : for( i = 0; i < nBlockPixels; i++ )
753 : {
754 2866200 : for( int j = 0; j < nWordBytes; j++ )
755 : {
756 2299712 : ((GByte *) pImage)[i*nWordBytes + j] = pabyImage[j];
757 : }
758 566488 : pabyImage += poGDS->nBands * nWordBytes;
759 : }
760 : }
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* In the fairly common case of pixel interleaved 8bit data */
764 : /* that is multi-band, lets push the rest of the data into the */
765 : /* block cache too, to avoid (hopefully) having to redecode it. */
766 : /* */
767 : /* Our following logic actually depends on the fact that the */
768 : /* this block is already loaded, so subsequent calls will end */
769 : /* up back in this method and pull from the loaded block. */
770 : /* */
771 : /* Be careful not entering this portion of code from */
772 : /* the other bands, otherwise we'll get very deep nested calls */
773 : /* and O(nBands^2) performance ! */
774 : /* */
775 : /* If there are many bands and the block cache size is not big */
776 : /* enough to accomodate the size of all the blocks, don't enter */
777 : /* -------------------------------------------------------------------- */
778 68304 : if( poGDS->nBands != 1 && eErr == CE_None && !poGDS->bLoadingOtherBands &&
779 : nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) < GDALGetCacheMax() / poGDS->nBands)
780 : {
781 : int iOtherBand;
782 :
783 896 : poGDS->bLoadingOtherBands = TRUE;
784 :
785 69197 : for( iOtherBand = 1; iOtherBand <= poGDS->nBands; iOtherBand++ )
786 : {
787 68301 : if( iOtherBand == nBand )
788 896 : continue;
789 :
790 : GDALRasterBlock *poBlock;
791 :
792 : poBlock = poGDS->GetRasterBand(iOtherBand)->
793 67405 : GetLockedBlockRef(nBlockXOff,nBlockYOff);
794 67405 : if (poBlock == NULL)
795 : {
796 0 : eErr = CE_Failure;
797 0 : break;
798 : }
799 67405 : poBlock->DropLock();
800 : }
801 :
802 896 : poGDS->bLoadingOtherBands = FALSE;
803 : }
804 :
805 68304 : return eErr;
806 : }
807 :
808 : /************************************************************************/
809 : /* IWriteBlock() */
810 : /************************************************************************/
811 :
812 : CPLErr GTiffRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
813 13217 : void * pImage )
814 :
815 : {
816 : int nBlockId;
817 13217 : CPLErr eErr = CE_None;
818 :
819 13217 : if (!poGDS->SetDirectory())
820 0 : return CE_Failure;
821 :
822 13217 : CPLAssert( poGDS != NULL
823 : && nBlockXOff >= 0
824 : && nBlockYOff >= 0
825 : && pImage != NULL );
826 :
827 : /* -------------------------------------------------------------------- */
828 : /* Handle case of "separate" images */
829 : /* -------------------------------------------------------------------- */
830 13217 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
831 : || poGDS->nBands == 1 )
832 : {
833 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow
834 12475 : + (nBand-1) * poGDS->nBlocksPerBand;
835 :
836 12475 : eErr = poGDS->WriteEncodedTileOrStrip(nBlockId, pImage, TRUE);
837 :
838 12475 : return eErr;
839 : }
840 :
841 : /* -------------------------------------------------------------------- */
842 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
843 : /* -------------------------------------------------------------------- */
844 :
845 742 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
846 :
847 742 : eErr = poGDS->LoadBlockBuf( nBlockId );
848 742 : if( eErr != CE_None )
849 0 : return eErr;
850 :
851 : /* -------------------------------------------------------------------- */
852 : /* On write of pixel interleaved data, we might as well flush */
853 : /* out any other bands that are dirty in our cache. This is */
854 : /* especially helpful when writing compressed blocks. */
855 : /* -------------------------------------------------------------------- */
856 : int iBand;
857 742 : int nWordBytes = poGDS->nBitsPerSample / 8;
858 :
859 3044 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
860 : {
861 2302 : const GByte *pabyThisImage = NULL;
862 2302 : GDALRasterBlock *poBlock = NULL;
863 :
864 2302 : if( iBand+1 == nBand )
865 742 : pabyThisImage = (GByte *) pImage;
866 : else
867 : {
868 : poBlock = ((GTiffRasterBand *)poGDS->GetRasterBand( iBand+1 ))
869 1560 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
870 :
871 1560 : if( poBlock == NULL )
872 117 : continue;
873 :
874 1443 : if( !poBlock->GetDirty() )
875 : {
876 89 : poBlock->DropLock();
877 89 : continue;
878 : }
879 :
880 1354 : pabyThisImage = (GByte *) poBlock->GetDataRef();
881 : }
882 :
883 2096 : int i, nBlockPixels = nBlockXSize * nBlockYSize;
884 2096 : GByte *pabyOut = poGDS->pabyBlockBuf + iBand*nWordBytes;
885 :
886 11560355 : for( i = 0; i < nBlockPixels; i++ )
887 : {
888 11558259 : memcpy( pabyOut, pabyThisImage, nWordBytes );
889 :
890 11558259 : pabyOut += nWordBytes * poGDS->nBands;
891 11558259 : pabyThisImage += nWordBytes;
892 : }
893 :
894 2096 : if( poBlock != NULL )
895 : {
896 1354 : poBlock->MarkClean();
897 1354 : poBlock->DropLock();
898 : }
899 : }
900 :
901 742 : poGDS->bLoadedBlockDirty = TRUE;
902 :
903 742 : return CE_None;
904 : }
905 :
906 : /************************************************************************/
907 : /* GetOffset() */
908 : /************************************************************************/
909 :
910 133248 : double GTiffRasterBand::GetOffset( int *pbSuccess )
911 :
912 : {
913 133248 : if( pbSuccess )
914 132944 : *pbSuccess = bHaveOffsetScale;
915 133248 : return dfOffset;
916 : }
917 :
918 : /************************************************************************/
919 : /* SetOffset() */
920 : /************************************************************************/
921 :
922 10 : CPLErr GTiffRasterBand::SetOffset( double dfNewValue )
923 :
924 : {
925 10 : if( !bHaveOffsetScale || dfNewValue != dfOffset )
926 10 : poGDS->bMetadataChanged = TRUE;
927 :
928 10 : bHaveOffsetScale = TRUE;
929 10 : dfOffset = dfNewValue;
930 10 : return CE_None;
931 : }
932 :
933 : /************************************************************************/
934 : /* GetScale() */
935 : /************************************************************************/
936 :
937 133248 : double GTiffRasterBand::GetScale( int *pbSuccess )
938 :
939 : {
940 133248 : if( pbSuccess )
941 705 : *pbSuccess = bHaveOffsetScale;
942 133248 : return dfScale;
943 : }
944 :
945 : /************************************************************************/
946 : /* SetScale() */
947 : /************************************************************************/
948 :
949 10 : CPLErr GTiffRasterBand::SetScale( double dfNewValue )
950 :
951 : {
952 10 : if( !bHaveOffsetScale || dfNewValue != dfScale )
953 10 : poGDS->bMetadataChanged = TRUE;
954 :
955 10 : bHaveOffsetScale = TRUE;
956 10 : dfScale = dfNewValue;
957 10 : return CE_None;
958 : }
959 :
960 : /************************************************************************/
961 : /* GetUnitType() */
962 : /************************************************************************/
963 :
964 132726 : const char* GTiffRasterBand::GetUnitType()
965 :
966 : {
967 132726 : return osUnitType.c_str();
968 : }
969 :
970 : /************************************************************************/
971 : /* SetUnitType() */
972 : /************************************************************************/
973 :
974 17 : CPLErr GTiffRasterBand::SetUnitType( const char* pszNewValue )
975 :
976 : {
977 17 : CPLString osNewValue(pszNewValue ? pszNewValue : "");
978 17 : if( osNewValue.compare(osUnitType) != 0 )
979 17 : poGDS->bMetadataChanged = TRUE;
980 :
981 17 : osUnitType = osNewValue;
982 17 : return CE_None;
983 : }
984 :
985 : /************************************************************************/
986 : /* GetMetadata() */
987 : /************************************************************************/
988 :
989 1498 : char **GTiffRasterBand::GetMetadata( const char * pszDomain )
990 :
991 : {
992 1498 : return oGTiffMDMD.GetMetadata( pszDomain );
993 : }
994 :
995 : /************************************************************************/
996 : /* SetMetadata() */
997 : /************************************************************************/
998 :
999 258 : CPLErr GTiffRasterBand::SetMetadata( char ** papszMD, const char *pszDomain )
1000 :
1001 : {
1002 258 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1003 : {
1004 258 : if( papszMD != NULL )
1005 33 : poGDS->bMetadataChanged = TRUE;
1006 : }
1007 :
1008 258 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* GetMetadataItem() */
1013 : /************************************************************************/
1014 :
1015 : const char *GTiffRasterBand::GetMetadataItem( const char * pszName,
1016 1664 : const char * pszDomain )
1017 :
1018 : {
1019 1664 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
1020 : }
1021 :
1022 : /************************************************************************/
1023 : /* SetMetadataItem() */
1024 : /************************************************************************/
1025 :
1026 : CPLErr GTiffRasterBand::SetMetadataItem( const char *pszName,
1027 : const char *pszValue,
1028 583 : const char *pszDomain )
1029 :
1030 : {
1031 583 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
1032 583 : poGDS->bMetadataChanged = TRUE;
1033 :
1034 583 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
1035 : }
1036 :
1037 : /************************************************************************/
1038 : /* GetColorInterpretation() */
1039 : /************************************************************************/
1040 :
1041 2362 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1042 :
1043 : {
1044 2362 : return eBandInterp;
1045 : }
1046 :
1047 : /************************************************************************/
1048 : /* SetColorInterpretation() */
1049 : /************************************************************************/
1050 :
1051 20 : CPLErr GTiffRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
1052 :
1053 : {
1054 20 : if( eInterp == eBandInterp )
1055 12 : return CE_None;
1056 :
1057 8 : if( poGDS->bCrystalized )
1058 0 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1059 :
1060 : /* greyscale + alpha */
1061 8 : else if( eInterp == GCI_AlphaBand
1062 : && nBand == 2
1063 : && poGDS->nSamplesPerPixel == 2
1064 : && poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK )
1065 : {
1066 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
1067 :
1068 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1069 1 : eBandInterp = eInterp;
1070 1 : return CE_None;
1071 : }
1072 :
1073 : /* RGB + alpha */
1074 7 : else if( eInterp == GCI_AlphaBand
1075 : && nBand == 4
1076 : && poGDS->nSamplesPerPixel == 4
1077 : && poGDS->nPhotometric == PHOTOMETRIC_RGB )
1078 : {
1079 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
1080 :
1081 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
1082 1 : eBandInterp = eInterp;
1083 1 : return CE_None;
1084 : }
1085 :
1086 : else
1087 6 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
1088 : }
1089 :
1090 : /************************************************************************/
1091 : /* GetColorTable() */
1092 : /************************************************************************/
1093 :
1094 1712 : GDALColorTable *GTiffRasterBand::GetColorTable()
1095 :
1096 : {
1097 1712 : if( nBand == 1 )
1098 1397 : return poGDS->poColorTable;
1099 : else
1100 315 : return NULL;
1101 : }
1102 :
1103 : /************************************************************************/
1104 : /* SetColorTable() */
1105 : /************************************************************************/
1106 :
1107 14 : CPLErr GTiffRasterBand::SetColorTable( GDALColorTable * poCT )
1108 :
1109 : {
1110 : /* -------------------------------------------------------------------- */
1111 : /* Check if this is even a candidate for applying a PCT. */
1112 : /* -------------------------------------------------------------------- */
1113 14 : if( nBand != 1)
1114 : {
1115 : CPLError( CE_Failure, CPLE_NotSupported,
1116 0 : "SetColorTable() can only be called on band 1." );
1117 0 : return CE_Failure;
1118 : }
1119 :
1120 14 : if( poGDS->nSamplesPerPixel != 1 && poGDS->nSamplesPerPixel != 2)
1121 : {
1122 : CPLError( CE_Failure, CPLE_NotSupported,
1123 0 : "SetColorTable() not supported for multi-sample TIFF files." );
1124 0 : return CE_Failure;
1125 : }
1126 :
1127 14 : if( eDataType != GDT_Byte && eDataType != GDT_UInt16 )
1128 : {
1129 : CPLError( CE_Failure, CPLE_NotSupported,
1130 0 : "SetColorTable() only supported for Byte or UInt16 bands in TIFF format." );
1131 0 : return CE_Failure;
1132 : }
1133 :
1134 : /* -------------------------------------------------------------------- */
1135 : /* We are careful about calling SetDirectory() to avoid */
1136 : /* prematurely crystalizing the directory. (#2820) */
1137 : /* -------------------------------------------------------------------- */
1138 14 : if( poGDS->bCrystalized )
1139 : {
1140 4 : if (!poGDS->SetDirectory())
1141 0 : return CE_Failure;
1142 : }
1143 :
1144 : /* -------------------------------------------------------------------- */
1145 : /* Is this really a request to clear the color table? */
1146 : /* -------------------------------------------------------------------- */
1147 14 : if( poCT == NULL || poCT->GetColorEntryCount() == 0 )
1148 : {
1149 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC,
1150 1 : PHOTOMETRIC_MINISBLACK );
1151 :
1152 : #ifdef HAVE_UNSETFIELD
1153 1 : TIFFUnsetField( poGDS->hTIFF, TIFFTAG_COLORMAP );
1154 : #else
1155 : CPLDebug( "GTiff",
1156 : "TIFFUnsetField() not supported, colormap may not be cleared." );
1157 : #endif
1158 :
1159 1 : if( poGDS->poColorTable )
1160 : {
1161 1 : delete poGDS->poColorTable;
1162 1 : poGDS->poColorTable = NULL;
1163 : }
1164 :
1165 1 : return CE_None;
1166 : }
1167 :
1168 : /* -------------------------------------------------------------------- */
1169 : /* Write out the colortable, and update the configuration. */
1170 : /* -------------------------------------------------------------------- */
1171 : int nColors;
1172 :
1173 13 : if( eDataType == GDT_Byte )
1174 12 : nColors = 256;
1175 : else
1176 1 : nColors = 65536;
1177 :
1178 : unsigned short *panTRed, *panTGreen, *panTBlue;
1179 :
1180 13 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1181 13 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1182 13 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1183 :
1184 68621 : for( int iColor = 0; iColor < nColors; iColor++ )
1185 : {
1186 68608 : if( iColor < poCT->GetColorEntryCount() )
1187 : {
1188 : GDALColorEntry sRGB;
1189 :
1190 696 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
1191 :
1192 696 : panTRed[iColor] = (unsigned short) (257 * sRGB.c1);
1193 696 : panTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
1194 696 : panTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
1195 : }
1196 : else
1197 : {
1198 67912 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
1199 : }
1200 : }
1201 :
1202 13 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
1203 : TIFFSetField( poGDS->hTIFF, TIFFTAG_COLORMAP,
1204 13 : panTRed, panTGreen, panTBlue );
1205 :
1206 13 : CPLFree( panTRed );
1207 13 : CPLFree( panTGreen );
1208 13 : CPLFree( panTBlue );
1209 :
1210 13 : if( poGDS->poColorTable )
1211 3 : delete poGDS->poColorTable;
1212 :
1213 : /* libtiff 3.X needs setting this in all cases (creation or update) */
1214 : /* whereas libtiff 4.X would just need it if there */
1215 : /* was no color table before */
1216 : #if 0
1217 : else
1218 : #endif
1219 13 : poGDS->bNeedsRewrite = TRUE;
1220 :
1221 13 : poGDS->poColorTable = poCT->Clone();
1222 :
1223 13 : return CE_None;
1224 : }
1225 :
1226 : /************************************************************************/
1227 : /* GetNoDataValue() */
1228 : /************************************************************************/
1229 :
1230 4745 : double GTiffRasterBand::GetNoDataValue( int * pbSuccess )
1231 :
1232 : {
1233 4745 : if( bNoDataSet )
1234 : {
1235 91 : if( pbSuccess )
1236 82 : *pbSuccess = TRUE;
1237 :
1238 91 : return dfNoDataValue;
1239 : }
1240 :
1241 4654 : if( poGDS->bNoDataSet )
1242 : {
1243 222 : if( pbSuccess )
1244 215 : *pbSuccess = TRUE;
1245 :
1246 222 : return poGDS->dfNoDataValue;
1247 : }
1248 :
1249 4432 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
1250 : }
1251 :
1252 : /************************************************************************/
1253 : /* SetNoDataValue() */
1254 : /************************************************************************/
1255 :
1256 64 : CPLErr GTiffRasterBand::SetNoDataValue( double dfNoData )
1257 :
1258 : {
1259 64 : if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
1260 16 : return CE_None;
1261 :
1262 48 : if (!poGDS->SetDirectory()) // needed to call TIFFSetField().
1263 0 : return CE_Failure;
1264 :
1265 48 : poGDS->bNoDataSet = TRUE;
1266 48 : poGDS->dfNoDataValue = dfNoData;
1267 :
1268 48 : poGDS->WriteNoDataValue( poGDS->hTIFF, dfNoData );
1269 48 : poGDS->bNeedsRewrite = TRUE;
1270 :
1271 48 : bNoDataSet = TRUE;
1272 48 : dfNoDataValue = dfNoData;
1273 48 : return CE_None;
1274 : }
1275 :
1276 : /************************************************************************/
1277 : /* NullBlock() */
1278 : /* */
1279 : /* Set the block data to the null value if it is set, or zero */
1280 : /* if there is no null data value. */
1281 : /************************************************************************/
1282 :
1283 1961 : void GTiffRasterBand::NullBlock( void *pData )
1284 :
1285 : {
1286 1961 : int nWords = nBlockXSize * nBlockYSize;
1287 1961 : int nChunkSize = MAX(1,GDALGetDataTypeSize(eDataType)/8);
1288 :
1289 : int bNoDataSet;
1290 1961 : double dfNoData = GetNoDataValue( &bNoDataSet );
1291 1961 : if( !bNoDataSet )
1292 : {
1293 1877 : memset( pData, 0, nWords*nChunkSize );
1294 : }
1295 : else
1296 : {
1297 : /* Will convert nodata value to the right type and copy efficiently */
1298 : GDALCopyWords( &dfNoData, GDT_Float64, 0,
1299 84 : pData, eDataType, nChunkSize, nWords);
1300 : }
1301 1961 : }
1302 :
1303 : /************************************************************************/
1304 : /* GetOverviewCount() */
1305 : /************************************************************************/
1306 :
1307 300184 : int GTiffRasterBand::GetOverviewCount()
1308 :
1309 : {
1310 300184 : if( poGDS->nOverviewCount > 0 )
1311 674 : return poGDS->nOverviewCount;
1312 : else
1313 299510 : return GDALRasterBand::GetOverviewCount();
1314 : }
1315 :
1316 : /************************************************************************/
1317 : /* GetOverview() */
1318 : /************************************************************************/
1319 :
1320 707 : GDALRasterBand *GTiffRasterBand::GetOverview( int i )
1321 :
1322 : {
1323 707 : if( poGDS->nOverviewCount > 0 )
1324 : {
1325 479 : if( i < 0 || i >= poGDS->nOverviewCount )
1326 0 : return NULL;
1327 : else
1328 479 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
1329 : }
1330 : else
1331 228 : return GDALRasterBand::GetOverview( i );
1332 : }
1333 :
1334 : /************************************************************************/
1335 : /* GetMaskFlags() */
1336 : /************************************************************************/
1337 :
1338 1238 : int GTiffRasterBand::GetMaskFlags()
1339 : {
1340 1238 : if( poGDS->poMaskDS != NULL )
1341 : {
1342 : int iBand;
1343 24 : int nMaskFlag = 0;
1344 24 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1345 : {
1346 18 : iBand = 1;
1347 18 : nMaskFlag = GMF_PER_DATASET;
1348 : }
1349 : else
1350 : {
1351 6 : iBand = nBand;
1352 : }
1353 24 : if( poGDS->poMaskDS->GetRasterBand(iBand)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
1354 : && atoi(poGDS->poMaskDS->GetRasterBand(iBand)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) == 1)
1355 : {
1356 20 : return nMaskFlag;
1357 : }
1358 : else
1359 : {
1360 4 : return nMaskFlag | GMF_ALPHA;
1361 : }
1362 : }
1363 : else
1364 1214 : return GDALPamRasterBand::GetMaskFlags();
1365 : }
1366 :
1367 : /************************************************************************/
1368 : /* GetMaskBand() */
1369 : /************************************************************************/
1370 :
1371 476 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1372 : {
1373 476 : if( poGDS->poMaskDS != NULL )
1374 : {
1375 43 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1376 37 : return poGDS->poMaskDS->GetRasterBand(1);
1377 : else
1378 6 : return poGDS->poMaskDS->GetRasterBand(nBand);
1379 : }
1380 : else
1381 433 : return GDALPamRasterBand::GetMaskBand();
1382 : }
1383 :
1384 : /************************************************************************/
1385 : /* ==================================================================== */
1386 : /* GTiffSplitBand */
1387 : /* ==================================================================== */
1388 : /************************************************************************/
1389 :
1390 : class GTiffSplitBand : public GTiffRasterBand
1391 : {
1392 : friend class GTiffDataset;
1393 :
1394 : public:
1395 :
1396 : GTiffSplitBand( GTiffDataset *, int );
1397 : virtual ~GTiffSplitBand();
1398 :
1399 : virtual CPLErr IReadBlock( int, int, void * );
1400 : virtual CPLErr IWriteBlock( int, int, void * );
1401 : };
1402 :
1403 : /************************************************************************/
1404 : /* GTiffSplitBand() */
1405 : /************************************************************************/
1406 :
1407 24 : GTiffSplitBand::GTiffSplitBand( GTiffDataset *poDS, int nBand )
1408 24 : : GTiffRasterBand( poDS, nBand )
1409 :
1410 : {
1411 24 : nBlockXSize = poDS->GetRasterXSize();
1412 24 : nBlockYSize = 1;
1413 24 : }
1414 :
1415 : /************************************************************************/
1416 : /* ~GTiffSplitBand() */
1417 : /************************************************************************/
1418 :
1419 24 : GTiffSplitBand::~GTiffSplitBand()
1420 : {
1421 24 : }
1422 :
1423 : /************************************************************************/
1424 : /* IReadBlock() */
1425 : /************************************************************************/
1426 :
1427 : CPLErr GTiffSplitBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1428 66144 : void * pImage )
1429 :
1430 : {
1431 : (void) nBlockXOff;
1432 :
1433 : /* Optimization when reading the same line in a contig multi-band TIFF */
1434 66144 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 &&
1435 : poGDS->nLastLineRead == nBlockYOff )
1436 : {
1437 9 : goto extract_band_data;
1438 : }
1439 :
1440 66135 : if (!poGDS->SetDirectory())
1441 0 : return CE_Failure;
1442 :
1443 102270 : if (poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
1444 : poGDS->nBands > 1)
1445 : {
1446 36135 : if (poGDS->pabyBlockBuf == NULL)
1447 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
1448 : }
1449 : else
1450 : {
1451 30000 : CPLAssert(TIFFScanlineSize(poGDS->hTIFF) == nBlockXSize);
1452 : }
1453 :
1454 : /* -------------------------------------------------------------------- */
1455 : /* Read through to target scanline. */
1456 : /* -------------------------------------------------------------------- */
1457 66135 : if( poGDS->nLastLineRead >= nBlockYOff )
1458 31 : poGDS->nLastLineRead = -1;
1459 :
1460 66135 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE && poGDS->nBands > 1 )
1461 : {
1462 : /* If we change of band, we must start reading the */
1463 : /* new strip from its beginning */
1464 30000 : if ( poGDS->nLastBandRead != nBand )
1465 20 : poGDS->nLastLineRead = -1;
1466 30000 : poGDS->nLastBandRead = nBand;
1467 : }
1468 :
1469 247718 : while( poGDS->nLastLineRead < nBlockYOff )
1470 : {
1471 115448 : if( TIFFReadScanline( poGDS->hTIFF,
1472 : poGDS->pabyBlockBuf ? poGDS->pabyBlockBuf : pImage,
1473 : ++poGDS->nLastLineRead,
1474 : (poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE) ? nBand-1 : 0 ) == -1 )
1475 : {
1476 : CPLError( CE_Failure, CPLE_AppDefined,
1477 0 : "TIFFReadScanline() failed." );
1478 0 : return CE_Failure;
1479 : }
1480 : }
1481 :
1482 66144 : extract_band_data:
1483 : /* -------------------------------------------------------------------- */
1484 : /* Extract band data from contig buffer. */
1485 : /* -------------------------------------------------------------------- */
1486 66144 : if ( poGDS->pabyBlockBuf != NULL )
1487 : {
1488 36144 : int iPixel, iSrcOffset= nBand - 1, iDstOffset=0;
1489 :
1490 164448 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset+=poGDS->nBands, iDstOffset++ )
1491 : {
1492 128304 : ((GByte *) pImage)[iDstOffset] = poGDS->pabyBlockBuf[iSrcOffset];
1493 : }
1494 : }
1495 :
1496 66144 : return CE_None;
1497 : }
1498 :
1499 : /************************************************************************/
1500 : /* IWriteBlock() */
1501 : /************************************************************************/
1502 :
1503 : CPLErr GTiffSplitBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1504 0 : void * pImage )
1505 :
1506 : {
1507 : (void) nBlockXOff;
1508 : (void) nBlockYOff;
1509 : (void) pImage;
1510 :
1511 : CPLError( CE_Failure, CPLE_AppDefined,
1512 0 : "Split bands are read-only." );
1513 0 : return CE_Failure;
1514 : }
1515 :
1516 : /************************************************************************/
1517 : /* ==================================================================== */
1518 : /* GTiffRGBABand */
1519 : /* ==================================================================== */
1520 : /************************************************************************/
1521 :
1522 : class GTiffRGBABand : public GTiffRasterBand
1523 16 : {
1524 : friend class GTiffDataset;
1525 :
1526 : public:
1527 :
1528 : GTiffRGBABand( GTiffDataset *, int );
1529 :
1530 : virtual CPLErr IReadBlock( int, int, void * );
1531 : virtual CPLErr IWriteBlock( int, int, void * );
1532 :
1533 : virtual GDALColorInterp GetColorInterpretation();
1534 : };
1535 :
1536 :
1537 : /************************************************************************/
1538 : /* GTiffRGBABand() */
1539 : /************************************************************************/
1540 :
1541 16 : GTiffRGBABand::GTiffRGBABand( GTiffDataset *poDS, int nBand )
1542 16 : : GTiffRasterBand( poDS, nBand )
1543 :
1544 : {
1545 16 : eDataType = GDT_Byte;
1546 16 : }
1547 :
1548 : /************************************************************************/
1549 : /* IWriteBlock() */
1550 : /************************************************************************/
1551 :
1552 0 : CPLErr GTiffRGBABand::IWriteBlock( int, int, void * )
1553 :
1554 : {
1555 : CPLError( CE_Failure, CPLE_AppDefined,
1556 0 : "RGBA interpreted raster bands are read-only." );
1557 0 : return CE_Failure;
1558 : }
1559 :
1560 : /************************************************************************/
1561 : /* IReadBlock() */
1562 : /************************************************************************/
1563 :
1564 : CPLErr GTiffRGBABand::IReadBlock( int nBlockXOff, int nBlockYOff,
1565 6 : void * pImage )
1566 :
1567 : {
1568 : int nBlockBufSize, nBlockId;
1569 6 : CPLErr eErr = CE_None;
1570 :
1571 6 : if (!poGDS->SetDirectory())
1572 0 : return CE_Failure;
1573 :
1574 6 : nBlockBufSize = 4 * nBlockXSize * nBlockYSize;
1575 6 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1576 :
1577 : /* -------------------------------------------------------------------- */
1578 : /* Allocate a temporary buffer for this strip. */
1579 : /* -------------------------------------------------------------------- */
1580 6 : if( poGDS->pabyBlockBuf == NULL )
1581 : {
1582 2 : poGDS->pabyBlockBuf = (GByte *) VSIMalloc3( 4, nBlockXSize, nBlockYSize );
1583 2 : if( poGDS->pabyBlockBuf == NULL )
1584 0 : return( CE_Failure );
1585 : }
1586 :
1587 : /* -------------------------------------------------------------------- */
1588 : /* Read the strip */
1589 : /* -------------------------------------------------------------------- */
1590 6 : if( poGDS->nLoadedBlock != nBlockId )
1591 : {
1592 3 : if( TIFFIsTiled( poGDS->hTIFF ) )
1593 : {
1594 0 : if( TIFFReadRGBATile(poGDS->hTIFF,
1595 : nBlockXOff * nBlockXSize,
1596 : nBlockYOff * nBlockYSize,
1597 : (uint32 *) poGDS->pabyBlockBuf) == -1 )
1598 : {
1599 : /* Once TIFFError() is properly hooked, this can go away */
1600 : CPLError( CE_Failure, CPLE_AppDefined,
1601 0 : "TIFFReadRGBATile() failed." );
1602 :
1603 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
1604 :
1605 0 : eErr = CE_Failure;
1606 : }
1607 : }
1608 : else
1609 : {
1610 3 : if( TIFFReadRGBAStrip(poGDS->hTIFF,
1611 : nBlockId * nBlockYSize,
1612 : (uint32 *) poGDS->pabyBlockBuf) == -1 )
1613 : {
1614 : /* Once TIFFError() is properly hooked, this can go away */
1615 : CPLError( CE_Failure, CPLE_AppDefined,
1616 0 : "TIFFReadRGBAStrip() failed." );
1617 :
1618 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
1619 :
1620 0 : eErr = CE_Failure;
1621 : }
1622 : }
1623 : }
1624 :
1625 6 : poGDS->nLoadedBlock = nBlockId;
1626 :
1627 : /* -------------------------------------------------------------------- */
1628 : /* Handle simple case of eight bit data, and pixel interleaving. */
1629 : /* -------------------------------------------------------------------- */
1630 : int iDestLine, nBO;
1631 : int nThisBlockYSize;
1632 :
1633 6 : if( (nBlockYOff+1) * nBlockYSize > GetYSize()
1634 : && !TIFFIsTiled( poGDS->hTIFF ) )
1635 1 : nThisBlockYSize = GetYSize() - nBlockYOff * nBlockYSize;
1636 : else
1637 5 : nThisBlockYSize = nBlockYSize;
1638 :
1639 : #ifdef CPL_LSB
1640 6 : nBO = nBand - 1;
1641 : #else
1642 : nBO = 4 - nBand;
1643 : #endif
1644 :
1645 60 : for( iDestLine = 0; iDestLine < nThisBlockYSize; iDestLine++ )
1646 : {
1647 : int nSrcOffset;
1648 :
1649 54 : nSrcOffset = (nThisBlockYSize - iDestLine - 1) * nBlockXSize * 4;
1650 :
1651 : GDALCopyWords( poGDS->pabyBlockBuf + nBO + nSrcOffset, GDT_Byte, 4,
1652 : ((GByte *) pImage)+iDestLine*nBlockXSize, GDT_Byte, 1,
1653 54 : nBlockXSize );
1654 : }
1655 :
1656 6 : return eErr;
1657 : }
1658 :
1659 : /************************************************************************/
1660 : /* GetColorInterpretation() */
1661 : /************************************************************************/
1662 :
1663 5 : GDALColorInterp GTiffRGBABand::GetColorInterpretation()
1664 :
1665 : {
1666 5 : if( nBand == 1 )
1667 2 : return GCI_RedBand;
1668 3 : else if( nBand == 2 )
1669 1 : return GCI_GreenBand;
1670 2 : else if( nBand == 3 )
1671 1 : return GCI_BlueBand;
1672 : else
1673 1 : return GCI_AlphaBand;
1674 : }
1675 :
1676 : /************************************************************************/
1677 : /* ==================================================================== */
1678 : /* GTiffOddBitsBand */
1679 : /* ==================================================================== */
1680 : /************************************************************************/
1681 :
1682 : class GTiffOddBitsBand : public GTiffRasterBand
1683 : {
1684 : friend class GTiffDataset;
1685 : public:
1686 :
1687 : GTiffOddBitsBand( GTiffDataset *, int );
1688 : virtual ~GTiffOddBitsBand();
1689 :
1690 : virtual CPLErr IReadBlock( int, int, void * );
1691 : virtual CPLErr IWriteBlock( int, int, void * );
1692 : };
1693 :
1694 :
1695 : /************************************************************************/
1696 : /* GTiffOddBitsBand() */
1697 : /************************************************************************/
1698 :
1699 330 : GTiffOddBitsBand::GTiffOddBitsBand( GTiffDataset *poGDS, int nBand )
1700 330 : : GTiffRasterBand( poGDS, nBand )
1701 :
1702 : {
1703 330 : eDataType = GDT_Byte;
1704 330 : if( poGDS->nSampleFormat == SAMPLEFORMAT_IEEEFP )
1705 2 : eDataType = GDT_Float32;
1706 425 : else if( poGDS->nBitsPerSample > 8 && poGDS->nBitsPerSample < 16 )
1707 97 : eDataType = GDT_UInt16;
1708 231 : else if( poGDS->nBitsPerSample > 16 )
1709 67 : eDataType = GDT_UInt32;
1710 330 : }
1711 :
1712 : /************************************************************************/
1713 : /* ~GTiffOddBitsBand() */
1714 : /************************************************************************/
1715 :
1716 330 : GTiffOddBitsBand::~GTiffOddBitsBand()
1717 :
1718 : {
1719 330 : }
1720 :
1721 : /************************************************************************/
1722 : /* IWriteBlock() */
1723 : /************************************************************************/
1724 :
1725 : CPLErr GTiffOddBitsBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1726 69 : void *pImage )
1727 :
1728 : {
1729 : int nBlockId;
1730 69 : CPLErr eErr = CE_None;
1731 :
1732 69 : if (!poGDS->SetDirectory())
1733 0 : return CE_Failure;
1734 :
1735 69 : CPLAssert( poGDS != NULL
1736 : && nBlockXOff >= 0
1737 : && nBlockYOff >= 0
1738 : && pImage != NULL );
1739 :
1740 69 : if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
1741 : {
1742 : CPLError(CE_Failure, CPLE_NotSupported,
1743 0 : "Writing float data with nBitsPerSample < 32 is unsupported");
1744 0 : return CE_Failure;
1745 : }
1746 :
1747 : /* -------------------------------------------------------------------- */
1748 : /* Load the block buffer. */
1749 : /* -------------------------------------------------------------------- */
1750 69 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1751 :
1752 69 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
1753 18 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
1754 :
1755 : /* Only read content from disk in the CONTIG case */
1756 : eErr = poGDS->LoadBlockBuf( nBlockId,
1757 69 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 );
1758 69 : if( eErr != CE_None )
1759 0 : return eErr;
1760 :
1761 69 : GUInt32 nMaxVal = (1 << poGDS->nBitsPerSample) - 1;
1762 :
1763 : /* -------------------------------------------------------------------- */
1764 : /* Handle case of "separate" images or single band images where */
1765 : /* no interleaving with other data is required. */
1766 : /* -------------------------------------------------------------------- */
1767 69 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
1768 : || poGDS->nBands == 1 )
1769 : {
1770 53 : int iBit, iPixel, iBitOffset = 0;
1771 : int iX, iY, nBitsPerLine;
1772 :
1773 : // bits per line rounds up to next byte boundary.
1774 53 : nBitsPerLine = nBlockXSize * poGDS->nBitsPerSample;
1775 53 : if( (nBitsPerLine & 7) != 0 )
1776 28 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
1777 :
1778 : /* Initialize to zero as we set the buffer with binary or operations */
1779 53 : if (poGDS->nBitsPerSample != 24)
1780 48 : memset(poGDS->pabyBlockBuf, 0, (nBitsPerLine / 8) * nBlockYSize);
1781 :
1782 53 : iPixel = 0;
1783 9854 : for( iY = 0; iY < nBlockYSize; iY++ )
1784 : {
1785 9801 : iBitOffset = iY * nBitsPerLine;
1786 :
1787 : /* Small optimization in 1 bit case */
1788 9801 : if (poGDS->nBitsPerSample == 1)
1789 : {
1790 7437914 : for( iX = 0; iX < nBlockXSize; iX++ )
1791 : {
1792 7428711 : if (((GByte *) pImage)[iPixel++])
1793 7107766 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1794 7428711 : iBitOffset++;
1795 : }
1796 :
1797 9203 : continue;
1798 : }
1799 :
1800 39368 : for( iX = 0; iX < nBlockXSize; iX++ )
1801 : {
1802 38770 : GUInt32 nInWord = 0;
1803 38770 : if( eDataType == GDT_Byte )
1804 400 : nInWord = ((GByte *) pImage)[iPixel++];
1805 38370 : else if( eDataType == GDT_UInt16 )
1806 35569 : nInWord = ((GUInt16 *) pImage)[iPixel++];
1807 2801 : else if( eDataType == GDT_UInt32 )
1808 2801 : nInWord = ((GUInt32 *) pImage)[iPixel++];
1809 : else
1810 0 : CPLAssert(0);
1811 :
1812 38770 : if (nInWord > nMaxVal)
1813 : {
1814 400 : nInWord = nMaxVal;
1815 400 : if( !poGDS->bClipWarn )
1816 : {
1817 1 : poGDS->bClipWarn = TRUE;
1818 : CPLError( CE_Warning, CPLE_AppDefined,
1819 1 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
1820 : }
1821 : }
1822 :
1823 38770 : if (poGDS->nBitsPerSample == 24)
1824 : {
1825 : /* -------------------------------------------------------------------- */
1826 : /* Special case for 24bit data which is pre-byteswapped since */
1827 : /* the size falls on a byte boundary ... ugg (#2361). */
1828 : /* -------------------------------------------------------------------- */
1829 : #ifdef CPL_MSB
1830 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1831 : (GByte) nInWord;
1832 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1833 : (GByte) (nInWord >> 8);
1834 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1835 : (GByte) (nInWord >> 16);
1836 : #else
1837 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1838 1400 : (GByte) (nInWord >> 16);
1839 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1840 1400 : (GByte) (nInWord >> 8);
1841 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1842 1400 : (GByte) nInWord;
1843 : #endif
1844 1400 : iBitOffset += 24;
1845 : }
1846 : else
1847 : {
1848 485812 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
1849 : {
1850 448442 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
1851 18485 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1852 448442 : iBitOffset++;
1853 : }
1854 : }
1855 : }
1856 : }
1857 :
1858 53 : poGDS->bLoadedBlockDirty = TRUE;
1859 :
1860 53 : return eErr;
1861 : }
1862 :
1863 : /* -------------------------------------------------------------------- */
1864 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
1865 : /* -------------------------------------------------------------------- */
1866 :
1867 : /* -------------------------------------------------------------------- */
1868 : /* On write of pixel interleaved data, we might as well flush */
1869 : /* out any other bands that are dirty in our cache. This is */
1870 : /* especially helpful when writing compressed blocks. */
1871 : /* -------------------------------------------------------------------- */
1872 : int iBand;
1873 :
1874 54 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
1875 : {
1876 38 : const GByte *pabyThisImage = NULL;
1877 38 : GDALRasterBlock *poBlock = NULL;
1878 38 : int iBit, iPixel, iBitOffset = 0;
1879 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
1880 :
1881 38 : if( iBand+1 == nBand )
1882 16 : pabyThisImage = (GByte *) pImage;
1883 : else
1884 : {
1885 : poBlock = ((GTiffOddBitsBand *)poGDS->GetRasterBand( iBand+1 ))
1886 22 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
1887 :
1888 22 : if( poBlock == NULL )
1889 10 : continue;
1890 :
1891 12 : if( !poBlock->GetDirty() )
1892 : {
1893 0 : poBlock->DropLock();
1894 0 : continue;
1895 : }
1896 :
1897 12 : pabyThisImage = (GByte *) poBlock->GetDataRef();
1898 : }
1899 :
1900 28 : iPixelBitSkip = poGDS->nBitsPerSample * poGDS->nBands;
1901 28 : iBandBitOffset = iBand * poGDS->nBitsPerSample;
1902 :
1903 : // bits per line rounds up to next byte boundary.
1904 28 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
1905 28 : if( (nBitsPerLine & 7) != 0 )
1906 15 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
1907 :
1908 28 : iPixel = 0;
1909 671 : for( iY = 0; iY < nBlockYSize; iY++ )
1910 : {
1911 643 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
1912 :
1913 22616 : for( iX = 0; iX < nBlockXSize; iX++ )
1914 : {
1915 21973 : GUInt32 nInWord = 0;
1916 21973 : if( eDataType == GDT_Byte )
1917 4085 : nInWord = ((GByte *) pabyThisImage)[iPixel++];
1918 17888 : else if( eDataType == GDT_UInt16 )
1919 15088 : nInWord = ((GUInt16 *) pabyThisImage)[iPixel++];
1920 2800 : else if( eDataType == GDT_UInt32 )
1921 2800 : nInWord = ((GUInt32 *) pabyThisImage)[iPixel++];
1922 : else
1923 0 : CPLAssert(0);
1924 :
1925 21973 : if (nInWord > nMaxVal)
1926 : {
1927 0 : nInWord = nMaxVal;
1928 0 : if( !poGDS->bClipWarn )
1929 : {
1930 0 : poGDS->bClipWarn = TRUE;
1931 : CPLError( CE_Warning, CPLE_AppDefined,
1932 0 : "One or more pixels clipped to fit %d bit domain.", poGDS->nBitsPerSample );
1933 : }
1934 : }
1935 :
1936 21973 : if (poGDS->nBitsPerSample == 24)
1937 : {
1938 : /* -------------------------------------------------------------------- */
1939 : /* Special case for 24bit data which is pre-byteswapped since */
1940 : /* the size falls on a byte boundary ... ugg (#2361). */
1941 : /* -------------------------------------------------------------------- */
1942 : #ifdef CPL_MSB
1943 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1944 : (GByte) nInWord;
1945 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1946 : (GByte) (nInWord >> 8);
1947 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1948 : (GByte) (nInWord >> 16);
1949 : #else
1950 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1951 1400 : (GByte) (nInWord >> 16);
1952 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1953 1400 : (GByte) (nInWord >> 8);
1954 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1955 1400 : (GByte) nInWord;
1956 : #endif
1957 1400 : iBitOffset += 24;
1958 : }
1959 : else
1960 : {
1961 248624 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
1962 : {
1963 228051 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
1964 101895 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1965 : else
1966 : {
1967 : /* We must explictly unset the bit as we may update an existing block */
1968 126156 : poGDS->pabyBlockBuf[iBitOffset>>3] &= ~(0x80 >>(iBitOffset & 7));
1969 : }
1970 :
1971 228051 : iBitOffset++;
1972 : }
1973 : }
1974 :
1975 21973 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
1976 : }
1977 : }
1978 :
1979 28 : if( poBlock != NULL )
1980 : {
1981 12 : poBlock->MarkClean();
1982 12 : poBlock->DropLock();
1983 : }
1984 : }
1985 :
1986 16 : poGDS->bLoadedBlockDirty = TRUE;
1987 :
1988 16 : return CE_None;
1989 : }
1990 :
1991 : /************************************************************************/
1992 : /* IReadBlock() */
1993 : /************************************************************************/
1994 :
1995 : CPLErr GTiffOddBitsBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1996 133 : void * pImage )
1997 :
1998 : {
1999 : int nBlockId;
2000 133 : CPLErr eErr = CE_None;
2001 :
2002 133 : if (!poGDS->SetDirectory())
2003 0 : return CE_Failure;
2004 :
2005 133 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
2006 :
2007 133 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
2008 20 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
2009 :
2010 : /* -------------------------------------------------------------------- */
2011 : /* Handle the case of a strip in a writable file that doesn't */
2012 : /* exist yet, but that we want to read. Just set to zeros and */
2013 : /* return. */
2014 : /* -------------------------------------------------------------------- */
2015 133 : if( !poGDS->IsBlockAvailable(nBlockId) )
2016 : {
2017 19 : NullBlock( pImage );
2018 19 : return CE_None;
2019 : }
2020 :
2021 : /* -------------------------------------------------------------------- */
2022 : /* Load the block buffer. */
2023 : /* -------------------------------------------------------------------- */
2024 114 : eErr = poGDS->LoadBlockBuf( nBlockId );
2025 114 : if( eErr != CE_None )
2026 0 : return eErr;
2027 :
2028 146 : if ( poGDS->nBitsPerSample == 1 && (poGDS->nBands == 1 || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) )
2029 : {
2030 : /* -------------------------------------------------------------------- */
2031 : /* Translate 1bit data to eight bit. */
2032 : /* -------------------------------------------------------------------- */
2033 32 : int iDstOffset=0, iLine;
2034 32 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2035 :
2036 2103 : for( iLine = 0; iLine < nBlockYSize; iLine++ )
2037 : {
2038 : int iSrcOffset, iPixel;
2039 :
2040 2071 : iSrcOffset = ((nBlockXSize+7) >> 3) * 8 * iLine;
2041 :
2042 235030 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2043 : {
2044 232959 : if( pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2045 52867 : ((GByte *) pImage)[iDstOffset++] = 1;
2046 : else
2047 180092 : ((GByte *) pImage)[iDstOffset++] = 0;
2048 : }
2049 : }
2050 : }
2051 : /* -------------------------------------------------------------------- */
2052 : /* Handle the case of 16- and 24-bit floating point data as per */
2053 : /* TIFF Technical Note 3. */
2054 : /* -------------------------------------------------------------------- */
2055 84 : else if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
2056 : {
2057 : int i, nBlockPixels, nWordBytes, iSkipBytes;
2058 : GByte *pabyImage;
2059 :
2060 2 : nWordBytes = poGDS->nBitsPerSample / 8;
2061 2 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
2062 : iSkipBytes = ( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) ?
2063 2 : nWordBytes : poGDS->nBands * nWordBytes;
2064 :
2065 2 : nBlockPixels = nBlockXSize * nBlockYSize;
2066 2 : if ( poGDS->nBitsPerSample == 16 )
2067 : {
2068 401 : for( i = 0; i < nBlockPixels; i++ )
2069 : {
2070 : ((GUInt32 *) pImage)[i] =
2071 400 : HalfToFloat( *((GUInt16 *)pabyImage) );
2072 400 : pabyImage += iSkipBytes;
2073 : }
2074 : }
2075 1 : else if ( poGDS->nBitsPerSample == 24 )
2076 : {
2077 401 : for( i = 0; i < nBlockPixels; i++ )
2078 : {
2079 : #ifdef CPL_MSB
2080 : ((GUInt32 *) pImage)[i] =
2081 : TripleToFloat( ((GUInt32)*(pabyImage + 0) << 16)
2082 : | ((GUInt32)*(pabyImage + 1) << 8)
2083 : | (GUInt32)*(pabyImage + 2) );
2084 : #else
2085 : ((GUInt32 *) pImage)[i] =
2086 : TripleToFloat( ((GUInt32)*(pabyImage + 2) << 16)
2087 : | ((GUInt32)*(pabyImage + 1) << 8)
2088 400 : | (GUInt32)*pabyImage );
2089 : #endif
2090 400 : pabyImage += iSkipBytes;
2091 : }
2092 : }
2093 : }
2094 :
2095 : /* -------------------------------------------------------------------- */
2096 : /* Special case for moving 12bit data somewhat more efficiently. */
2097 : /* -------------------------------------------------------------------- */
2098 80 : else if( poGDS->nBitsPerSample == 12 )
2099 : {
2100 20 : int iPixel, iBitOffset = 0;
2101 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2102 :
2103 20 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2104 : {
2105 17 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2106 17 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2107 : }
2108 : else
2109 : {
2110 3 : iPixelBitSkip = poGDS->nBitsPerSample;
2111 3 : iBandBitOffset = 0;
2112 : }
2113 :
2114 : // bits per line rounds up to next byte boundary.
2115 20 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2116 20 : if( (nBitsPerLine & 7) != 0 )
2117 0 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2118 :
2119 20 : iPixel = 0;
2120 904 : for( iY = 0; iY < nBlockYSize; iY++ )
2121 : {
2122 884 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2123 :
2124 65524 : for( iX = 0; iX < nBlockXSize; iX++ )
2125 : {
2126 64640 : int iByte = iBitOffset>>3;
2127 :
2128 64640 : if( (iBitOffset & 0x7) == 0 )
2129 : {
2130 : /* starting on byte boundary */
2131 :
2132 : ((GUInt16 *) pImage)[iPixel++] =
2133 : (poGDS->pabyBlockBuf[iByte] << 4)
2134 32420 : | (poGDS->pabyBlockBuf[iByte+1] >> 4);
2135 : }
2136 : else
2137 : {
2138 : /* starting off byte boundary */
2139 :
2140 : ((GUInt16 *) pImage)[iPixel++] =
2141 : ((poGDS->pabyBlockBuf[iByte] & 0xf) << 8)
2142 32220 : | (poGDS->pabyBlockBuf[iByte+1]);
2143 : }
2144 64640 : iBitOffset += iPixelBitSkip;
2145 : }
2146 : }
2147 : }
2148 :
2149 : /* -------------------------------------------------------------------- */
2150 : /* Special case for 24bit data which is pre-byteswapped since */
2151 : /* the size falls on a byte boundary ... ugg (#2361). */
2152 : /* -------------------------------------------------------------------- */
2153 60 : else if( poGDS->nBitsPerSample == 24 )
2154 : {
2155 : int iPixel;
2156 : int iPixelByteSkip, iBandByteOffset, iX, iY, nBytesPerLine;
2157 :
2158 11 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2159 : {
2160 8 : iPixelByteSkip = (poGDS->nBands * poGDS->nBitsPerSample) / 8;
2161 8 : iBandByteOffset = ((nBand-1) * poGDS->nBitsPerSample) / 8;
2162 : }
2163 : else
2164 : {
2165 3 : iPixelByteSkip = poGDS->nBitsPerSample / 8;
2166 3 : iBandByteOffset = 0;
2167 : }
2168 :
2169 11 : nBytesPerLine = nBlockXSize * iPixelByteSkip;
2170 :
2171 11 : iPixel = 0;
2172 191 : for( iY = 0; iY < nBlockYSize; iY++ )
2173 : {
2174 : GByte *pabyImage =
2175 180 : poGDS->pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
2176 :
2177 3380 : for( iX = 0; iX < nBlockXSize; iX++ )
2178 : {
2179 : #ifdef CPL_MSB
2180 : ((GUInt32 *) pImage)[iPixel++] =
2181 : ((GUInt32)*(pabyImage + 2) << 16)
2182 : | ((GUInt32)*(pabyImage + 1) << 8)
2183 : | (GUInt32)*(pabyImage + 0);
2184 : #else
2185 : ((GUInt32 *) pImage)[iPixel++] =
2186 : ((GUInt32)*(pabyImage + 0) << 16)
2187 : | ((GUInt32)*(pabyImage + 1) << 8)
2188 3200 : | (GUInt32)*(pabyImage + 2);
2189 : #endif
2190 3200 : pabyImage += iPixelByteSkip;
2191 : }
2192 : }
2193 : }
2194 :
2195 : /* -------------------------------------------------------------------- */
2196 : /* Handle 1-32 bit integer data. */
2197 : /* -------------------------------------------------------------------- */
2198 : else
2199 : {
2200 49 : int iBit, iPixel, iBitOffset = 0;
2201 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2202 :
2203 49 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2204 : {
2205 43 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2206 43 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2207 : }
2208 : else
2209 : {
2210 6 : iPixelBitSkip = poGDS->nBitsPerSample;
2211 6 : iBandBitOffset = 0;
2212 : }
2213 :
2214 : // bits per line rounds up to next byte boundary.
2215 49 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2216 49 : if( (nBitsPerLine & 7) != 0 )
2217 48 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2218 :
2219 49 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2220 49 : iPixel = 0;
2221 :
2222 2285 : for( iY = 0; iY < nBlockYSize; iY++ )
2223 : {
2224 2236 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2225 :
2226 180540 : for( iX = 0; iX < nBlockXSize; iX++ )
2227 : {
2228 178304 : int nOutWord = 0;
2229 :
2230 452342 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2231 : {
2232 274038 : if( pabyBlockBuf[iBitOffset>>3]
2233 : & (0x80 >>(iBitOffset & 7)) )
2234 137696 : nOutWord |= (1 << (poGDS->nBitsPerSample - 1 - iBit));
2235 274038 : iBitOffset++;
2236 : }
2237 :
2238 178304 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2239 :
2240 178304 : if( eDataType == GDT_Byte )
2241 172302 : ((GByte *) pImage)[iPixel++] = (GByte) nOutWord;
2242 6002 : else if( eDataType == GDT_UInt16 )
2243 3201 : ((GUInt16 *) pImage)[iPixel++] = (GUInt16) nOutWord;
2244 2801 : else if( eDataType == GDT_UInt32 )
2245 2801 : ((GUInt32 *) pImage)[iPixel++] = nOutWord;
2246 : else
2247 0 : CPLAssert(0);
2248 : }
2249 : }
2250 : }
2251 :
2252 114 : return CE_None;
2253 : }
2254 :
2255 :
2256 : /************************************************************************/
2257 : /* ==================================================================== */
2258 : /* GTiffBitmapBand */
2259 : /* ==================================================================== */
2260 : /************************************************************************/
2261 :
2262 : class GTiffBitmapBand : public GTiffOddBitsBand
2263 : {
2264 : friend class GTiffDataset;
2265 :
2266 : GDALColorTable *poColorTable;
2267 :
2268 : public:
2269 :
2270 : GTiffBitmapBand( GTiffDataset *, int );
2271 : virtual ~GTiffBitmapBand();
2272 :
2273 : virtual GDALColorInterp GetColorInterpretation();
2274 : virtual GDALColorTable *GetColorTable();
2275 : };
2276 :
2277 :
2278 : /************************************************************************/
2279 : /* GTiffBitmapBand() */
2280 : /************************************************************************/
2281 :
2282 76 : GTiffBitmapBand::GTiffBitmapBand( GTiffDataset *poDS, int nBand )
2283 76 : : GTiffOddBitsBand( poDS, nBand )
2284 :
2285 : {
2286 76 : eDataType = GDT_Byte;
2287 :
2288 76 : if( poDS->poColorTable != NULL )
2289 17 : poColorTable = poDS->poColorTable->Clone();
2290 : else
2291 : {
2292 : GDALColorEntry oWhite, oBlack;
2293 :
2294 59 : oWhite.c1 = 255;
2295 59 : oWhite.c2 = 255;
2296 59 : oWhite.c3 = 255;
2297 59 : oWhite.c4 = 255;
2298 :
2299 59 : oBlack.c1 = 0;
2300 59 : oBlack.c2 = 0;
2301 59 : oBlack.c3 = 0;
2302 59 : oBlack.c4 = 255;
2303 :
2304 59 : poColorTable = new GDALColorTable();
2305 :
2306 59 : if( poDS->nPhotometric == PHOTOMETRIC_MINISWHITE )
2307 : {
2308 0 : poColorTable->SetColorEntry( 0, &oWhite );
2309 0 : poColorTable->SetColorEntry( 1, &oBlack );
2310 : }
2311 : else
2312 : {
2313 59 : poColorTable->SetColorEntry( 0, &oBlack );
2314 59 : poColorTable->SetColorEntry( 1, &oWhite );
2315 : }
2316 : }
2317 76 : }
2318 :
2319 : /************************************************************************/
2320 : /* ~GTiffBitmapBand() */
2321 : /************************************************************************/
2322 :
2323 76 : GTiffBitmapBand::~GTiffBitmapBand()
2324 :
2325 : {
2326 76 : delete poColorTable;
2327 76 : }
2328 :
2329 : /************************************************************************/
2330 : /* GetColorInterpretation() */
2331 : /************************************************************************/
2332 :
2333 8 : GDALColorInterp GTiffBitmapBand::GetColorInterpretation()
2334 :
2335 : {
2336 8 : return GCI_PaletteIndex;
2337 : }
2338 :
2339 : /************************************************************************/
2340 : /* GetColorTable() */
2341 : /************************************************************************/
2342 :
2343 10 : GDALColorTable *GTiffBitmapBand::GetColorTable()
2344 :
2345 : {
2346 10 : return poColorTable;
2347 : }
2348 :
2349 : /************************************************************************/
2350 : /* ==================================================================== */
2351 : /* GTiffSplitBitmapBand */
2352 : /* ==================================================================== */
2353 : /************************************************************************/
2354 :
2355 : class GTiffSplitBitmapBand : public GTiffBitmapBand
2356 : {
2357 : friend class GTiffDataset;
2358 :
2359 : public:
2360 :
2361 : GTiffSplitBitmapBand( GTiffDataset *, int );
2362 : virtual ~GTiffSplitBitmapBand();
2363 :
2364 : virtual CPLErr IReadBlock( int, int, void * );
2365 : virtual CPLErr IWriteBlock( int, int, void * );
2366 : };
2367 :
2368 :
2369 : /************************************************************************/
2370 : /* GTiffSplitBitmapBand() */
2371 : /************************************************************************/
2372 :
2373 4 : GTiffSplitBitmapBand::GTiffSplitBitmapBand( GTiffDataset *poDS, int nBand )
2374 4 : : GTiffBitmapBand( poDS, nBand )
2375 :
2376 : {
2377 4 : nBlockXSize = poDS->GetRasterXSize();
2378 4 : nBlockYSize = 1;
2379 4 : }
2380 :
2381 : /************************************************************************/
2382 : /* ~GTiffSplitBitmapBand() */
2383 : /************************************************************************/
2384 :
2385 4 : GTiffSplitBitmapBand::~GTiffSplitBitmapBand()
2386 :
2387 : {
2388 4 : }
2389 :
2390 :
2391 : /************************************************************************/
2392 : /* IReadBlock() */
2393 : /************************************************************************/
2394 :
2395 : CPLErr GTiffSplitBitmapBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2396 21600 : void * pImage )
2397 :
2398 : {
2399 : (void) nBlockXOff;
2400 :
2401 21600 : if (!poGDS->SetDirectory())
2402 0 : return CE_Failure;
2403 :
2404 21600 : if (poGDS->pabyBlockBuf == NULL)
2405 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
2406 :
2407 : /* -------------------------------------------------------------------- */
2408 : /* Read through to target scanline. */
2409 : /* -------------------------------------------------------------------- */
2410 21600 : if( poGDS->nLastLineRead >= nBlockYOff )
2411 0 : poGDS->nLastLineRead = -1;
2412 :
2413 64800 : while( poGDS->nLastLineRead < nBlockYOff )
2414 : {
2415 21600 : if( TIFFReadScanline( poGDS->hTIFF, poGDS->pabyBlockBuf, ++poGDS->nLastLineRead, 0 ) == -1 )
2416 : {
2417 : CPLError( CE_Failure, CPLE_AppDefined,
2418 0 : "TIFFReadScanline() failed." );
2419 0 : return CE_Failure;
2420 : }
2421 : }
2422 :
2423 : /* -------------------------------------------------------------------- */
2424 : /* Translate 1bit data to eight bit. */
2425 : /* -------------------------------------------------------------------- */
2426 21600 : int iPixel, iSrcOffset=0, iDstOffset=0;
2427 :
2428 21621600 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2429 : {
2430 21600000 : if( poGDS->pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2431 21243630 : ((GByte *) pImage)[iDstOffset++] = 1;
2432 : else
2433 356370 : ((GByte *) pImage)[iDstOffset++] = 0;
2434 : }
2435 :
2436 21600 : return CE_None;
2437 : }
2438 :
2439 : /************************************************************************/
2440 : /* IWriteBlock() */
2441 : /************************************************************************/
2442 :
2443 : CPLErr GTiffSplitBitmapBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2444 0 : void * pImage )
2445 :
2446 : {
2447 : (void) nBlockXOff;
2448 : (void) nBlockYOff;
2449 : (void) pImage;
2450 :
2451 : CPLError( CE_Failure, CPLE_AppDefined,
2452 0 : "Split bitmap bands are read-only." );
2453 0 : return CE_Failure;
2454 : }
2455 :
2456 : /************************************************************************/
2457 : /* ==================================================================== */
2458 : /* GTiffDataset */
2459 : /* ==================================================================== */
2460 : /************************************************************************/
2461 :
2462 :
2463 : /************************************************************************/
2464 : /* GTiffDataset() */
2465 : /************************************************************************/
2466 :
2467 4635 : GTiffDataset::GTiffDataset()
2468 :
2469 : {
2470 4635 : nLoadedBlock = -1;
2471 4635 : bLoadedBlockDirty = FALSE;
2472 4635 : pabyBlockBuf = NULL;
2473 4635 : hTIFF = NULL;
2474 4635 : bNeedsRewrite = FALSE;
2475 4635 : bMetadataChanged = FALSE;
2476 4635 : bGeoTIFFInfoChanged = FALSE;
2477 4635 : bCrystalized = TRUE;
2478 4635 : poColorTable = NULL;
2479 4635 : bNoDataSet = FALSE;
2480 4635 : dfNoDataValue = -9999.0;
2481 4635 : pszProjection = CPLStrdup("");
2482 4635 : bLookedForProjection = FALSE;
2483 4635 : bBase = TRUE;
2484 4635 : bCloseTIFFHandle = FALSE;
2485 4635 : bTreatAsRGBA = FALSE;
2486 4635 : nOverviewCount = 0;
2487 4635 : papoOverviewDS = NULL;
2488 4635 : nDirOffset = 0;
2489 4635 : poActiveDS = NULL;
2490 4635 : ppoActiveDSRef = NULL;
2491 :
2492 4635 : bGeoTransformValid = FALSE;
2493 4635 : adfGeoTransform[0] = 0.0;
2494 4635 : adfGeoTransform[1] = 1.0;
2495 4635 : adfGeoTransform[2] = 0.0;
2496 4635 : adfGeoTransform[3] = 0.0;
2497 4635 : adfGeoTransform[4] = 0.0;
2498 4635 : adfGeoTransform[5] = 1.0;
2499 :
2500 4635 : nGCPCount = 0;
2501 4635 : pasGCPList = NULL;
2502 :
2503 4635 : osProfile = "GDALGeoTIFF";
2504 :
2505 4635 : papszCreationOptions = NULL;
2506 :
2507 4635 : nTempWriteBufferSize = 0;
2508 4635 : pabyTempWriteBuffer = NULL;
2509 :
2510 4635 : poMaskDS = NULL;
2511 4635 : poBaseDS = NULL;
2512 :
2513 4635 : bFillEmptyTiles = FALSE;
2514 4635 : bLoadingOtherBands = FALSE;
2515 4635 : nLastLineRead = -1;
2516 4635 : nLastBandRead = -1;
2517 4635 : bTreatAsSplit = FALSE;
2518 4635 : bTreatAsSplitBitmap = FALSE;
2519 4635 : bClipWarn = FALSE;
2520 4635 : }
2521 :
2522 : /************************************************************************/
2523 : /* ~GTiffDataset() */
2524 : /************************************************************************/
2525 :
2526 4635 : GTiffDataset::~GTiffDataset()
2527 :
2528 : {
2529 4635 : Crystalize();
2530 :
2531 : /* -------------------------------------------------------------------- */
2532 : /* Ensure any blocks write cached by GDAL gets pushed through libtiff.*/
2533 : /* -------------------------------------------------------------------- */
2534 4635 : GDALPamDataset::FlushCache();
2535 :
2536 : /* -------------------------------------------------------------------- */
2537 : /* Fill in missing blocks with empty data. */
2538 : /* -------------------------------------------------------------------- */
2539 4635 : if( bFillEmptyTiles )
2540 : {
2541 764 : FillEmptyTiles();
2542 764 : bFillEmptyTiles = FALSE;
2543 : }
2544 :
2545 : /* -------------------------------------------------------------------- */
2546 : /* Force a complete flush, including either rewriting(moving) */
2547 : /* of writing in place the current directory. */
2548 : /* -------------------------------------------------------------------- */
2549 4635 : FlushCache();
2550 :
2551 : /* -------------------------------------------------------------------- */
2552 : /* If there is still changed metadata, then presumably we want */
2553 : /* to push it into PAM. */
2554 : /* -------------------------------------------------------------------- */
2555 4635 : if( bMetadataChanged )
2556 : {
2557 26 : PushMetadataToPam();
2558 26 : bMetadataChanged = FALSE;
2559 26 : GDALPamDataset::FlushCache();
2560 : }
2561 :
2562 : /* -------------------------------------------------------------------- */
2563 : /* Cleanup overviews. */
2564 : /* -------------------------------------------------------------------- */
2565 4635 : if( bBase )
2566 : {
2567 4518 : for( int i = 0; i < nOverviewCount; i++ )
2568 : {
2569 251 : delete papoOverviewDS[i];
2570 : }
2571 : }
2572 :
2573 : /* If we are a mask dataset, we can have overviews, but we don't */
2574 : /* own them. We can only free the array, not the overviews themselves */
2575 4635 : CPLFree( papoOverviewDS );
2576 :
2577 : /* poMaskDS is owned by the main image and the overviews */
2578 : /* so because of the latter case, we can delete it even if */
2579 : /* we are not the base image */
2580 4635 : if (poMaskDS)
2581 57 : delete poMaskDS;
2582 :
2583 4635 : if( poColorTable != NULL )
2584 105 : delete poColorTable;
2585 :
2586 4635 : if( bBase || bCloseTIFFHandle )
2587 : {
2588 4271 : XTIFFClose( hTIFF );
2589 : }
2590 :
2591 4635 : if( nGCPCount > 0 )
2592 : {
2593 44 : GDALDeinitGCPs( nGCPCount, pasGCPList );
2594 44 : CPLFree( pasGCPList );
2595 : }
2596 :
2597 4635 : CPLFree( pszProjection );
2598 :
2599 4635 : CSLDestroy( papszCreationOptions );
2600 :
2601 4635 : CPLFree(pabyTempWriteBuffer);
2602 :
2603 4635 : if( *ppoActiveDSRef == this )
2604 4395 : *ppoActiveDSRef = NULL;
2605 4635 : }
2606 :
2607 : /************************************************************************/
2608 : /* FillEmptyTiles() */
2609 : /************************************************************************/
2610 :
2611 764 : void GTiffDataset::FillEmptyTiles()
2612 :
2613 : {
2614 764 : toff_t *panByteCounts = NULL;
2615 : int nBlockCount, iBlock;
2616 :
2617 764 : if (!SetDirectory())
2618 0 : return;
2619 :
2620 : /* -------------------------------------------------------------------- */
2621 : /* How many blocks are there in this file? */
2622 : /* -------------------------------------------------------------------- */
2623 764 : if( nPlanarConfig == PLANARCONFIG_SEPARATE )
2624 5 : nBlockCount = nBlocksPerBand * nBands;
2625 : else
2626 759 : nBlockCount = nBlocksPerBand;
2627 :
2628 : /* -------------------------------------------------------------------- */
2629 : /* Fetch block maps. */
2630 : /* -------------------------------------------------------------------- */
2631 764 : if( TIFFIsTiled( hTIFF ) )
2632 15 : TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts );
2633 : else
2634 749 : TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
2635 :
2636 764 : if (panByteCounts == NULL)
2637 : {
2638 : /* Got here with libtiff 3.9.3 and tiff_write_8 test */
2639 0 : CPLError(CE_Failure, CPLE_AppDefined, "FillEmptyTiles() failed because panByteCounts == NULL");
2640 0 : return;
2641 : }
2642 :
2643 : /* -------------------------------------------------------------------- */
2644 : /* Prepare a blank data buffer to write for uninitialized blocks. */
2645 : /* -------------------------------------------------------------------- */
2646 : int nBlockBytes;
2647 :
2648 764 : if( TIFFIsTiled( hTIFF ) )
2649 15 : nBlockBytes = TIFFTileSize(hTIFF);
2650 : else
2651 749 : nBlockBytes = TIFFStripSize(hTIFF);
2652 :
2653 764 : GByte *pabyData = (GByte *) VSICalloc(nBlockBytes,1);
2654 764 : if (pabyData == NULL)
2655 : {
2656 : CPLError(CE_Failure, CPLE_OutOfMemory,
2657 0 : "Cannot allocate %d bytes", nBlockBytes);
2658 0 : return;
2659 : }
2660 :
2661 : /* -------------------------------------------------------------------- */
2662 : /* Check all blocks, writing out data for uninitialized blocks. */
2663 : /* -------------------------------------------------------------------- */
2664 81051 : for( iBlock = 0; iBlock < nBlockCount; iBlock++ )
2665 : {
2666 80287 : if( panByteCounts[iBlock] == 0 )
2667 70098 : WriteEncodedTileOrStrip( iBlock, pabyData, FALSE );
2668 : }
2669 :
2670 764 : CPLFree( pabyData );
2671 : }
2672 :
2673 : /************************************************************************/
2674 : /* WriteEncodedTile() */
2675 : /************************************************************************/
2676 :
2677 : int GTiffDataset::WriteEncodedTile(uint32 tile, void* data,
2678 8620 : int bPreserveDataBuffer)
2679 : {
2680 : /* TIFFWriteEncodedTile can alter the passed buffer if byte-swapping is necessary */
2681 : /* so we use a temporary buffer before calling it */
2682 8620 : int cc = TIFFTileSize( hTIFF );
2683 8620 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
2684 : {
2685 40 : if (cc != nTempWriteBufferSize)
2686 : {
2687 21 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
2688 21 : nTempWriteBufferSize = cc;
2689 : }
2690 40 : memcpy(pabyTempWriteBuffer, data, cc);
2691 40 : return TIFFWriteEncodedTile(hTIFF, tile, pabyTempWriteBuffer, cc);
2692 : }
2693 : else
2694 8580 : return TIFFWriteEncodedTile(hTIFF, tile, data, cc);
2695 : }
2696 :
2697 : /************************************************************************/
2698 : /* WriteEncodedStrip() */
2699 : /************************************************************************/
2700 :
2701 : int GTiffDataset::WriteEncodedStrip(uint32 strip, void* data,
2702 74764 : int bPreserveDataBuffer)
2703 : {
2704 74764 : int cc = TIFFStripSize( hTIFF );
2705 :
2706 : /* -------------------------------------------------------------------- */
2707 : /* If this is the last strip in the image, and is partial, then */
2708 : /* we need to trim the number of scanlines written to the */
2709 : /* amount of valid data we have. (#2748) */
2710 : /* -------------------------------------------------------------------- */
2711 74764 : int nStripWithinBand = strip % nBlocksPerBand;
2712 :
2713 74764 : if( (int) ((nStripWithinBand+1) * nRowsPerStrip) > GetRasterYSize() )
2714 : {
2715 : cc = (cc / nRowsPerStrip)
2716 85 : * (GetRasterYSize() - nStripWithinBand * nRowsPerStrip);
2717 : CPLDebug( "GTiff", "Adjusted bytes to write from %d to %d.",
2718 85 : (int) TIFFStripSize(hTIFF), cc );
2719 : }
2720 :
2721 : /* -------------------------------------------------------------------- */
2722 : /* TIFFWriteEncodedStrip can alter the passed buffer if */
2723 : /* byte-swapping is necessary so we use a temporary buffer */
2724 : /* before calling it. */
2725 : /* -------------------------------------------------------------------- */
2726 74764 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
2727 : {
2728 28 : if (cc != nTempWriteBufferSize)
2729 : {
2730 22 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
2731 22 : nTempWriteBufferSize = cc;
2732 : }
2733 28 : memcpy(pabyTempWriteBuffer, data, cc);
2734 28 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyTempWriteBuffer, cc);
2735 : }
2736 : else
2737 74736 : return TIFFWriteEncodedStrip(hTIFF, strip, data, cc);
2738 : }
2739 :
2740 : /************************************************************************/
2741 : /* WriteEncodedTileOrStrip() */
2742 : /************************************************************************/
2743 :
2744 : CPLErr GTiffDataset::WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data,
2745 83384 : int bPreserveDataBuffer)
2746 : {
2747 83384 : CPLErr eErr = CE_None;
2748 :
2749 83384 : if( TIFFIsTiled( hTIFF ) )
2750 : {
2751 8620 : if( WriteEncodedTile(tile_or_strip, data, bPreserveDataBuffer) == -1 )
2752 : {
2753 0 : eErr = CE_Failure;
2754 : }
2755 : }
2756 : else
2757 : {
2758 74764 : if( WriteEncodedStrip(tile_or_strip, data, bPreserveDataBuffer) == -1 )
2759 : {
2760 0 : eErr = CE_Failure;
2761 : }
2762 : }
2763 :
2764 83384 : return eErr;
2765 : }
2766 :
2767 : /************************************************************************/
2768 : /* FlushBlockBuf() */
2769 : /************************************************************************/
2770 :
2771 195077 : CPLErr GTiffDataset::FlushBlockBuf()
2772 :
2773 : {
2774 195077 : CPLErr eErr = CE_None;
2775 :
2776 195077 : if( nLoadedBlock < 0 || !bLoadedBlockDirty )
2777 194266 : return CE_None;
2778 :
2779 811 : bLoadedBlockDirty = FALSE;
2780 :
2781 811 : if (!SetDirectory())
2782 0 : return CE_Failure;
2783 :
2784 811 : eErr = WriteEncodedTileOrStrip(nLoadedBlock, pabyBlockBuf, TRUE);
2785 811 : if (eErr != CE_None)
2786 : {
2787 : CPLError( CE_Failure, CPLE_AppDefined,
2788 0 : "WriteEncodedTile/Strip() failed." );
2789 : }
2790 :
2791 811 : return eErr;
2792 : }
2793 :
2794 : /************************************************************************/
2795 : /* LoadBlockBuf() */
2796 : /* */
2797 : /* Load working block buffer with request block (tile/strip). */
2798 : /************************************************************************/
2799 :
2800 69229 : CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
2801 :
2802 : {
2803 : int nBlockBufSize;
2804 69229 : CPLErr eErr = CE_None;
2805 :
2806 69229 : if( nLoadedBlock == nBlockId )
2807 67494 : return CE_None;
2808 :
2809 : /* -------------------------------------------------------------------- */
2810 : /* If we have a dirty loaded block, flush it out first. */
2811 : /* -------------------------------------------------------------------- */
2812 1735 : if( nLoadedBlock != -1 && bLoadedBlockDirty )
2813 : {
2814 0 : eErr = FlushBlockBuf();
2815 0 : if( eErr != CE_None )
2816 0 : return eErr;
2817 : }
2818 :
2819 : /* -------------------------------------------------------------------- */
2820 : /* Get block size. */
2821 : /* -------------------------------------------------------------------- */
2822 1735 : if( TIFFIsTiled(hTIFF) )
2823 152 : nBlockBufSize = TIFFTileSize( hTIFF );
2824 : else
2825 1583 : nBlockBufSize = TIFFStripSize( hTIFF );
2826 :
2827 1735 : if ( !nBlockBufSize )
2828 : {
2829 : CPLError( CE_Failure, CPLE_AppDefined,
2830 0 : "Bogus block size; unable to allocate a buffer.");
2831 0 : return CE_Failure;
2832 : }
2833 :
2834 : /* -------------------------------------------------------------------- */
2835 : /* Allocate a temporary buffer for this strip. */
2836 : /* -------------------------------------------------------------------- */
2837 1735 : if( pabyBlockBuf == NULL )
2838 : {
2839 385 : pabyBlockBuf = (GByte *) VSICalloc( 1, nBlockBufSize );
2840 385 : if( pabyBlockBuf == NULL )
2841 : {
2842 : CPLError( CE_Failure, CPLE_OutOfMemory,
2843 : "Unable to allocate %d bytes for a temporary strip "
2844 : "buffer in GTIFF driver.",
2845 0 : nBlockBufSize );
2846 :
2847 0 : return( CE_Failure );
2848 : }
2849 : }
2850 :
2851 : /* -------------------------------------------------------------------- */
2852 : /* When called from ::IWriteBlock in separate cases (or in single band */
2853 : /* geotiffs), the ::IWriteBlock will override the content of the buffer*/
2854 : /* with pImage, so we don't need to read data from disk */
2855 : /* -------------------------------------------------------------------- */
2856 1735 : if( !bReadFromDisk )
2857 : {
2858 47 : nLoadedBlock = nBlockId;
2859 47 : return CE_None;
2860 : }
2861 :
2862 : /* -------------------------------------------------------------------- */
2863 : /* The bottom most partial tiles and strips are sometimes only */
2864 : /* partially encoded. This code reduces the requested data so */
2865 : /* an error won't be reported in this case. (#1179) */
2866 : /* -------------------------------------------------------------------- */
2867 1688 : int nBlockReqSize = nBlockBufSize;
2868 1688 : int nBlocksPerRow = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
2869 1688 : int nBlockYOff = (nBlockId % nBlocksPerBand) / nBlocksPerRow;
2870 :
2871 1688 : if( (int)((nBlockYOff+1) * nBlockYSize) > nRasterYSize )
2872 : {
2873 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
2874 151 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
2875 151 : memset( pabyBlockBuf, 0, nBlockBufSize );
2876 : }
2877 :
2878 : /* -------------------------------------------------------------------- */
2879 : /* If we don't have this block already loaded, and we know it */
2880 : /* doesn't yet exist on disk, just zero the memory buffer and */
2881 : /* pretend we loaded it. */
2882 : /* -------------------------------------------------------------------- */
2883 1688 : if( !IsBlockAvailable( nBlockId ) )
2884 : {
2885 698 : memset( pabyBlockBuf, 0, nBlockBufSize );
2886 698 : nLoadedBlock = nBlockId;
2887 698 : return CE_None;
2888 : }
2889 :
2890 : /* -------------------------------------------------------------------- */
2891 : /* Load the block, if it isn't our current block. */
2892 : /* -------------------------------------------------------------------- */
2893 990 : if( TIFFIsTiled( hTIFF ) )
2894 : {
2895 84 : if( TIFFReadEncodedTile(hTIFF, nBlockId, pabyBlockBuf,
2896 : nBlockReqSize) == -1 )
2897 : {
2898 : /* Once TIFFError() is properly hooked, this can go away */
2899 : CPLError( CE_Failure, CPLE_AppDefined,
2900 0 : "TIFFReadEncodedTile() failed." );
2901 :
2902 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
2903 :
2904 0 : eErr = CE_Failure;
2905 : }
2906 : }
2907 : else
2908 : {
2909 906 : if( TIFFReadEncodedStrip(hTIFF, nBlockId, pabyBlockBuf,
2910 : nBlockReqSize) == -1 )
2911 : {
2912 : /* Once TIFFError() is properly hooked, this can go away */
2913 : CPLError( CE_Failure, CPLE_AppDefined,
2914 0 : "TIFFReadEncodedStrip() failed." );
2915 :
2916 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
2917 :
2918 0 : eErr = CE_Failure;
2919 : }
2920 : }
2921 :
2922 990 : nLoadedBlock = nBlockId;
2923 990 : bLoadedBlockDirty = FALSE;
2924 :
2925 990 : return eErr;
2926 : }
2927 :
2928 :
2929 : /************************************************************************/
2930 : /* Crystalize() */
2931 : /* */
2932 : /* Make sure that the directory information is written out for */
2933 : /* a new file, require before writing any imagery data. */
2934 : /************************************************************************/
2935 :
2936 199621 : void GTiffDataset::Crystalize()
2937 :
2938 : {
2939 199621 : if( !bCrystalized )
2940 : {
2941 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
2942 779 : papszCreationOptions );
2943 779 : WriteGeoTIFFInfo();
2944 :
2945 779 : bMetadataChanged = FALSE;
2946 779 : bGeoTIFFInfoChanged = FALSE;
2947 779 : bNeedsRewrite = FALSE;
2948 :
2949 779 : bCrystalized = TRUE;
2950 :
2951 779 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffDataset::Crystalize");
2952 :
2953 : // Keep zip and tiff quality, and jpegcolormode which get reset when we call
2954 : // TIFFWriteDirectory
2955 779 : int jquality = -1, zquality = -1, nColorMode = -1;
2956 779 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
2957 779 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
2958 779 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
2959 :
2960 779 : TIFFWriteDirectory( hTIFF );
2961 779 : TIFFSetDirectory( hTIFF, 0 );
2962 :
2963 :
2964 : // Now, reset zip and tiff quality and jpegcolormode.
2965 779 : if(jquality > 0)
2966 2 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
2967 779 : if(zquality > 0)
2968 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
2969 779 : if (nColorMode >= 0)
2970 2 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, nColorMode);
2971 :
2972 779 : nDirOffset = TIFFCurrentDirOffset( hTIFF );
2973 : }
2974 199621 : }
2975 :
2976 :
2977 : /************************************************************************/
2978 : /* IsBlockAvailable() */
2979 : /* */
2980 : /* Return TRUE if the indicated strip/tile is available. We */
2981 : /* establish this by testing if the stripbytecount is zero. If */
2982 : /* zero then the block has never been committed to disk. */
2983 : /************************************************************************/
2984 :
2985 84081 : int GTiffDataset::IsBlockAvailable( int nBlockId )
2986 :
2987 : {
2988 84081 : toff_t *panByteCounts = NULL;
2989 :
2990 84081 : if( ( TIFFIsTiled( hTIFF )
2991 : && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts ) )
2992 : || ( !TIFFIsTiled( hTIFF )
2993 : && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts ) ) )
2994 : {
2995 84081 : if( panByteCounts == NULL )
2996 0 : return FALSE;
2997 : else
2998 84081 : return panByteCounts[nBlockId] != 0;
2999 : }
3000 : else
3001 0 : return FALSE;
3002 : }
3003 :
3004 : /************************************************************************/
3005 : /* FlushCache() */
3006 : /* */
3007 : /* We override this so we can also flush out local tiff strip */
3008 : /* cache if need be. */
3009 : /************************************************************************/
3010 :
3011 4892 : void GTiffDataset::FlushCache()
3012 :
3013 : {
3014 4892 : GDALPamDataset::FlushCache();
3015 :
3016 4892 : if( bLoadedBlockDirty && nLoadedBlock != -1 )
3017 91 : FlushBlockBuf();
3018 :
3019 4892 : CPLFree( pabyBlockBuf );
3020 4892 : pabyBlockBuf = NULL;
3021 4892 : nLoadedBlock = -1;
3022 4892 : bLoadedBlockDirty = FALSE;
3023 :
3024 4892 : if (!SetDirectory())
3025 0 : return;
3026 4892 : FlushDirectory();
3027 : }
3028 :
3029 : /************************************************************************/
3030 : /* FlushDirectory() */
3031 : /************************************************************************/
3032 :
3033 9132 : void GTiffDataset::FlushDirectory()
3034 :
3035 : {
3036 9132 : if( GetAccess() == GA_Update )
3037 : {
3038 2591 : if( bMetadataChanged )
3039 : {
3040 14 : if (!SetDirectory())
3041 0 : return;
3042 : bNeedsRewrite =
3043 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
3044 14 : papszCreationOptions );
3045 14 : bMetadataChanged = FALSE;
3046 : }
3047 :
3048 2591 : if( bGeoTIFFInfoChanged )
3049 : {
3050 18 : if (!SetDirectory())
3051 0 : return;
3052 18 : WriteGeoTIFFInfo();
3053 : }
3054 :
3055 2591 : if( bNeedsRewrite )
3056 : {
3057 : #if defined(TIFFLIB_VERSION)
3058 : #if defined(HAVE_TIFFGETSIZEPROC)
3059 73 : if (!SetDirectory())
3060 0 : return;
3061 :
3062 73 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3063 :
3064 73 : nDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3065 73 : if( (nDirOffset % 2) == 1 )
3066 14 : nDirOffset++;
3067 :
3068 73 : TIFFRewriteDirectory( hTIFF );
3069 :
3070 73 : TIFFSetSubDirectory( hTIFF, nDirOffset );
3071 : #elif TIFFLIB_VERSION > 20010925 && TIFFLIB_VERSION != 20011807
3072 : if (!SetDirectory())
3073 : return;
3074 :
3075 : TIFFRewriteDirectory( hTIFF );
3076 : #endif
3077 : #endif
3078 73 : bNeedsRewrite = FALSE;
3079 : }
3080 : }
3081 :
3082 : // there are some circumstances in which we can reach this point
3083 : // without having made this our directory (SetDirectory()) in which
3084 : // case we should not risk a flush.
3085 9132 : if( TIFFCurrentDirOffset(hTIFF) == nDirOffset )
3086 : {
3087 : #if defined(HAVE_TIFFGETSIZEPROC)
3088 9121 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
3089 :
3090 9121 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
3091 9121 : if( (nNewDirOffset % 2) == 1 )
3092 870 : nNewDirOffset++;
3093 : #endif
3094 9121 : TIFFFlush( hTIFF );
3095 : #if defined(HAVE_TIFFGETSIZEPROC)
3096 9121 : if( nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
3097 : {
3098 14 : nDirOffset = nNewDirOffset;
3099 : CPLDebug( "GTiff",
3100 14 : "directory moved during flush in FlushDirectory()" );
3101 : }
3102 : #endif
3103 : }
3104 : }
3105 :
3106 : /************************************************************************/
3107 : /* TIFF_OvLevelAdjust() */
3108 : /* */
3109 : /* Some overview levels cannot be achieved closely enough to be */
3110 : /* recognised as the desired overview level. This function */
3111 : /* will adjust an overview level to one that is achievable on */
3112 : /* the given raster size. */
3113 : /* */
3114 : /* For instance a 1200x1200 image on which a 256 level overview */
3115 : /* is request will end up generating a 5x5 overview. However, */
3116 : /* this will appear to the system be a level 240 overview. */
3117 : /* This function will adjust 256 to 240 based on knowledge of */
3118 : /* the image size. */
3119 : /* */
3120 : /* This is a copy of the GDALOvLevelAdjust() function in */
3121 : /* gdaldefaultoverviews.cpp. */
3122 : /************************************************************************/
3123 :
3124 65 : static int TIFF_OvLevelAdjust( int nOvLevel, int nXSize )
3125 :
3126 : {
3127 65 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
3128 :
3129 65 : return (int) (0.5 + nXSize / (double) nOXSize);
3130 : }
3131 :
3132 : /************************************************************************/
3133 : /* CleanOverviews() */
3134 : /************************************************************************/
3135 :
3136 2 : CPLErr GTiffDataset::CleanOverviews()
3137 :
3138 : {
3139 2 : CPLAssert( bBase );
3140 :
3141 2 : FlushDirectory();
3142 2 : *ppoActiveDSRef = NULL;
3143 :
3144 : /* -------------------------------------------------------------------- */
3145 : /* Cleanup overviews objects, and get offsets to all overview */
3146 : /* directories. */
3147 : /* -------------------------------------------------------------------- */
3148 2 : std::vector<toff_t> anOvDirOffsets;
3149 : int i;
3150 :
3151 4 : for( i = 0; i < nOverviewCount; i++ )
3152 : {
3153 2 : anOvDirOffsets.push_back( papoOverviewDS[i]->nDirOffset );
3154 2 : delete papoOverviewDS[i];
3155 : }
3156 :
3157 : /* -------------------------------------------------------------------- */
3158 : /* Loop through all the directories, translating the offsets */
3159 : /* into indexes we can use with TIFFUnlinkDirectory(). */
3160 : /* -------------------------------------------------------------------- */
3161 2 : std::vector<uint16> anOvDirIndexes;
3162 2 : int iThisOffset = 1;
3163 :
3164 2 : TIFFSetDirectory( hTIFF, 0 );
3165 :
3166 2 : for( ; TRUE; )
3167 : {
3168 8 : for( i = 0; i < nOverviewCount; i++ )
3169 : {
3170 4 : if( anOvDirOffsets[i] == TIFFCurrentDirOffset( hTIFF ) )
3171 : {
3172 : CPLDebug( "GTiff", "%d -> %d",
3173 2 : (int) anOvDirOffsets[i], iThisOffset );
3174 2 : anOvDirIndexes.push_back( iThisOffset );
3175 : }
3176 : }
3177 :
3178 4 : if( TIFFLastDirectory( hTIFF ) )
3179 2 : break;
3180 :
3181 2 : TIFFReadDirectory( hTIFF );
3182 2 : iThisOffset++;
3183 : }
3184 :
3185 : /* -------------------------------------------------------------------- */
3186 : /* Actually unlink the target directories. Note that we do */
3187 : /* this from last to first so as to avoid renumbering any of */
3188 : /* the earlier directories we need to remove. */
3189 : /* -------------------------------------------------------------------- */
3190 6 : while( !anOvDirIndexes.empty() )
3191 : {
3192 2 : TIFFUnlinkDirectory( hTIFF, anOvDirIndexes.back() );
3193 2 : anOvDirIndexes.pop_back();
3194 : }
3195 :
3196 2 : CPLFree( papoOverviewDS );
3197 :
3198 2 : nOverviewCount = 0;
3199 2 : papoOverviewDS = NULL;
3200 :
3201 2 : if (!SetDirectory())
3202 0 : return CE_Failure;
3203 :
3204 2 : return CE_None;
3205 : }
3206 :
3207 : /************************************************************************/
3208 : /* IBuildOverviews() */
3209 : /************************************************************************/
3210 :
3211 : CPLErr GTiffDataset::IBuildOverviews(
3212 : const char * pszResampling,
3213 : int nOverviews, int * panOverviewList,
3214 : int nBands, int * panBandList,
3215 122 : GDALProgressFunc pfnProgress, void * pProgressData )
3216 :
3217 : {
3218 122 : CPLErr eErr = CE_None;
3219 : int i;
3220 : GTiffDataset *poODS;
3221 :
3222 : /* -------------------------------------------------------------------- */
3223 : /* If we don't have read access, then create the overviews */
3224 : /* externally. */
3225 : /* -------------------------------------------------------------------- */
3226 122 : if( GetAccess() != GA_Update )
3227 : {
3228 : CPLDebug( "GTiff",
3229 : "File open for read-only accessing, "
3230 58 : "creating overviews externally." );
3231 :
3232 : return GDALDataset::IBuildOverviews(
3233 : pszResampling, nOverviews, panOverviewList,
3234 58 : nBands, panBandList, pfnProgress, pProgressData );
3235 : }
3236 :
3237 : /* -------------------------------------------------------------------- */
3238 : /* If RRD overviews requested, then invoke generic handling. */
3239 : /* -------------------------------------------------------------------- */
3240 64 : if( CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" )) )
3241 : {
3242 : return GDALDataset::IBuildOverviews(
3243 : pszResampling, nOverviews, panOverviewList,
3244 2 : nBands, panBandList, pfnProgress, pProgressData );
3245 : }
3246 :
3247 : /* -------------------------------------------------------------------- */
3248 : /* Our TIFF overview support currently only works safely if all */
3249 : /* bands are handled at the same time. */
3250 : /* -------------------------------------------------------------------- */
3251 62 : if( nBands != GetRasterCount() )
3252 : {
3253 : CPLError( CE_Failure, CPLE_NotSupported,
3254 : "Generation of overviews in TIFF currently only"
3255 : " supported when operating on all bands.\n"
3256 0 : "Operation failed.\n" );
3257 0 : return CE_Failure;
3258 : }
3259 :
3260 : /* -------------------------------------------------------------------- */
3261 : /* Initialize progress counter. */
3262 : /* -------------------------------------------------------------------- */
3263 62 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
3264 : {
3265 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
3266 0 : return CE_Failure;
3267 : }
3268 :
3269 : /* -------------------------------------------------------------------- */
3270 : /* If zero overviews were requested, we need to clear all */
3271 : /* existing overviews. */
3272 : /* -------------------------------------------------------------------- */
3273 62 : if( nOverviews == 0 )
3274 : {
3275 3 : if( nOverviewCount == 0 )
3276 : return GDALDataset::IBuildOverviews(
3277 : pszResampling, nOverviews, panOverviewList,
3278 1 : nBands, panBandList, pfnProgress, pProgressData );
3279 : else
3280 2 : return CleanOverviews();
3281 : }
3282 :
3283 : /* -------------------------------------------------------------------- */
3284 : /* Move to the directory for this dataset. */
3285 : /* -------------------------------------------------------------------- */
3286 59 : if (!SetDirectory())
3287 0 : return CE_Failure;
3288 59 : FlushDirectory();
3289 :
3290 : /* -------------------------------------------------------------------- */
3291 : /* If we are averaging bit data to grayscale we need to create */
3292 : /* 8bit overviews. */
3293 : /* -------------------------------------------------------------------- */
3294 59 : int nOvBitsPerSample = nBitsPerSample;
3295 :
3296 59 : if( EQUALN(pszResampling,"AVERAGE_BIT2",12) )
3297 2 : nOvBitsPerSample = 8;
3298 :
3299 : /* -------------------------------------------------------------------- */
3300 : /* Do we have a palette? If so, create a TIFF compatible version. */
3301 : /* -------------------------------------------------------------------- */
3302 59 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
3303 59 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
3304 :
3305 68 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
3306 : {
3307 : int nColors;
3308 :
3309 9 : if( nOvBitsPerSample == 8 )
3310 9 : nColors = 256;
3311 0 : else if( nOvBitsPerSample < 8 )
3312 0 : nColors = 1 << nOvBitsPerSample;
3313 : else
3314 0 : nColors = 65536;
3315 :
3316 9 : anTRed.resize(nColors,0);
3317 9 : anTGreen.resize(nColors,0);
3318 9 : anTBlue.resize(nColors,0);
3319 :
3320 2313 : for( int iColor = 0; iColor < nColors; iColor++ )
3321 : {
3322 2304 : if( iColor < poColorTable->GetColorEntryCount() )
3323 : {
3324 : GDALColorEntry sRGB;
3325 :
3326 2304 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
3327 :
3328 2304 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
3329 2304 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
3330 2304 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
3331 : }
3332 : else
3333 : {
3334 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
3335 : }
3336 : }
3337 :
3338 9 : panRed = &(anTRed[0]);
3339 9 : panGreen = &(anTGreen[0]);
3340 9 : panBlue = &(anTBlue[0]);
3341 : }
3342 :
3343 : /* -------------------------------------------------------------------- */
3344 : /* Do we need some metadata for the overviews? */
3345 : /* -------------------------------------------------------------------- */
3346 59 : CPLString osMetadata;
3347 :
3348 59 : GTIFFBuildOverviewMetadata( pszResampling, this, osMetadata );
3349 :
3350 : /* -------------------------------------------------------------------- */
3351 : /* Fetch extra sample tag */
3352 : /* -------------------------------------------------------------------- */
3353 59 : uint16 *panExtraSampleValues = NULL;
3354 59 : uint16 nExtraSamples = 0;
3355 :
3356 59 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
3357 : {
3358 8 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
3359 8 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
3360 8 : panExtraSampleValues = panExtraSampleValuesNew;
3361 : }
3362 : else
3363 : {
3364 51 : panExtraSampleValues = NULL;
3365 51 : nExtraSamples = 0;
3366 : }
3367 :
3368 : /* -------------------------------------------------------------------- */
3369 : /* Fetch predictor tag */
3370 : /* -------------------------------------------------------------------- */
3371 59 : uint16 nPredictor = PREDICTOR_NONE;
3372 59 : if ( nCompression == COMPRESSION_LZW ||
3373 : nCompression == COMPRESSION_ADOBE_DEFLATE )
3374 7 : TIFFGetField( hTIFF, TIFFTAG_PREDICTOR, &nPredictor );
3375 :
3376 : /* -------------------------------------------------------------------- */
3377 : /* Establish which of the overview levels we already have, and */
3378 : /* which are new. We assume that band 1 of the file is */
3379 : /* representative. */
3380 : /* -------------------------------------------------------------------- */
3381 : int nOvrBlockXSize, nOvrBlockYSize;
3382 59 : GTIFFGetOverviewBlockSize(&nOvrBlockXSize, &nOvrBlockYSize);
3383 140 : for( i = 0; i < nOverviews && eErr == CE_None; i++ )
3384 : {
3385 : int j;
3386 :
3387 114 : for( j = 0; j < nOverviewCount; j++ )
3388 : {
3389 : int nOvFactor;
3390 :
3391 33 : poODS = papoOverviewDS[j];
3392 :
3393 : nOvFactor = (int)
3394 33 : (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
3395 :
3396 33 : if( nOvFactor == panOverviewList[i]
3397 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3398 : GetRasterXSize() ) )
3399 8 : panOverviewList[i] *= -1;
3400 : }
3401 :
3402 81 : if( panOverviewList[i] > 0 )
3403 : {
3404 : toff_t nOverviewOffset;
3405 : int nOXSize, nOYSize;
3406 :
3407 : nOXSize = (GetRasterXSize() + panOverviewList[i] - 1)
3408 73 : / panOverviewList[i];
3409 : nOYSize = (GetRasterYSize() + panOverviewList[i] - 1)
3410 73 : / panOverviewList[i];
3411 :
3412 : nOverviewOffset =
3413 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
3414 : nOXSize, nOYSize,
3415 : nOvBitsPerSample, nPlanarConfig,
3416 : nSamplesPerPixel, nOvrBlockXSize, nOvrBlockYSize, TRUE,
3417 : nCompression, nPhotometric, nSampleFormat,
3418 : nPredictor,
3419 : panRed, panGreen, panBlue,
3420 : nExtraSamples, panExtraSampleValues,
3421 73 : osMetadata );
3422 :
3423 73 : if( nOverviewOffset == 0 )
3424 : {
3425 0 : eErr = CE_Failure;
3426 0 : continue;
3427 : }
3428 :
3429 73 : poODS = new GTiffDataset();
3430 146 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nOverviewOffset, FALSE,
3431 : GA_Update ) != CE_None )
3432 : {
3433 0 : delete poODS;
3434 0 : eErr = CE_Failure;
3435 : }
3436 : else
3437 : {
3438 73 : nOverviewCount++;
3439 : papoOverviewDS = (GTiffDataset **)
3440 : CPLRealloc(papoOverviewDS,
3441 73 : nOverviewCount * (sizeof(void*)));
3442 73 : papoOverviewDS[nOverviewCount-1] = poODS;
3443 73 : poODS->poBaseDS = this;
3444 : }
3445 : }
3446 : else
3447 8 : panOverviewList[i] *= -1;
3448 : }
3449 :
3450 59 : CPLFree(panExtraSampleValues);
3451 59 : panExtraSampleValues = NULL;
3452 :
3453 : /* -------------------------------------------------------------------- */
3454 : /* Create overviews for the mask. */
3455 : /* -------------------------------------------------------------------- */
3456 :
3457 59 : if (poMaskDS != NULL &&
3458 : poMaskDS->GetRasterCount() == 1 &&
3459 : CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
3460 : {
3461 3 : for( i = 0; i < nOverviewCount; i++ )
3462 : {
3463 2 : if (papoOverviewDS[i]->poMaskDS == NULL)
3464 : {
3465 : toff_t nOverviewOffset;
3466 :
3467 : nOverviewOffset =
3468 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
3469 : papoOverviewDS[i]->nRasterXSize, papoOverviewDS[i]->nRasterYSize,
3470 : 1, PLANARCONFIG_CONTIG,
3471 : 1, nOvrBlockXSize, nOvrBlockYSize, TRUE,
3472 : COMPRESSION_NONE, PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT, PREDICTOR_NONE,
3473 : NULL, NULL, NULL, 0, NULL,
3474 2 : "" );
3475 :
3476 2 : if( nOverviewOffset == 0 )
3477 : {
3478 0 : eErr = CE_Failure;
3479 0 : continue;
3480 : }
3481 :
3482 2 : poODS = new GTiffDataset();
3483 4 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef,
3484 : nOverviewOffset, FALSE,
3485 : GA_Update ) != CE_None )
3486 : {
3487 0 : delete poODS;
3488 0 : eErr = CE_Failure;
3489 : }
3490 : else
3491 : {
3492 2 : poODS->poBaseDS = this;
3493 2 : papoOverviewDS[i]->poMaskDS = poODS;
3494 2 : poMaskDS->nOverviewCount++;
3495 : poMaskDS->papoOverviewDS = (GTiffDataset **)
3496 : CPLRealloc(poMaskDS->papoOverviewDS,
3497 2 : poMaskDS->nOverviewCount * (sizeof(void*)));
3498 2 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] = poODS;
3499 : }
3500 : }
3501 : }
3502 : }
3503 :
3504 : /* -------------------------------------------------------------------- */
3505 : /* Refresh overviews for the mask */
3506 : /* -------------------------------------------------------------------- */
3507 59 : if (poMaskDS != NULL &&
3508 : poMaskDS->GetRasterCount() == 1)
3509 : {
3510 : GDALRasterBand **papoOverviewBands;
3511 5 : int nMaskOverviews = 0;
3512 :
3513 5 : papoOverviewBands = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviewCount);
3514 15 : for( i = 0; i < nOverviewCount; i++ )
3515 : {
3516 10 : if (papoOverviewDS[i]->poMaskDS != NULL)
3517 : {
3518 : papoOverviewBands[nMaskOverviews ++] =
3519 8 : papoOverviewDS[i]->poMaskDS->GetRasterBand(1);
3520 : }
3521 : }
3522 : eErr = GDALRegenerateOverviews( (GDALRasterBandH)
3523 : poMaskDS->GetRasterBand(1),
3524 : nMaskOverviews,
3525 : (GDALRasterBandH *) papoOverviewBands,
3526 5 : pszResampling, GDALDummyProgress, NULL);
3527 5 : CPLFree(papoOverviewBands);
3528 : }
3529 :
3530 :
3531 : /* -------------------------------------------------------------------- */
3532 : /* Refresh old overviews that were listed. */
3533 : /* -------------------------------------------------------------------- */
3534 59 : if (nCompression != COMPRESSION_NONE &&
3535 : nPlanarConfig == PLANARCONFIG_CONTIG &&
3536 : GDALDataTypeIsComplex(GetRasterBand( panBandList[0] )->GetRasterDataType()) == FALSE &&
3537 : GetRasterBand( panBandList[0] )->GetColorTable() == NULL &&
3538 : (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
3539 : {
3540 : /* In the case of pixel interleaved compressed overviews, we want to generate */
3541 : /* the overviews for all the bands block by block, and not band after band, */
3542 : /* in order to write the block once and not loose space in the TIFF file */
3543 :
3544 : GDALRasterBand ***papapoOverviewBands;
3545 : GDALRasterBand **papoBandList;
3546 :
3547 8 : int nNewOverviews = 0;
3548 : int iBand;
3549 :
3550 8 : papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
3551 8 : papoBandList = (GDALRasterBand **) CPLCalloc(sizeof(void*),nBands);
3552 28 : for( iBand = 0; iBand < nBands; iBand++ )
3553 : {
3554 20 : GDALRasterBand* poBand = GetRasterBand( panBandList[iBand] );
3555 :
3556 20 : papoBandList[iBand] = poBand;
3557 20 : papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*), poBand->GetOverviewCount());
3558 :
3559 20 : int iCurOverview = 0;
3560 42 : for( i = 0; i < nOverviews; i++ )
3561 : {
3562 : int j;
3563 :
3564 24 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
3565 : {
3566 : int nOvFactor;
3567 24 : GDALRasterBand * poOverview = poBand->GetOverview( j );
3568 :
3569 : nOvFactor = (int)
3570 24 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
3571 :
3572 : int bHasNoData;
3573 24 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
3574 :
3575 24 : if (bHasNoData)
3576 18 : poOverview->SetNoDataValue(noDataValue);
3577 :
3578 24 : if( nOvFactor == panOverviewList[i]
3579 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3580 : poBand->GetXSize() ) )
3581 : {
3582 22 : papapoOverviewBands[iBand][iCurOverview] = poOverview;
3583 22 : iCurOverview++ ;
3584 22 : break;
3585 : }
3586 : }
3587 : }
3588 :
3589 20 : if (nNewOverviews == 0)
3590 8 : nNewOverviews = iCurOverview;
3591 12 : else if (nNewOverviews != iCurOverview)
3592 : {
3593 0 : CPLAssert(0);
3594 59 : return CE_Failure;
3595 : }
3596 : }
3597 :
3598 : GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
3599 : nNewOverviews, papapoOverviewBands,
3600 8 : pszResampling, pfnProgress, pProgressData );
3601 :
3602 28 : for( iBand = 0; iBand < nBands; iBand++ )
3603 : {
3604 20 : CPLFree(papapoOverviewBands[iBand]);
3605 : }
3606 8 : CPLFree(papapoOverviewBands);
3607 8 : CPLFree(papoBandList);
3608 : }
3609 : else
3610 : {
3611 : GDALRasterBand **papoOverviewBands;
3612 :
3613 : papoOverviewBands = (GDALRasterBand **)
3614 51 : CPLCalloc(sizeof(void*),nOverviews);
3615 :
3616 124 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
3617 : {
3618 : GDALRasterBand *poBand;
3619 : int nNewOverviews;
3620 :
3621 73 : poBand = GetRasterBand( panBandList[iBand] );
3622 :
3623 73 : nNewOverviews = 0;
3624 184 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
3625 : {
3626 : int j;
3627 :
3628 149 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
3629 : {
3630 : int nOvFactor;
3631 149 : GDALRasterBand * poOverview = poBand->GetOverview( j );
3632 :
3633 : int bHasNoData;
3634 149 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
3635 :
3636 149 : if (bHasNoData)
3637 7 : poOverview->SetNoDataValue(noDataValue);
3638 :
3639 : nOvFactor = (int)
3640 149 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
3641 :
3642 149 : if( nOvFactor == panOverviewList[i]
3643 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3644 : poBand->GetXSize() ) )
3645 : {
3646 111 : papoOverviewBands[nNewOverviews++] = poOverview;
3647 111 : break;
3648 : }
3649 : }
3650 : }
3651 :
3652 : void *pScaledProgressData;
3653 :
3654 : pScaledProgressData =
3655 : GDALCreateScaledProgress( iBand / (double) nBands,
3656 : (iBand+1) / (double) nBands,
3657 73 : pfnProgress, pProgressData );
3658 :
3659 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
3660 : nNewOverviews,
3661 : (GDALRasterBandH *) papoOverviewBands,
3662 : pszResampling,
3663 : GDALScaledProgress,
3664 73 : pScaledProgressData);
3665 :
3666 73 : GDALDestroyScaledProgress( pScaledProgressData );
3667 : }
3668 :
3669 : /* -------------------------------------------------------------------- */
3670 : /* Cleanup */
3671 : /* -------------------------------------------------------------------- */
3672 51 : CPLFree( papoOverviewBands );
3673 : }
3674 :
3675 :
3676 59 : pfnProgress( 1.0, NULL, pProgressData );
3677 :
3678 59 : return eErr;
3679 : }
3680 :
3681 :
3682 : /************************************************************************/
3683 : /* WriteGeoTIFFInfo() */
3684 : /************************************************************************/
3685 :
3686 797 : void GTiffDataset::WriteGeoTIFFInfo()
3687 :
3688 : {
3689 : /* -------------------------------------------------------------------- */
3690 : /* If the geotransform is the default, don't bother writing it. */
3691 : /* -------------------------------------------------------------------- */
3692 1389 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
3693 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
3694 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 )
3695 : {
3696 592 : bNeedsRewrite = TRUE;
3697 :
3698 : /* -------------------------------------------------------------------- */
3699 : /* Clear old tags to ensure we don't end up with conflicting */
3700 : /* information. (#2625) */
3701 : /* -------------------------------------------------------------------- */
3702 : #ifdef HAVE_UNSETFIELD
3703 592 : TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
3704 592 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTIEPOINTS );
3705 592 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTRANSMATRIX );
3706 : #endif
3707 :
3708 : /* -------------------------------------------------------------------- */
3709 : /* Write the transform. If we have a normal north-up image we */
3710 : /* use the tiepoint plus pixelscale otherwise we use a matrix. */
3711 : /* -------------------------------------------------------------------- */
3712 1181 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
3713 : && adfGeoTransform[5] < 0.0 )
3714 : {
3715 : double adfPixelScale[3], adfTiePoints[6];
3716 :
3717 589 : adfPixelScale[0] = adfGeoTransform[1];
3718 589 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
3719 589 : adfPixelScale[2] = 0.0;
3720 :
3721 589 : if( !EQUAL(osProfile,"BASELINE") )
3722 584 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
3723 :
3724 589 : adfTiePoints[0] = 0.0;
3725 589 : adfTiePoints[1] = 0.0;
3726 589 : adfTiePoints[2] = 0.0;
3727 589 : adfTiePoints[3] = adfGeoTransform[0];
3728 589 : adfTiePoints[4] = adfGeoTransform[3];
3729 589 : adfTiePoints[5] = 0.0;
3730 :
3731 589 : if( !EQUAL(osProfile,"BASELINE") )
3732 584 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
3733 : }
3734 : else
3735 : {
3736 : double adfMatrix[16];
3737 :
3738 3 : memset(adfMatrix,0,sizeof(double) * 16);
3739 :
3740 3 : adfMatrix[0] = adfGeoTransform[1];
3741 3 : adfMatrix[1] = adfGeoTransform[2];
3742 3 : adfMatrix[3] = adfGeoTransform[0];
3743 3 : adfMatrix[4] = adfGeoTransform[4];
3744 3 : adfMatrix[5] = adfGeoTransform[5];
3745 3 : adfMatrix[7] = adfGeoTransform[3];
3746 3 : adfMatrix[15] = 1.0;
3747 :
3748 3 : if( !EQUAL(osProfile,"BASELINE") )
3749 3 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
3750 : }
3751 :
3752 : // Do we need a world file?
3753 592 : if( CSLFetchBoolean( papszCreationOptions, "TFW", FALSE ) )
3754 2 : GDALWriteWorldFile( osFilename, "tfw", adfGeoTransform );
3755 590 : else if( CSLFetchBoolean( papszCreationOptions, "WORLDFILE", FALSE ) )
3756 2 : GDALWriteWorldFile( osFilename, "wld", adfGeoTransform );
3757 : }
3758 205 : else if( GetGCPCount() > 0 )
3759 : {
3760 : double *padfTiePoints;
3761 : int iGCP;
3762 2 : bNeedsRewrite = TRUE;
3763 :
3764 : padfTiePoints = (double *)
3765 2 : CPLMalloc( 6 * sizeof(double) * GetGCPCount() );
3766 :
3767 14 : for( iGCP = 0; iGCP < GetGCPCount(); iGCP++ )
3768 : {
3769 :
3770 12 : padfTiePoints[iGCP*6+0] = pasGCPList[iGCP].dfGCPPixel;
3771 12 : padfTiePoints[iGCP*6+1] = pasGCPList[iGCP].dfGCPLine;
3772 12 : padfTiePoints[iGCP*6+2] = 0;
3773 12 : padfTiePoints[iGCP*6+3] = pasGCPList[iGCP].dfGCPX;
3774 12 : padfTiePoints[iGCP*6+4] = pasGCPList[iGCP].dfGCPY;
3775 12 : padfTiePoints[iGCP*6+5] = pasGCPList[iGCP].dfGCPZ;
3776 : }
3777 :
3778 2 : if( !EQUAL(osProfile,"BASELINE") )
3779 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
3780 2 : 6 * GetGCPCount(), padfTiePoints );
3781 2 : CPLFree( padfTiePoints );
3782 : }
3783 :
3784 : /* -------------------------------------------------------------------- */
3785 : /* Write out projection definition. */
3786 : /* -------------------------------------------------------------------- */
3787 797 : if( pszProjection != NULL && !EQUAL( pszProjection, "" )
3788 : && !EQUAL(osProfile,"BASELINE") )
3789 : {
3790 : GTIF *psGTIF;
3791 :
3792 596 : bNeedsRewrite = TRUE;
3793 :
3794 : // If we have existing geokeys, try to wipe them
3795 : // by writing a dummy goekey directory. (#2546)
3796 596 : uint16 *panVI = NULL;
3797 : uint16 nKeyCount;
3798 :
3799 596 : if( TIFFGetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
3800 : &nKeyCount, &panVI ) )
3801 : {
3802 11 : GUInt16 anGKVersionInfo[4] = { 1, 1, 0, 0 };
3803 11 : double adfDummyDoubleParams[1] = { 0.0 };
3804 : TIFFSetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
3805 11 : 4, anGKVersionInfo );
3806 : TIFFSetField( hTIFF, TIFFTAG_GEODOUBLEPARAMS,
3807 11 : 1, adfDummyDoubleParams );
3808 11 : TIFFSetField( hTIFF, TIFFTAG_GEOASCIIPARAMS, "" );
3809 : }
3810 :
3811 596 : psGTIF = GTIFNew( hTIFF );
3812 :
3813 : // set according to coordinate system.
3814 596 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
3815 :
3816 596 : if( GetMetadataItem( GDALMD_AREA_OR_POINT )
3817 : && EQUAL(GetMetadataItem(GDALMD_AREA_OR_POINT),
3818 : GDALMD_AOP_POINT) )
3819 : {
3820 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
3821 4 : RasterPixelIsPoint);
3822 : }
3823 :
3824 596 : GTIFWriteKeys( psGTIF );
3825 596 : GTIFFree( psGTIF );
3826 : }
3827 797 : }
3828 :
3829 : /************************************************************************/
3830 : /* AppendMetadataItem() */
3831 : /************************************************************************/
3832 :
3833 : static void AppendMetadataItem( CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
3834 : const char *pszKey, const char *pszValue,
3835 : int nBand, const char *pszRole,
3836 184 : const char *pszDomain )
3837 :
3838 : {
3839 : char szBandId[32];
3840 : CPLXMLNode *psItem;
3841 :
3842 : /* -------------------------------------------------------------------- */
3843 : /* Create the Item element, and subcomponents. */
3844 : /* -------------------------------------------------------------------- */
3845 184 : psItem = CPLCreateXMLNode( NULL, CXT_Element, "Item" );
3846 : CPLCreateXMLNode( CPLCreateXMLNode( psItem, CXT_Attribute, "name"),
3847 184 : CXT_Text, pszKey );
3848 :
3849 184 : if( nBand > 0 )
3850 : {
3851 39 : sprintf( szBandId, "%d", nBand - 1 );
3852 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"sample"),
3853 39 : CXT_Text, szBandId );
3854 : }
3855 :
3856 184 : if( pszRole != NULL )
3857 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"role"),
3858 9 : CXT_Text, pszRole );
3859 :
3860 184 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
3861 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"domain"),
3862 1 : CXT_Text, pszDomain );
3863 :
3864 184 : char *pszEscapedItemValue = CPLEscapeString(pszValue,-1,CPLES_XML);
3865 184 : CPLCreateXMLNode( psItem, CXT_Text, pszEscapedItemValue );
3866 184 : CPLFree( pszEscapedItemValue );
3867 :
3868 : /* -------------------------------------------------------------------- */
3869 : /* Create root, if missing. */
3870 : /* -------------------------------------------------------------------- */
3871 184 : if( *ppsRoot == NULL )
3872 54 : *ppsRoot = CPLCreateXMLNode( NULL, CXT_Element, "GDALMetadata" );
3873 :
3874 : /* -------------------------------------------------------------------- */
3875 : /* Append item to tail. We keep track of the tail to avoid */
3876 : /* O(nsquared) time as the list gets longer. */
3877 : /* -------------------------------------------------------------------- */
3878 184 : if( *ppsTail == NULL )
3879 54 : CPLAddXMLChild( *ppsRoot, psItem );
3880 : else
3881 130 : CPLAddXMLSibling( *ppsTail, psItem );
3882 :
3883 184 : *ppsTail = psItem;
3884 184 : }
3885 :
3886 : /************************************************************************/
3887 : /* WriteMDMDMetadata() */
3888 : /************************************************************************/
3889 :
3890 : static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
3891 : CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
3892 132971 : int nBand, const char *pszProfile )
3893 :
3894 : {
3895 : int iDomain;
3896 : char **papszDomainList;
3897 :
3898 : (void) pszProfile;
3899 :
3900 : /* ==================================================================== */
3901 : /* Process each domain. */
3902 : /* ==================================================================== */
3903 132971 : papszDomainList = poMDMD->GetDomainList();
3904 133166 : for( iDomain = 0; papszDomainList && papszDomainList[iDomain]; iDomain++ )
3905 : {
3906 195 : char **papszMD = poMDMD->GetMetadata( papszDomainList[iDomain] );
3907 : int iItem;
3908 195 : int bIsXML = FALSE;
3909 :
3910 195 : if( EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") )
3911 42 : continue; // ignored
3912 153 : if( EQUAL(papszDomainList[iDomain], "RPC") )
3913 0 : continue; // handled elsewhere
3914 153 : if( EQUALN(papszDomainList[iDomain], "xml:",4 ) )
3915 1 : bIsXML = TRUE;
3916 :
3917 : /* -------------------------------------------------------------------- */
3918 : /* Process each item in this domain. */
3919 : /* -------------------------------------------------------------------- */
3920 428 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
3921 : {
3922 : const char *pszItemValue;
3923 275 : char *pszItemName = NULL;
3924 :
3925 275 : if( bIsXML )
3926 : {
3927 1 : pszItemName = CPLStrdup("doc");
3928 1 : pszItemValue = papszMD[iItem];
3929 : }
3930 : else
3931 : {
3932 274 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
3933 : }
3934 :
3935 : /* -------------------------------------------------------------------- */
3936 : /* Convert into XML item or handle as a special TIFF tag. */
3937 : /* -------------------------------------------------------------------- */
3938 304 : if( strlen(papszDomainList[iDomain]) == 0
3939 : && nBand == 0 && EQUALN(pszItemName,"TIFFTAG_",8) )
3940 : {
3941 29 : if( EQUAL(pszItemName,"TIFFTAG_DOCUMENTNAME") )
3942 4 : TIFFSetField( hTIFF, TIFFTAG_DOCUMENTNAME, pszItemValue );
3943 25 : else if( EQUAL(pszItemName,"TIFFTAG_IMAGEDESCRIPTION") )
3944 1 : TIFFSetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, pszItemValue );
3945 24 : else if( EQUAL(pszItemName,"TIFFTAG_SOFTWARE") )
3946 2 : TIFFSetField( hTIFF, TIFFTAG_SOFTWARE, pszItemValue );
3947 22 : else if( EQUAL(pszItemName,"TIFFTAG_DATETIME") )
3948 1 : TIFFSetField( hTIFF, TIFFTAG_DATETIME, pszItemValue );
3949 21 : else if( EQUAL(pszItemName,"TIFFTAG_ARTIST") )
3950 1 : TIFFSetField( hTIFF, TIFFTAG_ARTIST, pszItemValue );
3951 20 : else if( EQUAL(pszItemName,"TIFFTAG_HOSTCOMPUTER") )
3952 1 : TIFFSetField( hTIFF, TIFFTAG_HOSTCOMPUTER, pszItemValue );
3953 19 : else if( EQUAL(pszItemName,"TIFFTAG_COPYRIGHT") )
3954 1 : TIFFSetField( hTIFF, TIFFTAG_COPYRIGHT, pszItemValue );
3955 18 : else if( EQUAL(pszItemName,"TIFFTAG_XRESOLUTION") )
3956 6 : TIFFSetField( hTIFF, TIFFTAG_XRESOLUTION, atof(pszItemValue) );
3957 12 : else if( EQUAL(pszItemName,"TIFFTAG_YRESOLUTION") )
3958 6 : TIFFSetField( hTIFF, TIFFTAG_YRESOLUTION, atof(pszItemValue) );
3959 6 : else if( EQUAL(pszItemName,"TIFFTAG_RESOLUTIONUNIT") )
3960 6 : TIFFSetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, atoi(pszItemValue) );
3961 : else
3962 : CPLError(CE_Warning, CPLE_NotSupported,
3963 : "%s metadata item is unhandled and will not be written",
3964 0 : pszItemName);
3965 : }
3966 246 : else if( nBand == 0 && EQUAL(pszItemName,GDALMD_AREA_OR_POINT) )
3967 : /* do nothing, handled elsewhere */;
3968 : else
3969 : AppendMetadataItem( ppsRoot, ppsTail,
3970 : pszItemName, pszItemValue,
3971 175 : nBand, NULL, papszDomainList[iDomain] );
3972 :
3973 275 : CPLFree( pszItemName );
3974 : }
3975 : }
3976 132971 : }
3977 :
3978 : /************************************************************************/
3979 : /* WriteMetadata() */
3980 : /************************************************************************/
3981 :
3982 : int GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
3983 : int bSrcIsGeoTIFF,
3984 : const char *pszProfile,
3985 : const char *pszTIFFFilename,
3986 : char **papszCreationOptions,
3987 954 : int bExcludeRPBandIMGFileWriting)
3988 :
3989 : {
3990 : /* -------------------------------------------------------------------- */
3991 : /* Convert all the remaining metadata into a simple XML */
3992 : /* format. */
3993 : /* -------------------------------------------------------------------- */
3994 954 : CPLXMLNode *psRoot = NULL, *psTail = NULL;
3995 :
3996 954 : if( bSrcIsGeoTIFF )
3997 : {
3998 : WriteMDMetadata( &(((GTiffDataset *)poSrcDS)->oGTiffMDMD),
3999 797 : hTIFF, &psRoot, &psTail, 0, pszProfile );
4000 : }
4001 : else
4002 : {
4003 157 : char **papszMD = poSrcDS->GetMetadata();
4004 :
4005 157 : if( CSLCount(papszMD) > 0 )
4006 : {
4007 86 : GDALMultiDomainMetadata oMDMD;
4008 86 : oMDMD.SetMetadata( papszMD );
4009 :
4010 86 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, 0, pszProfile );
4011 : }
4012 : }
4013 :
4014 : /* -------------------------------------------------------------------- */
4015 : /* Handle RPC data written to an RPB file. */
4016 : /* -------------------------------------------------------------------- */
4017 954 : char **papszRPCMD = poSrcDS->GetMetadata("RPC");
4018 954 : if( papszRPCMD != NULL && !bExcludeRPBandIMGFileWriting )
4019 : {
4020 2 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
4021 1 : WriteRPCTag( hTIFF, papszRPCMD );
4022 :
4023 2 : if( !EQUAL(pszProfile,"GDALGeoTIFF")
4024 : || CSLFetchBoolean( papszCreationOptions, "RPB", FALSE ) )
4025 : {
4026 1 : GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
4027 : }
4028 : }
4029 :
4030 : /* -------------------------------------------------------------------- */
4031 : /* Handle metadata data written to an IMD file. */
4032 : /* -------------------------------------------------------------------- */
4033 954 : char **papszIMDMD = poSrcDS->GetMetadata("IMD");
4034 954 : if( papszIMDMD != NULL && !bExcludeRPBandIMGFileWriting)
4035 : {
4036 2 : GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
4037 : }
4038 :
4039 : /* -------------------------------------------------------------------- */
4040 : /* We also need to address band specific metadata, and special */
4041 : /* "role" metadata. */
4042 : /* -------------------------------------------------------------------- */
4043 : int nBand;
4044 133267 : for( nBand = 1; nBand <= poSrcDS->GetRasterCount(); nBand++ )
4045 : {
4046 132313 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( nBand );
4047 :
4048 132313 : if( bSrcIsGeoTIFF )
4049 : {
4050 : WriteMDMetadata( &(((GTiffRasterBand *)poBand)->oGTiffMDMD),
4051 132062 : hTIFF, &psRoot, &psTail, nBand, pszProfile );
4052 : }
4053 : else
4054 : {
4055 251 : char **papszMD = poBand->GetMetadata();
4056 :
4057 251 : if( CSLCount(papszMD) > 0 )
4058 : {
4059 26 : GDALMultiDomainMetadata oMDMD;
4060 26 : oMDMD.SetMetadata( papszMD );
4061 :
4062 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, nBand,
4063 26 : pszProfile );
4064 : }
4065 : }
4066 :
4067 : int bSuccess;
4068 132313 : double dfOffset = poBand->GetOffset( &bSuccess );
4069 132313 : double dfScale = poBand->GetScale();
4070 :
4071 132313 : if( bSuccess && (dfOffset != 0.0 || dfScale != 1.0) )
4072 : {
4073 : char szValue[128];
4074 :
4075 2 : sprintf( szValue, "%.18g", dfOffset );
4076 : AppendMetadataItem( &psRoot, &psTail, "OFFSET", szValue, nBand,
4077 2 : "offset", "" );
4078 2 : sprintf( szValue, "%.18g", dfScale );
4079 : AppendMetadataItem( &psRoot, &psTail, "SCALE", szValue, nBand,
4080 2 : "scale", "" );
4081 : }
4082 :
4083 132313 : const char* pszUnitType = poBand->GetUnitType();
4084 132313 : if (pszUnitType != NULL && pszUnitType[0] != '\0')
4085 : AppendMetadataItem( &psRoot, &psTail, "UNITTYPE", pszUnitType, nBand,
4086 5 : "unittype", "" );
4087 : }
4088 :
4089 : /* -------------------------------------------------------------------- */
4090 : /* Write out the generic XML metadata if there is any. */
4091 : /* -------------------------------------------------------------------- */
4092 954 : if( psRoot != NULL )
4093 : {
4094 54 : int bRet = TRUE;
4095 :
4096 54 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
4097 : {
4098 44 : char *pszXML_MD = CPLSerializeXMLTree( psRoot );
4099 44 : if( strlen(pszXML_MD) > 32000 )
4100 : {
4101 1 : if( bSrcIsGeoTIFF )
4102 1 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
4103 : else
4104 0 : bRet = FALSE;
4105 : CPLError( CE_Warning, CPLE_AppDefined,
4106 1 : "Lost metadata writing to GeoTIFF ... too large to fit in tag." );
4107 : }
4108 : else
4109 : {
4110 43 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszXML_MD );
4111 : }
4112 44 : CPLFree( pszXML_MD );
4113 : }
4114 : else
4115 : {
4116 10 : if( bSrcIsGeoTIFF )
4117 6 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
4118 : else
4119 4 : bRet = FALSE;
4120 : }
4121 :
4122 54 : CPLDestroyXMLNode( psRoot );
4123 :
4124 54 : return bRet;
4125 : }
4126 : else
4127 : {
4128 : /* If we have no more metadata but it existed before, remove the GDAL_METADATA tag */
4129 900 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
4130 : {
4131 895 : char* pszText = NULL;
4132 895 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
4133 : {
4134 : #ifdef HAVE_UNSETFIELD
4135 2 : TIFFUnsetField( hTIFF, TIFFTAG_GDAL_METADATA );
4136 : #else
4137 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, "" );
4138 : #endif
4139 : }
4140 : }
4141 : }
4142 :
4143 900 : return TRUE;
4144 : }
4145 :
4146 : /************************************************************************/
4147 : /* PushMetadataToPam() */
4148 : /* */
4149 : /* When producing a strict profile TIFF or if our aggregate */
4150 : /* metadata is too big for a single tiff tag we may end up */
4151 : /* needing to write it via the PAM mechanisms. This method */
4152 : /* copies all the appropriate metadata into the PAM level */
4153 : /* metadata object but with special care to avoid copying */
4154 : /* metadata handled in other ways in TIFF format. */
4155 : /************************************************************************/
4156 :
4157 33 : void GTiffDataset::PushMetadataToPam()
4158 :
4159 : {
4160 : int nBand;
4161 111 : for( nBand = 0; nBand <= GetRasterCount(); nBand++ )
4162 : {
4163 : GDALMultiDomainMetadata *poSrcMDMD;
4164 78 : GTiffRasterBand *poBand = NULL;
4165 :
4166 78 : if( nBand == 0 )
4167 33 : poSrcMDMD = &(this->oGTiffMDMD);
4168 : else
4169 : {
4170 45 : poBand = (GTiffRasterBand *) GetRasterBand(nBand);
4171 45 : poSrcMDMD = &(poBand->oGTiffMDMD);
4172 : }
4173 :
4174 : /* -------------------------------------------------------------------- */
4175 : /* Loop over the available domains. */
4176 : /* -------------------------------------------------------------------- */
4177 : int iDomain, i;
4178 : char **papszDomainList;
4179 :
4180 78 : papszDomainList = poSrcMDMD->GetDomainList();
4181 171 : for( iDomain = 0;
4182 : papszDomainList && papszDomainList[iDomain];
4183 : iDomain++ )
4184 : {
4185 93 : char **papszMD = poSrcMDMD->GetMetadata( papszDomainList[iDomain] );
4186 :
4187 93 : if( EQUAL(papszDomainList[iDomain],"RPC")
4188 : || EQUAL(papszDomainList[iDomain],"IMD")
4189 : || EQUAL(papszDomainList[iDomain],"_temporary_")
4190 : || EQUAL(papszDomainList[iDomain],"IMAGE_STRUCTURE") )
4191 36 : continue;
4192 :
4193 57 : papszMD = CSLDuplicate(papszMD);
4194 :
4195 197 : for( i = CSLCount(papszMD)-1; i >= 0; i-- )
4196 : {
4197 140 : if( EQUALN(papszMD[i],"TIFFTAG_",8)
4198 : || EQUALN(papszMD[i],GDALMD_AREA_OR_POINT,
4199 : strlen(GDALMD_AREA_OR_POINT)) )
4200 25 : papszMD = CSLRemoveStrings( papszMD, i, 1, NULL );
4201 : }
4202 :
4203 57 : if( nBand == 0 )
4204 25 : GDALPamDataset::SetMetadata( papszMD, papszDomainList[iDomain]);
4205 : else
4206 32 : poBand->GDALPamRasterBand::SetMetadata( papszMD, papszDomainList[iDomain]);
4207 :
4208 57 : CSLDestroy( papszMD );
4209 : }
4210 :
4211 : /* -------------------------------------------------------------------- */
4212 : /* Handle some "special domain" stuff. */
4213 : /* -------------------------------------------------------------------- */
4214 78 : if( poBand != NULL )
4215 : {
4216 : int bSuccess;
4217 45 : double dfOffset = poBand->GetOffset( &bSuccess );
4218 45 : double dfScale = poBand->GetScale();
4219 :
4220 45 : if( bSuccess )
4221 : {
4222 42 : poBand->GDALPamRasterBand::SetScale( dfScale );
4223 42 : poBand->GDALPamRasterBand::SetOffset( dfOffset );
4224 : }
4225 :
4226 45 : poBand->GDALPamRasterBand::SetUnitType( poBand->GetUnitType() );
4227 : }
4228 : }
4229 33 : }
4230 :
4231 : /************************************************************************/
4232 : /* WriteRPCTag() */
4233 : /* */
4234 : /* Format a TAG according to: */
4235 : /* */
4236 : /* http://geotiff.maptools.org/rpc_prop.html */
4237 : /************************************************************************/
4238 :
4239 : /* static */
4240 1 : void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
4241 :
4242 : {
4243 : double adfRPCTag[92];
4244 : GDALRPCInfo sRPC;
4245 :
4246 1 : if( !GDALExtractRPCInfo( papszRPCMD, &sRPC ) )
4247 0 : return;
4248 :
4249 1 : adfRPCTag[0] = -1.0; // Error Bias
4250 1 : adfRPCTag[1] = -1.0; // Error Random
4251 :
4252 1 : adfRPCTag[2] = sRPC.dfLINE_OFF;
4253 1 : adfRPCTag[3] = sRPC.dfSAMP_OFF;
4254 1 : adfRPCTag[4] = sRPC.dfLAT_OFF;
4255 1 : adfRPCTag[5] = sRPC.dfLONG_OFF;
4256 1 : adfRPCTag[6] = sRPC.dfHEIGHT_OFF;
4257 1 : adfRPCTag[7] = sRPC.dfLINE_SCALE;
4258 1 : adfRPCTag[8] = sRPC.dfSAMP_SCALE;
4259 1 : adfRPCTag[9] = sRPC.dfLAT_SCALE;
4260 1 : adfRPCTag[10] = sRPC.dfLONG_SCALE;
4261 1 : adfRPCTag[11] = sRPC.dfHEIGHT_SCALE;
4262 :
4263 1 : memcpy( adfRPCTag + 12, sRPC.adfLINE_NUM_COEFF, sizeof(double) * 20 );
4264 1 : memcpy( adfRPCTag + 32, sRPC.adfLINE_DEN_COEFF, sizeof(double) * 20 );
4265 1 : memcpy( adfRPCTag + 52, sRPC.adfSAMP_NUM_COEFF, sizeof(double) * 20 );
4266 1 : memcpy( adfRPCTag + 72, sRPC.adfSAMP_DEN_COEFF, sizeof(double) * 20 );
4267 :
4268 1 : TIFFSetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, 92, adfRPCTag );
4269 : }
4270 :
4271 : /************************************************************************/
4272 : /* ReadRPCTag() */
4273 : /* */
4274 : /* Format a TAG according to: */
4275 : /* */
4276 : /* http://geotiff.maptools.org/rpc_prop.html */
4277 : /************************************************************************/
4278 :
4279 3485 : void GTiffDataset::ReadRPCTag()
4280 :
4281 : {
4282 : double *padfRPCTag;
4283 3485 : char **papszMD = NULL;
4284 3485 : CPLString osField;
4285 3485 : CPLString osMultiField;
4286 : int i;
4287 : uint16 nCount;
4288 :
4289 3485 : if( !TIFFGetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag )
4290 : || nCount != 92 )
4291 3482 : return;
4292 :
4293 3 : osField.Printf( "%.15g", padfRPCTag[2] );
4294 3 : papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
4295 :
4296 3 : osField.Printf( "%.15g", padfRPCTag[3] );
4297 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
4298 :
4299 3 : osField.Printf( "%.15g", padfRPCTag[4] );
4300 3 : papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
4301 :
4302 3 : osField.Printf( "%.15g", padfRPCTag[5] );
4303 3 : papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
4304 :
4305 3 : osField.Printf( "%.15g", padfRPCTag[6] );
4306 3 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
4307 :
4308 3 : osField.Printf( "%.15g", padfRPCTag[7] );
4309 3 : papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
4310 :
4311 3 : osField.Printf( "%.15g", padfRPCTag[8] );
4312 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
4313 :
4314 3 : osField.Printf( "%.15g", padfRPCTag[9] );
4315 3 : papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
4316 :
4317 3 : osField.Printf( "%.15g", padfRPCTag[10] );
4318 3 : papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
4319 :
4320 3 : osField.Printf( "%.15g", padfRPCTag[11] );
4321 3 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
4322 :
4323 63 : for( i = 0; i < 20; i++ )
4324 : {
4325 60 : osField.Printf( "%.15g", padfRPCTag[12+i] );
4326 60 : if( i > 0 )
4327 57 : osMultiField += " ";
4328 : else
4329 3 : osMultiField = "";
4330 60 : osMultiField += osField;
4331 : }
4332 3 : papszMD = CSLSetNameValue( papszMD, "LINE_NUM_COEFF", osMultiField );
4333 :
4334 63 : for( i = 0; i < 20; i++ )
4335 : {
4336 60 : osField.Printf( "%.15g", padfRPCTag[32+i] );
4337 60 : if( i > 0 )
4338 57 : osMultiField += " ";
4339 : else
4340 3 : osMultiField = "";
4341 60 : osMultiField += osField;
4342 : }
4343 3 : papszMD = CSLSetNameValue( papszMD, "LINE_DEN_COEFF", osMultiField );
4344 :
4345 63 : for( i = 0; i < 20; i++ )
4346 : {
4347 60 : osField.Printf( "%.15g", padfRPCTag[52+i] );
4348 60 : if( i > 0 )
4349 57 : osMultiField += " ";
4350 : else
4351 3 : osMultiField = "";
4352 60 : osMultiField += osField;
4353 : }
4354 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_NUM_COEFF", osMultiField );
4355 :
4356 63 : for( i = 0; i < 20; i++ )
4357 : {
4358 60 : osField.Printf( "%.15g", padfRPCTag[72+i] );
4359 60 : if( i > 0 )
4360 57 : osMultiField += " ";
4361 : else
4362 3 : osMultiField = "";
4363 60 : osMultiField += osField;
4364 : }
4365 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_DEN_COEFF", osMultiField );
4366 :
4367 3 : oGTiffMDMD.SetMetadata( papszMD, "RPC" );
4368 3 : CSLDestroy( papszMD );
4369 : }
4370 :
4371 : /************************************************************************/
4372 : /* WriteNoDataValue() */
4373 : /************************************************************************/
4374 :
4375 68 : void GTiffDataset::WriteNoDataValue( TIFF *hTIFF, double dfNoData )
4376 :
4377 : {
4378 : char szVal[400];
4379 68 : if (CPLIsNan(dfNoData))
4380 1 : strcpy(szVal, "nan");
4381 : else
4382 67 : snprintf(szVal, sizeof(szVal), "%.18g", dfNoData);
4383 68 : TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA, szVal );
4384 68 : }
4385 :
4386 : /************************************************************************/
4387 : /* SetDirectory() */
4388 : /************************************************************************/
4389 :
4390 194986 : int GTiffDataset::SetDirectory( toff_t nNewOffset )
4391 :
4392 : {
4393 194986 : Crystalize();
4394 :
4395 194986 : FlushBlockBuf();
4396 :
4397 194986 : if( nNewOffset == 0 )
4398 191130 : nNewOffset = nDirOffset;
4399 :
4400 194986 : if( TIFFCurrentDirOffset(hTIFF) == nNewOffset )
4401 : {
4402 193902 : CPLAssert( *ppoActiveDSRef == this || *ppoActiveDSRef == NULL );
4403 193902 : *ppoActiveDSRef = this;
4404 193902 : return TRUE;
4405 : }
4406 :
4407 1084 : int jquality = -1, zquality = -1;
4408 :
4409 1084 : if( GetAccess() == GA_Update )
4410 : {
4411 766 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
4412 766 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
4413 :
4414 766 : if( *ppoActiveDSRef != NULL )
4415 691 : (*ppoActiveDSRef)->FlushDirectory();
4416 : }
4417 :
4418 1084 : if( nNewOffset == 0)
4419 0 : return TRUE;
4420 :
4421 1084 : (*ppoActiveDSRef) = this;
4422 :
4423 1084 : int nSetDirResult = TIFFSetSubDirectory( hTIFF, nNewOffset );
4424 1084 : if (!nSetDirResult)
4425 0 : return nSetDirResult;
4426 :
4427 : /* -------------------------------------------------------------------- */
4428 : /* YCbCr JPEG compressed images should be translated on the fly */
4429 : /* to RGB by libtiff/libjpeg unless specifically requested */
4430 : /* otherwise. */
4431 : /* -------------------------------------------------------------------- */
4432 1084 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
4433 0 : nCompression = COMPRESSION_NONE;
4434 :
4435 1084 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
4436 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
4437 :
4438 1084 : if( nCompression == COMPRESSION_JPEG
4439 : && nPhotometric == PHOTOMETRIC_YCBCR
4440 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
4441 : "YES") ) )
4442 : {
4443 : int nColorMode;
4444 :
4445 18 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
4446 18 : if( nColorMode != JPEGCOLORMODE_RGB )
4447 18 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4448 : }
4449 :
4450 : /* -------------------------------------------------------------------- */
4451 : /* Propogate any quality settings. */
4452 : /* -------------------------------------------------------------------- */
4453 1084 : if( GetAccess() == GA_Update )
4454 : {
4455 : // Now, reset zip and jpeg quality.
4456 766 : if(jquality > 0)
4457 : {
4458 : CPLDebug( "GTiff", "Propgate JPEG_QUALITY(%d) in SetDirectory()",
4459 4 : jquality );
4460 4 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
4461 : }
4462 766 : if(zquality > 0)
4463 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
4464 : }
4465 :
4466 1084 : return nSetDirResult;
4467 : }
4468 :
4469 : /************************************************************************/
4470 : /* Identify() */
4471 : /************************************************************************/
4472 :
4473 15799 : int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
4474 :
4475 : {
4476 15799 : const char *pszFilename = poOpenInfo->pszFilename;
4477 15799 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4478 : {
4479 162 : pszFilename += strlen("GTIFF_RAW:");
4480 162 : GDALOpenInfo oOpenInfo( pszFilename, poOpenInfo->eAccess );
4481 162 : return Identify(&oOpenInfo);
4482 : }
4483 :
4484 : /* -------------------------------------------------------------------- */
4485 : /* We have a special hook for handling opening a specific */
4486 : /* directory of a TIFF file. */
4487 : /* -------------------------------------------------------------------- */
4488 15637 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4489 4 : return TRUE;
4490 :
4491 : /* -------------------------------------------------------------------- */
4492 : /* First we check to see if the file has the expected header */
4493 : /* bytes. */
4494 : /* -------------------------------------------------------------------- */
4495 15633 : if( poOpenInfo->nHeaderBytes < 2 )
4496 9690 : return FALSE;
4497 :
4498 5943 : if( (poOpenInfo->pabyHeader[0] != 'I' || poOpenInfo->pabyHeader[1] != 'I')
4499 : && (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
4500 2425 : return FALSE;
4501 :
4502 : #ifndef BIGTIFF_SUPPORT
4503 : if( (poOpenInfo->pabyHeader[2] == 0x2B && poOpenInfo->pabyHeader[3] == 0) ||
4504 : (poOpenInfo->pabyHeader[2] == 0 && poOpenInfo->pabyHeader[3] == 0x2B) )
4505 : {
4506 : CPLError( CE_Failure, CPLE_OpenFailed,
4507 : "This is a BigTIFF file. BigTIFF is not supported by this\n"
4508 : "version of GDAL and libtiff." );
4509 : return FALSE;
4510 : }
4511 : #endif
4512 :
4513 3518 : if( (poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0)
4514 : && (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0)
4515 : && (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0)
4516 : && (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
4517 0 : return FALSE;
4518 :
4519 3518 : return TRUE;
4520 : }
4521 :
4522 : /************************************************************************/
4523 : /* Open() */
4524 : /************************************************************************/
4525 :
4526 7277 : GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
4527 :
4528 : {
4529 : TIFF *hTIFF;
4530 7277 : int bAllowRGBAInterface = TRUE;
4531 7277 : const char *pszFilename = poOpenInfo->pszFilename;
4532 :
4533 : /* -------------------------------------------------------------------- */
4534 : /* Check if it looks like a TIFF file. */
4535 : /* -------------------------------------------------------------------- */
4536 7277 : if (!Identify(poOpenInfo))
4537 3785 : return NULL;
4538 :
4539 3492 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4540 : {
4541 162 : bAllowRGBAInterface = FALSE;
4542 162 : pszFilename += strlen("GTIFF_RAW:");
4543 : }
4544 :
4545 : /* -------------------------------------------------------------------- */
4546 : /* We have a special hook for handling opening a specific */
4547 : /* directory of a TIFF file. */
4548 : /* -------------------------------------------------------------------- */
4549 3492 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4550 4 : return OpenDir( poOpenInfo );
4551 :
4552 3488 : GTiffOneTimeInit();
4553 :
4554 : /* -------------------------------------------------------------------- */
4555 : /* Try opening the dataset. */
4556 : /* -------------------------------------------------------------------- */
4557 3488 : if( poOpenInfo->eAccess == GA_ReadOnly )
4558 3124 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
4559 : else
4560 364 : hTIFF = VSI_TIFFOpen( pszFilename, "r+" );
4561 :
4562 3488 : if( hTIFF == NULL )
4563 0 : return( NULL );
4564 :
4565 : /* -------------------------------------------------------------------- */
4566 : /* Create a corresponding GDALDataset. */
4567 : /* -------------------------------------------------------------------- */
4568 : GTiffDataset *poDS;
4569 :
4570 3488 : poDS = new GTiffDataset();
4571 3488 : poDS->SetDescription( pszFilename );
4572 6976 : poDS->osFilename = pszFilename;
4573 3488 : poDS->poActiveDS = poDS;
4574 :
4575 3488 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
4576 : TIFFCurrentDirOffset(hTIFF), TRUE,
4577 : poOpenInfo->eAccess,
4578 : bAllowRGBAInterface, TRUE,
4579 : poOpenInfo->papszSiblingFiles) != CE_None )
4580 : {
4581 0 : delete poDS;
4582 0 : return NULL;
4583 : }
4584 :
4585 : /* -------------------------------------------------------------------- */
4586 : /* Initialize any PAM information. */
4587 : /* -------------------------------------------------------------------- */
4588 3488 : poDS->TryLoadXML();
4589 3488 : poDS->ApplyPamInfo();
4590 :
4591 : int i;
4592 270010 : for(i=1;i<=poDS->nBands;i++)
4593 : {
4594 266522 : GTiffRasterBand* poBand = (GTiffRasterBand*) poDS->GetRasterBand(i);
4595 :
4596 : /* Load scale, offset and unittype from PAM if available */
4597 266522 : if (!poBand->bHaveOffsetScale)
4598 : {
4599 266516 : poBand->dfScale = poBand->GDALPamRasterBand::GetScale(&poBand->bHaveOffsetScale);
4600 266516 : poBand->dfOffset = poBand->GDALPamRasterBand::GetOffset();
4601 : }
4602 266522 : if (poBand->osUnitType.size() == 0)
4603 : {
4604 266509 : const char* pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
4605 266509 : if (pszUnitType)
4606 266509 : poBand->osUnitType = pszUnitType;
4607 : }
4608 : }
4609 :
4610 3488 : poDS->bMetadataChanged = FALSE;
4611 3488 : poDS->bGeoTIFFInfoChanged = FALSE;
4612 :
4613 : /* -------------------------------------------------------------------- */
4614 : /* Check for external overviews. */
4615 : /* -------------------------------------------------------------------- */
4616 3488 : poDS->oOvManager.Initialize( poDS, pszFilename );
4617 :
4618 3488 : return poDS;
4619 : }
4620 :
4621 : /************************************************************************/
4622 : /* LookForProjection() */
4623 : /************************************************************************/
4624 :
4625 4618 : void GTiffDataset::LookForProjection()
4626 :
4627 : {
4628 4618 : if( bLookedForProjection )
4629 3610 : return;
4630 :
4631 1008 : bLookedForProjection = TRUE;
4632 1008 : if (!SetDirectory())
4633 0 : return;
4634 :
4635 : /* -------------------------------------------------------------------- */
4636 : /* Capture the GeoTIFF projection, if available. */
4637 : /* -------------------------------------------------------------------- */
4638 : GTIF *hGTIF;
4639 : GTIFDefn sGTIFDefn;
4640 :
4641 1008 : CPLFree( pszProjection );
4642 1008 : pszProjection = NULL;
4643 :
4644 1008 : hGTIF = GTIFNew(hTIFF);
4645 :
4646 1008 : if ( !hGTIF )
4647 : {
4648 : CPLError( CE_Warning, CPLE_AppDefined,
4649 0 : "GeoTIFF tags apparently corrupt, they are being ignored." );
4650 : }
4651 : else
4652 : {
4653 1008 : if( GTIFGetDefn( hGTIF, &sGTIFDefn ) )
4654 : {
4655 975 : pszProjection = GTIFGetOGISDefn( hGTIF, &sGTIFDefn );
4656 :
4657 : // Should we simplify away vertical CS stuff?
4658 975 : if( EQUALN(pszProjection,"COMPD_CS",8)
4659 : && !CSLTestBoolean( CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
4660 : "NO") ) )
4661 : {
4662 0 : OGRSpatialReference oSRS;
4663 :
4664 0 : CPLDebug( "GTiff", "Got COMPD_CS, but stripping it." );
4665 0 : char *pszWKT = pszProjection;
4666 0 : oSRS.importFromWkt( &pszWKT );
4667 0 : CPLFree( pszProjection );
4668 :
4669 0 : oSRS.StripVertical();
4670 0 : oSRS.exportToWkt( &pszProjection );
4671 : }
4672 : }
4673 :
4674 : // Is this a pixel-is-point dataset?
4675 : short nRasterType;
4676 :
4677 1008 : if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
4678 : 0, 1 ) == 1 )
4679 : {
4680 974 : if( nRasterType == (short) RasterPixelIsPoint )
4681 13 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
4682 : else
4683 961 : oGTiffMDMD.SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
4684 : }
4685 :
4686 1008 : GTIFFree( hGTIF );
4687 : }
4688 :
4689 1008 : if( pszProjection == NULL )
4690 : {
4691 33 : pszProjection = CPLStrdup( "" );
4692 : }
4693 :
4694 1008 : bGeoTIFFInfoChanged = FALSE;
4695 : }
4696 :
4697 : /************************************************************************/
4698 : /* ApplyPamInfo() */
4699 : /* */
4700 : /* PAM Information, if available, overrides the GeoTIFF */
4701 : /* geotransform and projection definition. Check for them */
4702 : /* now. */
4703 : /************************************************************************/
4704 :
4705 3488 : void GTiffDataset::ApplyPamInfo()
4706 :
4707 : {
4708 : double adfPamGeoTransform[6];
4709 :
4710 3488 : if( GDALPamDataset::GetGeoTransform( adfPamGeoTransform ) == CE_None
4711 : && (adfPamGeoTransform[0] != 0.0 || adfPamGeoTransform[1] != 1.0
4712 : || adfPamGeoTransform[2] != 0.0 || adfPamGeoTransform[3] != 0.0
4713 : || adfPamGeoTransform[4] != 0.0 || adfPamGeoTransform[5] != 1.0 ))
4714 : {
4715 0 : memcpy( adfGeoTransform, adfPamGeoTransform, sizeof(double)*6 );
4716 0 : bGeoTransformValid = TRUE;
4717 : }
4718 :
4719 3488 : const char *pszPamSRS = GDALPamDataset::GetProjectionRef();
4720 :
4721 3488 : if( pszPamSRS != NULL && strlen(pszPamSRS) > 0 )
4722 : {
4723 0 : CPLFree( pszProjection );
4724 0 : pszProjection = CPLStrdup( pszPamSRS );
4725 0 : bLookedForProjection = TRUE;
4726 : }
4727 :
4728 3488 : int nPamGCPCount = GDALPamDataset::GetGCPCount();
4729 3488 : if( nPamGCPCount > 0 )
4730 : {
4731 2 : if( nGCPCount > 0 )
4732 : {
4733 0 : GDALDeinitGCPs( nGCPCount, pasGCPList );
4734 0 : CPLFree( pasGCPList );
4735 0 : pasGCPList = NULL;
4736 : }
4737 :
4738 2 : nGCPCount = nPamGCPCount;
4739 2 : pasGCPList = GDALDuplicateGCPs(nGCPCount, GDALPamDataset::GetGCPs());
4740 :
4741 2 : CPLFree( pszProjection );
4742 2 : pszProjection = NULL;
4743 :
4744 2 : const char *pszPamGCPProjection = GDALPamDataset::GetGCPProjection();
4745 2 : if( pszPamGCPProjection != NULL && strlen(pszPamGCPProjection) > 0 )
4746 2 : pszProjection = CPLStrdup(pszPamGCPProjection);
4747 :
4748 2 : bLookedForProjection = TRUE;
4749 : }
4750 :
4751 : /* -------------------------------------------------------------------- */
4752 : /* Copy any PAM metadata into our GeoTIFF context, but with the */
4753 : /* GeoTIFF context overriding the PAM info. */
4754 : /* -------------------------------------------------------------------- */
4755 3488 : char **papszPamDomains = oMDMD.GetDomainList();
4756 :
4757 3496 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
4758 : {
4759 8 : const char *pszDomain = papszPamDomains[iDomain];
4760 8 : char **papszGT_MD = oGTiffMDMD.GetMetadata( pszDomain );
4761 8 : char **papszPAM_MD = CSLDuplicate(oMDMD.GetMetadata( pszDomain ));
4762 :
4763 8 : papszPAM_MD = CSLMerge( papszPAM_MD, papszGT_MD );
4764 :
4765 8 : oGTiffMDMD.SetMetadata( papszPAM_MD, pszDomain );
4766 8 : CSLDestroy( papszPAM_MD );
4767 : }
4768 :
4769 270010 : for( int i = 1; i <= GetRasterCount(); i++)
4770 : {
4771 266522 : GTiffRasterBand* poBand = (GTiffRasterBand *)GetRasterBand(i);
4772 266522 : papszPamDomains = poBand->oMDMD.GetDomainList();
4773 :
4774 266548 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
4775 : {
4776 26 : const char *pszDomain = papszPamDomains[iDomain];
4777 26 : char **papszGT_MD = poBand->oGTiffMDMD.GetMetadata( pszDomain );
4778 26 : char **papszPAM_MD = CSLDuplicate(poBand->oMDMD.GetMetadata( pszDomain ));
4779 :
4780 26 : papszPAM_MD = CSLMerge( papszPAM_MD, papszGT_MD );
4781 :
4782 26 : poBand->oGTiffMDMD.SetMetadata( papszPAM_MD, pszDomain );
4783 26 : CSLDestroy( papszPAM_MD );
4784 : }
4785 : }
4786 3488 : }
4787 :
4788 : /************************************************************************/
4789 : /* OpenDir() */
4790 : /* */
4791 : /* Open a specific directory as encoded into a filename. */
4792 : /************************************************************************/
4793 :
4794 4 : GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
4795 :
4796 : {
4797 4 : int bAllowRGBAInterface = TRUE;
4798 4 : const char* pszFilename = poOpenInfo->pszFilename;
4799 4 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4800 : {
4801 0 : bAllowRGBAInterface = FALSE;
4802 0 : pszFilename += strlen("GTIFF_RAW:");
4803 : }
4804 :
4805 4 : if( !EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4806 0 : return NULL;
4807 :
4808 : /* -------------------------------------------------------------------- */
4809 : /* Split out filename, and dir#/offset. */
4810 : /* -------------------------------------------------------------------- */
4811 4 : pszFilename += strlen("GTIFF_DIR:");
4812 4 : int bAbsolute = FALSE;
4813 : toff_t nOffset;
4814 :
4815 4 : if( EQUALN(pszFilename,"off:",4) )
4816 : {
4817 1 : bAbsolute = TRUE;
4818 1 : pszFilename += 4;
4819 : }
4820 :
4821 4 : nOffset = atol(pszFilename);
4822 4 : pszFilename += 1;
4823 :
4824 14 : while( *pszFilename != '\0' && pszFilename[-1] != ':' )
4825 6 : pszFilename++;
4826 :
4827 4 : if( *pszFilename == '\0' || nOffset == 0 )
4828 : {
4829 : CPLError( CE_Failure, CPLE_OpenFailed,
4830 : "Unable to extract offset or filename, should take the form\n"
4831 0 : "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename" );
4832 0 : return NULL;
4833 : }
4834 :
4835 : /* -------------------------------------------------------------------- */
4836 : /* Try opening the dataset. */
4837 : /* -------------------------------------------------------------------- */
4838 : TIFF *hTIFF;
4839 :
4840 4 : GTiffOneTimeInit();
4841 :
4842 4 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
4843 4 : if( hTIFF == NULL )
4844 0 : return( NULL );
4845 :
4846 : /* -------------------------------------------------------------------- */
4847 : /* If a directory was requested by index, advance to it now. */
4848 : /* -------------------------------------------------------------------- */
4849 4 : if( !bAbsolute )
4850 : {
4851 7 : while( nOffset > 1 )
4852 : {
4853 1 : if( TIFFReadDirectory( hTIFF ) == 0 )
4854 : {
4855 0 : XTIFFClose( hTIFF );
4856 : CPLError( CE_Failure, CPLE_OpenFailed,
4857 0 : "Requested directory %lu not found.", (long unsigned int)nOffset );
4858 0 : return NULL;
4859 : }
4860 1 : nOffset--;
4861 : }
4862 :
4863 3 : nOffset = TIFFCurrentDirOffset( hTIFF );
4864 : }
4865 :
4866 : /* -------------------------------------------------------------------- */
4867 : /* Create a corresponding GDALDataset. */
4868 : /* -------------------------------------------------------------------- */
4869 : GTiffDataset *poDS;
4870 :
4871 4 : poDS = new GTiffDataset();
4872 4 : poDS->SetDescription( poOpenInfo->pszFilename );
4873 8 : poDS->osFilename = poOpenInfo->pszFilename;
4874 4 : poDS->poActiveDS = poDS;
4875 :
4876 8 : if( !EQUAL(pszFilename,poOpenInfo->pszFilename)
4877 : && !EQUALN(poOpenInfo->pszFilename,"GTIFF_RAW:",10) )
4878 : {
4879 4 : poDS->SetPhysicalFilename( pszFilename );
4880 4 : poDS->SetSubdatasetName( poOpenInfo->pszFilename );
4881 4 : poDS->osFilename = pszFilename;
4882 : }
4883 :
4884 4 : if (poOpenInfo->eAccess == GA_Update)
4885 : {
4886 : CPLError( CE_Warning, CPLE_AppDefined,
4887 0 : "Opening a specific TIFF directory is not supported in update mode. Switching to read-only" );
4888 : }
4889 :
4890 4 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
4891 : nOffset, FALSE, GA_ReadOnly,
4892 : bAllowRGBAInterface, TRUE,
4893 : poOpenInfo->papszSiblingFiles ) != CE_None )
4894 : {
4895 0 : delete poDS;
4896 0 : return NULL;
4897 : }
4898 : else
4899 : {
4900 4 : poDS->bCloseTIFFHandle = TRUE;
4901 4 : return poDS;
4902 : }
4903 : }
4904 :
4905 : /************************************************************************/
4906 : /* OpenOffset() */
4907 : /* */
4908 : /* Initialize the GTiffDataset based on a passed in file */
4909 : /* handle, and directory offset to utilize. This is called for */
4910 : /* full res, and overview pages. */
4911 : /************************************************************************/
4912 :
4913 : CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
4914 : GTiffDataset **ppoActiveDSRef,
4915 : toff_t nDirOffsetIn,
4916 : int bBaseIn, GDALAccess eAccess,
4917 : int bAllowRGBAInterface,
4918 : int bReadGeoTransform,
4919 3856 : char** papszSiblingFiles )
4920 :
4921 : {
4922 : uint32 nXSize, nYSize;
4923 3856 : int bTreatAsBitmap = FALSE;
4924 3856 : int bTreatAsOdd = FALSE;
4925 :
4926 3856 : this->eAccess = eAccess;
4927 :
4928 3856 : hTIFF = hTIFFIn;
4929 3856 : this->ppoActiveDSRef = ppoActiveDSRef;
4930 :
4931 3856 : nDirOffset = nDirOffsetIn;
4932 :
4933 3856 : if (!SetDirectory( nDirOffsetIn ))
4934 0 : return CE_Failure;
4935 :
4936 3856 : bBase = bBaseIn;
4937 :
4938 3856 : this->eAccess = eAccess;
4939 :
4940 : /* -------------------------------------------------------------------- */
4941 : /* Capture some information from the file that is of interest. */
4942 : /* -------------------------------------------------------------------- */
4943 3856 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
4944 3856 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
4945 3856 : nRasterXSize = nXSize;
4946 3856 : nRasterYSize = nYSize;
4947 :
4948 3856 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel ) )
4949 0 : nBands = 1;
4950 : else
4951 3856 : nBands = nSamplesPerPixel;
4952 :
4953 3856 : if( !TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)) )
4954 0 : nBitsPerSample = 1;
4955 :
4956 3856 : if( !TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(nPlanarConfig) ) )
4957 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
4958 :
4959 3856 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
4960 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
4961 :
4962 3856 : if( !TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(nSampleFormat) ) )
4963 10 : nSampleFormat = SAMPLEFORMAT_UINT;
4964 :
4965 3856 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
4966 0 : nCompression = COMPRESSION_NONE;
4967 :
4968 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
4969 3856 : if (nCompression != COMPRESSION_NONE &&
4970 : !TIFFIsCODECConfigured(nCompression))
4971 : {
4972 : CPLError( CE_Failure, CPLE_AppDefined,
4973 0 : "Cannot open TIFF file due to missing codec." );
4974 0 : return CE_Failure;
4975 : }
4976 : #endif
4977 :
4978 : /* -------------------------------------------------------------------- */
4979 : /* YCbCr JPEG compressed images should be translated on the fly */
4980 : /* to RGB by libtiff/libjpeg unless specifically requested */
4981 : /* otherwise. */
4982 : /* -------------------------------------------------------------------- */
4983 3856 : if( nCompression == COMPRESSION_JPEG
4984 : && nPhotometric == PHOTOMETRIC_YCBCR
4985 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
4986 : "YES") ) )
4987 : {
4988 : int nColorMode;
4989 :
4990 51 : SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
4991 51 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
4992 : nColorMode != JPEGCOLORMODE_RGB )
4993 49 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4994 : }
4995 :
4996 : /* -------------------------------------------------------------------- */
4997 : /* Get strip/tile layout. */
4998 : /* -------------------------------------------------------------------- */
4999 3856 : if( TIFFIsTiled(hTIFF) )
5000 : {
5001 637 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(nBlockXSize) );
5002 637 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(nBlockYSize) );
5003 : }
5004 : else
5005 : {
5006 3219 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
5007 : &(nRowsPerStrip) ) )
5008 : {
5009 : CPLError( CE_Warning, CPLE_AppDefined,
5010 0 : "RowsPerStrip not defined ... assuming all one strip." );
5011 0 : nRowsPerStrip = nYSize; /* dummy value */
5012 : }
5013 :
5014 3219 : nBlockXSize = nRasterXSize;
5015 3219 : nBlockYSize = MIN(nRowsPerStrip,nYSize);
5016 : }
5017 :
5018 : nBlocksPerBand =
5019 : ((nYSize + nBlockYSize - 1) / nBlockYSize)
5020 3856 : * ((nXSize + nBlockXSize - 1) / nBlockXSize);
5021 :
5022 : /* -------------------------------------------------------------------- */
5023 : /* Should we handle this using the GTiffBitmapBand? */
5024 : /* -------------------------------------------------------------------- */
5025 3856 : if( nBitsPerSample == 1 && nBands == 1 )
5026 : {
5027 76 : bTreatAsBitmap = TRUE;
5028 :
5029 : // Lets treat large "one row" bitmaps using the scanline api.
5030 76 : if( !TIFFIsTiled(hTIFF)
5031 : && nBlockYSize == nYSize
5032 : && nYSize > 2000
5033 : && bAllowRGBAInterface )
5034 4 : bTreatAsSplitBitmap = TRUE;
5035 : }
5036 :
5037 : /* -------------------------------------------------------------------- */
5038 : /* Should we treat this via the RGBA interface? */
5039 : /* -------------------------------------------------------------------- */
5040 3856 : if( bAllowRGBAInterface &&
5041 : !bTreatAsBitmap && !(nBitsPerSample > 8)
5042 : && (nPhotometric == PHOTOMETRIC_CIELAB ||
5043 : nPhotometric == PHOTOMETRIC_LOGL ||
5044 : nPhotometric == PHOTOMETRIC_LOGLUV ||
5045 : nPhotometric == PHOTOMETRIC_SEPARATED ||
5046 : ( nPhotometric == PHOTOMETRIC_YCBCR
5047 : && nCompression != COMPRESSION_JPEG )) )
5048 : {
5049 : char szMessage[1024];
5050 :
5051 4 : if( TIFFRGBAImageOK( hTIFF, szMessage ) == 1 )
5052 : {
5053 4 : const char* pszSourceColorSpace = NULL;
5054 4 : switch (nPhotometric)
5055 : {
5056 : case PHOTOMETRIC_CIELAB:
5057 1 : pszSourceColorSpace = "CIELAB";
5058 1 : break;
5059 : case PHOTOMETRIC_LOGL:
5060 0 : pszSourceColorSpace = "LOGL";
5061 0 : break;
5062 : case PHOTOMETRIC_LOGLUV:
5063 0 : pszSourceColorSpace = "LOGLUV";
5064 0 : break;
5065 : case PHOTOMETRIC_SEPARATED:
5066 3 : pszSourceColorSpace = "CMYK";
5067 3 : break;
5068 : case PHOTOMETRIC_YCBCR:
5069 0 : pszSourceColorSpace = "YCbCr";
5070 : break;
5071 : }
5072 4 : if (pszSourceColorSpace)
5073 4 : SetMetadataItem( "SOURCE_COLOR_SPACE", pszSourceColorSpace, "IMAGE_STRUCTURE" );
5074 4 : bTreatAsRGBA = TRUE;
5075 4 : nBands = 4;
5076 : }
5077 : else
5078 : {
5079 0 : CPLDebug( "GTiff", "TIFFRGBAImageOK says:\n%s", szMessage );
5080 : }
5081 : }
5082 :
5083 : /* -------------------------------------------------------------------- */
5084 : /* Should we treat this via the split interface? */
5085 : /* -------------------------------------------------------------------- */
5086 3856 : if( !TIFFIsTiled(hTIFF)
5087 : && nBitsPerSample == 8
5088 : && nBlockYSize == nYSize
5089 : && nYSize > 2000
5090 : && !bTreatAsRGBA
5091 : && CSLTestBoolean(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
5092 : {
5093 : /* libtiff 3.9.2 (20091104) and older, libtiff 4.0.0beta5 (also 20091104) */
5094 : /* and older will crash when trying to open a all-in-one-strip */
5095 : /* YCbCr JPEG compressed TIFF (see #3259). */
5096 : #if (TIFFLIB_VERSION <= 20091104 && !defined(BIGTIFF_SUPPORT)) || \
5097 : (TIFFLIB_VERSION <= 20091104 && defined(BIGTIFF_SUPPORT))
5098 : if (nPhotometric == PHOTOMETRIC_YCBCR &&
5099 : nCompression == COMPRESSION_JPEG)
5100 : {
5101 : CPLDebug("GTiff", "Avoid using split band to open all-in-one-strip "
5102 : "YCbCr JPEG compressed TIFF because of older libtiff");
5103 : }
5104 : else
5105 : #endif
5106 8 : bTreatAsSplit = TRUE;
5107 : }
5108 :
5109 : /* -------------------------------------------------------------------- */
5110 : /* Should we treat this via the odd bits interface? */
5111 : /* -------------------------------------------------------------------- */
5112 3856 : if ( nSampleFormat == SAMPLEFORMAT_IEEEFP )
5113 : {
5114 513 : if ( nBitsPerSample == 16 || nBitsPerSample == 24 )
5115 2 : bTreatAsOdd = TRUE;
5116 : }
5117 3343 : else if ( !bTreatAsRGBA && !bTreatAsBitmap
5118 : && nBitsPerSample != 8
5119 : && nBitsPerSample != 16
5120 : && nBitsPerSample != 32
5121 : && nBitsPerSample != 64
5122 : && nBitsPerSample != 128 )
5123 115 : bTreatAsOdd = TRUE;
5124 :
5125 3856 : int bMinIsWhite = nPhotometric == PHOTOMETRIC_MINISWHITE;
5126 :
5127 : /* -------------------------------------------------------------------- */
5128 : /* Capture the color table if there is one. */
5129 : /* -------------------------------------------------------------------- */
5130 : unsigned short *panRed, *panGreen, *panBlue;
5131 :
5132 3856 : if( bTreatAsRGBA
5133 : || TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
5134 : &panRed, &panGreen, &panBlue) == 0 )
5135 : {
5136 : // Build inverted palette if we have inverted photometric.
5137 : // Pixel values remains unchanged. Avoid doing this for *deep*
5138 : // data types (per #1882)
5139 3777 : if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
5140 : {
5141 : GDALColorEntry oEntry;
5142 : int iColor, nColorCount;
5143 :
5144 7 : poColorTable = new GDALColorTable();
5145 7 : nColorCount = 1 << nBitsPerSample;
5146 :
5147 21 : for ( iColor = 0; iColor < nColorCount; iColor++ )
5148 : {
5149 : oEntry.c1 = oEntry.c2 = oEntry.c3 = (short)
5150 14 : ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
5151 14 : oEntry.c4 = 255;
5152 14 : poColorTable->SetColorEntry( iColor, &oEntry );
5153 : }
5154 :
5155 7 : nPhotometric = PHOTOMETRIC_PALETTE;
5156 : }
5157 : else
5158 3763 : poColorTable = NULL;
5159 : }
5160 : else
5161 : {
5162 86 : int nColorCount, nMaxColor = 0;
5163 : GDALColorEntry oEntry;
5164 :
5165 86 : poColorTable = new GDALColorTable();
5166 :
5167 86 : nColorCount = 1 << nBitsPerSample;
5168 :
5169 345962 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
5170 : {
5171 345876 : oEntry.c1 = panRed[iColor] / 256;
5172 345876 : oEntry.c2 = panGreen[iColor] / 256;
5173 345876 : oEntry.c3 = panBlue[iColor] / 256;
5174 345876 : oEntry.c4 = 255;
5175 :
5176 345876 : poColorTable->SetColorEntry( iColor, &oEntry );
5177 :
5178 345876 : nMaxColor = MAX(nMaxColor,panRed[iColor]);
5179 345876 : nMaxColor = MAX(nMaxColor,panGreen[iColor]);
5180 345876 : nMaxColor = MAX(nMaxColor,panBlue[iColor]);
5181 : }
5182 :
5183 : // Bug 1384 - Some TIFF files are generated with color map entry
5184 : // values in range 0-255 instead of 0-65535 - try to handle these
5185 : // gracefully.
5186 86 : if( nMaxColor > 0 && nMaxColor < 256 )
5187 : {
5188 0 : CPLDebug( "GTiff", "TIFF ColorTable seems to be improperly scaled, fixing up." );
5189 :
5190 0 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
5191 : {
5192 0 : oEntry.c1 = panRed[iColor];
5193 0 : oEntry.c2 = panGreen[iColor];
5194 0 : oEntry.c3 = panBlue[iColor];
5195 0 : oEntry.c4 = 255;
5196 :
5197 0 : poColorTable->SetColorEntry( iColor, &oEntry );
5198 : }
5199 : }
5200 : }
5201 :
5202 : /* -------------------------------------------------------------------- */
5203 : /* Create band information objects. */
5204 : /* -------------------------------------------------------------------- */
5205 271018 : for( int iBand = 0; iBand < nBands; iBand++ )
5206 : {
5207 267162 : if( bTreatAsRGBA )
5208 16 : SetBand( iBand+1, new GTiffRGBABand( this, iBand+1 ) );
5209 267146 : else if( bTreatAsSplitBitmap )
5210 4 : SetBand( iBand+1, new GTiffSplitBitmapBand( this, iBand+1 ) );
5211 267142 : else if( bTreatAsSplit )
5212 24 : SetBand( iBand+1, new GTiffSplitBand( this, iBand+1 ) );
5213 267118 : else if( bTreatAsBitmap )
5214 72 : SetBand( iBand+1, new GTiffBitmapBand( this, iBand+1 ) );
5215 267046 : else if( bTreatAsOdd )
5216 231 : SetBand( iBand+1, new GTiffOddBitsBand( this, iBand+1 ) );
5217 : else
5218 266815 : SetBand( iBand+1, new GTiffRasterBand( this, iBand+1 ) );
5219 : }
5220 :
5221 3856 : if( GetRasterBand(1)->GetRasterDataType() == GDT_Unknown )
5222 : {
5223 : CPLError( CE_Failure, CPLE_NotSupported,
5224 0 : "Unsupported TIFF configuration." );
5225 0 : return CE_Failure;
5226 : }
5227 :
5228 : /* -------------------------------------------------------------------- */
5229 : /* Get the transform or gcps from the GeoTIFF file. */
5230 : /* -------------------------------------------------------------------- */
5231 3856 : if( bReadGeoTransform )
5232 : {
5233 3492 : char *pszTabWKT = NULL;
5234 : double *padfTiePoints, *padfScale, *padfMatrix;
5235 : uint16 nCount;
5236 :
5237 3492 : adfGeoTransform[0] = 0.0;
5238 3492 : adfGeoTransform[1] = 1.0;
5239 3492 : adfGeoTransform[2] = 0.0;
5240 3492 : adfGeoTransform[3] = 0.0;
5241 3492 : adfGeoTransform[4] = 0.0;
5242 3492 : adfGeoTransform[5] = 1.0;
5243 :
5244 3492 : if( TIFFGetField(hTIFF,TIFFTAG_GEOPIXELSCALE,&nCount,&padfScale )
5245 : && nCount >= 2
5246 : && padfScale[0] != 0.0 && padfScale[1] != 0.0 )
5247 : {
5248 2568 : adfGeoTransform[1] = padfScale[0];
5249 2568 : adfGeoTransform[5] = - ABS(padfScale[1]);
5250 :
5251 2568 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
5252 : && nCount >= 6 )
5253 : {
5254 : adfGeoTransform[0] =
5255 2568 : padfTiePoints[3] - padfTiePoints[0] * adfGeoTransform[1];
5256 : adfGeoTransform[3] =
5257 2568 : padfTiePoints[4] - padfTiePoints[1] * adfGeoTransform[5];
5258 :
5259 2568 : bGeoTransformValid = TRUE;
5260 : }
5261 : }
5262 :
5263 924 : else if( TIFFGetField(hTIFF,TIFFTAG_GEOTRANSMATRIX,&nCount,&padfMatrix )
5264 : && nCount == 16 )
5265 : {
5266 8 : adfGeoTransform[0] = padfMatrix[3];
5267 8 : adfGeoTransform[1] = padfMatrix[0];
5268 8 : adfGeoTransform[2] = padfMatrix[1];
5269 8 : adfGeoTransform[3] = padfMatrix[7];
5270 8 : adfGeoTransform[4] = padfMatrix[4];
5271 8 : adfGeoTransform[5] = padfMatrix[5];
5272 8 : bGeoTransformValid = TRUE;
5273 : }
5274 :
5275 : /* -------------------------------------------------------------------- */
5276 : /* Otherwise try looking for a .tfw, .tifw or .wld file. */
5277 : /* -------------------------------------------------------------------- */
5278 : else
5279 : {
5280 : bGeoTransformValid =
5281 916 : GDALReadWorldFile( osFilename, NULL, adfGeoTransform );
5282 :
5283 916 : if( !bGeoTransformValid )
5284 : {
5285 : bGeoTransformValid =
5286 911 : GDALReadWorldFile( osFilename, "wld", adfGeoTransform );
5287 : }
5288 :
5289 916 : if( !bGeoTransformValid )
5290 : {
5291 : int bTabFileOK =
5292 : GDALReadTabFile( osFilename, adfGeoTransform,
5293 906 : &pszTabWKT, &nGCPCount, &pasGCPList );
5294 :
5295 906 : if( bTabFileOK && nGCPCount == 0 )
5296 2 : bGeoTransformValid = TRUE;
5297 : }
5298 : }
5299 :
5300 : /* -------------------------------------------------------------------- */
5301 : /* Check for GCPs. Note, we will allow there to be GCPs and a */
5302 : /* transform in some circumstances. */
5303 : /* -------------------------------------------------------------------- */
5304 3492 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
5305 : && !bGeoTransformValid )
5306 : {
5307 40 : nGCPCount = nCount / 6;
5308 40 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPCount);
5309 :
5310 208 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
5311 : {
5312 : char szID[32];
5313 :
5314 168 : sprintf( szID, "%d", iGCP+1 );
5315 168 : pasGCPList[iGCP].pszId = CPLStrdup( szID );
5316 168 : pasGCPList[iGCP].pszInfo = CPLStrdup("");
5317 168 : pasGCPList[iGCP].dfGCPPixel = padfTiePoints[iGCP*6+0];
5318 168 : pasGCPList[iGCP].dfGCPLine = padfTiePoints[iGCP*6+1];
5319 168 : pasGCPList[iGCP].dfGCPX = padfTiePoints[iGCP*6+3];
5320 168 : pasGCPList[iGCP].dfGCPY = padfTiePoints[iGCP*6+4];
5321 168 : pasGCPList[iGCP].dfGCPZ = padfTiePoints[iGCP*6+5];
5322 : }
5323 : }
5324 :
5325 : /* -------------------------------------------------------------------- */
5326 : /* Did we find a tab file? If so we will use it's coordinate */
5327 : /* system and give it precidence. */
5328 : /* -------------------------------------------------------------------- */
5329 3492 : if( pszTabWKT != NULL
5330 : && (pszProjection == NULL || pszProjection[0] == '\0') )
5331 : {
5332 2 : CPLFree( pszProjection );
5333 2 : pszProjection = pszTabWKT;
5334 2 : pszTabWKT = NULL;
5335 2 : bLookedForProjection = TRUE;
5336 : }
5337 :
5338 3492 : CPLFree( pszTabWKT );
5339 3492 : bGeoTIFFInfoChanged = FALSE;
5340 : }
5341 :
5342 : /* -------------------------------------------------------------------- */
5343 : /* Capture some other potentially interesting information. */
5344 : /* -------------------------------------------------------------------- */
5345 : char *pszText, szWorkMDI[200];
5346 : float fResolution;
5347 : uint16 nShort;
5348 :
5349 3856 : if( TIFFGetField( hTIFF, TIFFTAG_DOCUMENTNAME, &pszText ) )
5350 16 : SetMetadataItem( "TIFFTAG_DOCUMENTNAME", pszText );
5351 :
5352 3856 : if( TIFFGetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, &pszText ) )
5353 2 : SetMetadataItem( "TIFFTAG_IMAGEDESCRIPTION", pszText );
5354 :
5355 3856 : if( TIFFGetField( hTIFF, TIFFTAG_SOFTWARE, &pszText ) )
5356 8 : SetMetadataItem( "TIFFTAG_SOFTWARE", pszText );
5357 :
5358 3856 : if( TIFFGetField( hTIFF, TIFFTAG_DATETIME, &pszText ) )
5359 3 : SetMetadataItem( "TIFFTAG_DATETIME", pszText );
5360 :
5361 3856 : if( TIFFGetField( hTIFF, TIFFTAG_ARTIST, &pszText ) )
5362 2 : SetMetadataItem( "TIFFTAG_ARTIST", pszText );
5363 :
5364 3856 : if( TIFFGetField( hTIFF, TIFFTAG_HOSTCOMPUTER, &pszText ) )
5365 2 : SetMetadataItem( "TIFFTAG_HOSTCOMPUTER", pszText );
5366 :
5367 3856 : if( TIFFGetField( hTIFF, TIFFTAG_COPYRIGHT, &pszText ) )
5368 2 : SetMetadataItem( "TIFFTAG_COPYRIGHT", pszText );
5369 :
5370 3856 : if( TIFFGetField( hTIFF, TIFFTAG_XRESOLUTION, &fResolution ) )
5371 : {
5372 35 : sprintf( szWorkMDI, "%.8g", fResolution );
5373 35 : SetMetadataItem( "TIFFTAG_XRESOLUTION", szWorkMDI );
5374 : }
5375 :
5376 3856 : if( TIFFGetField( hTIFF, TIFFTAG_YRESOLUTION, &fResolution ) )
5377 : {
5378 35 : sprintf( szWorkMDI, "%.8g", fResolution );
5379 35 : SetMetadataItem( "TIFFTAG_YRESOLUTION", szWorkMDI );
5380 : }
5381 :
5382 3856 : if( TIFFGetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, &nShort ) )
5383 : {
5384 0 : sprintf( szWorkMDI, "%d", nShort );
5385 0 : SetMetadataItem( "TIFFTAG_MINSAMPLEVALUE", szWorkMDI );
5386 : }
5387 :
5388 3856 : if( TIFFGetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, &nShort ) )
5389 : {
5390 0 : sprintf( szWorkMDI, "%d", nShort );
5391 0 : SetMetadataItem( "TIFFTAG_MAXSAMPLEVALUE", szWorkMDI );
5392 : }
5393 :
5394 3856 : if( TIFFGetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort ) )
5395 : {
5396 35 : if( nShort == RESUNIT_NONE )
5397 13 : sprintf( szWorkMDI, "%d (unitless)", nShort );
5398 22 : else if( nShort == RESUNIT_INCH )
5399 22 : sprintf( szWorkMDI, "%d (pixels/inch)", nShort );
5400 0 : else if( nShort == RESUNIT_CENTIMETER )
5401 0 : sprintf( szWorkMDI, "%d (pixels/cm)", nShort );
5402 : else
5403 0 : sprintf( szWorkMDI, "%d", nShort );
5404 35 : SetMetadataItem( "TIFFTAG_RESOLUTIONUNIT", szWorkMDI );
5405 : }
5406 :
5407 3856 : if( nCompression == COMPRESSION_NONE )
5408 : /* no compression tag */;
5409 227 : else if( nCompression == COMPRESSION_CCITTRLE )
5410 0 : SetMetadataItem( "COMPRESSION", "CCITTRLE", "IMAGE_STRUCTURE" );
5411 227 : else if( nCompression == COMPRESSION_CCITTFAX3 )
5412 0 : SetMetadataItem( "COMPRESSION", "CCITTFAX3", "IMAGE_STRUCTURE" );
5413 227 : else if( nCompression == COMPRESSION_CCITTFAX4 )
5414 9 : SetMetadataItem( "COMPRESSION", "CCITTFAX4", "IMAGE_STRUCTURE" );
5415 218 : else if( nCompression == COMPRESSION_LZW )
5416 42 : SetMetadataItem( "COMPRESSION", "LZW", "IMAGE_STRUCTURE" );
5417 176 : else if( nCompression == COMPRESSION_OJPEG )
5418 0 : SetMetadataItem( "COMPRESSION", "OJPEG", "IMAGE_STRUCTURE" );
5419 176 : else if( nCompression == COMPRESSION_JPEG )
5420 : {
5421 64 : if ( nPhotometric == PHOTOMETRIC_YCBCR )
5422 51 : SetMetadataItem( "COMPRESSION", "YCbCr JPEG", "IMAGE_STRUCTURE" );
5423 : else
5424 13 : SetMetadataItem( "COMPRESSION", "JPEG", "IMAGE_STRUCTURE" );
5425 : }
5426 112 : else if( nCompression == COMPRESSION_NEXT )
5427 0 : SetMetadataItem( "COMPRESSION", "NEXT", "IMAGE_STRUCTURE" );
5428 112 : else if( nCompression == COMPRESSION_CCITTRLEW )
5429 0 : SetMetadataItem( "COMPRESSION", "CCITTRLEW", "IMAGE_STRUCTURE" );
5430 112 : else if( nCompression == COMPRESSION_PACKBITS )
5431 8 : SetMetadataItem( "COMPRESSION", "PACKBITS", "IMAGE_STRUCTURE" );
5432 104 : else if( nCompression == COMPRESSION_THUNDERSCAN )
5433 0 : SetMetadataItem( "COMPRESSION", "THUNDERSCAN", "IMAGE_STRUCTURE" );
5434 104 : else if( nCompression == COMPRESSION_PIXARFILM )
5435 0 : SetMetadataItem( "COMPRESSION", "PIXARFILM", "IMAGE_STRUCTURE" );
5436 104 : else if( nCompression == COMPRESSION_PIXARLOG )
5437 0 : SetMetadataItem( "COMPRESSION", "PIXARLOG", "IMAGE_STRUCTURE" );
5438 104 : else if( nCompression == COMPRESSION_DEFLATE )
5439 45 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
5440 59 : else if( nCompression == COMPRESSION_ADOBE_DEFLATE )
5441 59 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
5442 0 : else if( nCompression == COMPRESSION_DCS )
5443 0 : SetMetadataItem( "COMPRESSION", "DCS", "IMAGE_STRUCTURE" );
5444 0 : else if( nCompression == COMPRESSION_JBIG )
5445 0 : SetMetadataItem( "COMPRESSION", "JBIG", "IMAGE_STRUCTURE" );
5446 0 : else if( nCompression == COMPRESSION_SGILOG )
5447 0 : SetMetadataItem( "COMPRESSION", "SGILOG", "IMAGE_STRUCTURE" );
5448 0 : else if( nCompression == COMPRESSION_SGILOG24 )
5449 0 : SetMetadataItem( "COMPRESSION", "SGILOG24", "IMAGE_STRUCTURE" );
5450 0 : else if( nCompression == COMPRESSION_JP2000 )
5451 0 : SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
5452 : else
5453 : {
5454 0 : CPLString oComp;
5455 : SetMetadataItem( "COMPRESSION",
5456 0 : (const char *) oComp.Printf( "%d", nCompression));
5457 : }
5458 :
5459 4267 : if( nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1 )
5460 411 : SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
5461 : else
5462 3445 : SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
5463 :
5464 3856 : if( (GetRasterBand(1)->GetRasterDataType() == GDT_Byte && nBitsPerSample != 8 ) ||
5465 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 && nBitsPerSample != 16) ||
5466 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 && nBitsPerSample != 32) )
5467 : {
5468 992 : for (int i = 0; i < nBands; ++i)
5469 : GetRasterBand(i+1)->SetMetadataItem( "NBITS",
5470 : CPLString().Printf( "%d", (int)nBitsPerSample ),
5471 305 : "IMAGE_STRUCTURE" );
5472 : }
5473 :
5474 3856 : if( bMinIsWhite )
5475 8 : SetMetadataItem( "MINISWHITE", "YES", "IMAGE_STRUCTURE" );
5476 :
5477 3856 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
5478 : {
5479 195 : CPLXMLNode *psRoot = CPLParseXMLString( pszText );
5480 195 : CPLXMLNode *psItem = NULL;
5481 :
5482 195 : if( psRoot != NULL && psRoot->eType == CXT_Element
5483 : && EQUAL(psRoot->pszValue,"GDALMetadata") )
5484 195 : psItem = psRoot->psChild;
5485 :
5486 893 : for( ; psItem != NULL; psItem = psItem->psNext )
5487 : {
5488 : const char *pszKey, *pszValue, *pszRole, *pszDomain;
5489 : char *pszUnescapedValue;
5490 698 : int nBand, bIsXML = FALSE;
5491 :
5492 698 : if( psItem->eType != CXT_Element
5493 : || !EQUAL(psItem->pszValue,"Item") )
5494 0 : continue;
5495 :
5496 698 : pszKey = CPLGetXMLValue( psItem, "name", NULL );
5497 698 : pszValue = CPLGetXMLValue( psItem, NULL, NULL );
5498 698 : nBand = atoi(CPLGetXMLValue( psItem, "sample", "-1" )) + 1;
5499 698 : pszRole = CPLGetXMLValue( psItem, "role", "" );
5500 698 : pszDomain = CPLGetXMLValue( psItem, "domain", "" );
5501 :
5502 698 : if( pszKey == NULL || pszValue == NULL )
5503 25 : continue;
5504 :
5505 673 : if( EQUALN(pszDomain,"xml:",4) )
5506 2 : bIsXML = TRUE;
5507 :
5508 : pszUnescapedValue = CPLUnescapeString( pszValue, NULL,
5509 673 : CPLES_XML );
5510 673 : if( nBand == 0 )
5511 : {
5512 502 : if( bIsXML )
5513 : {
5514 2 : char *apszMD[2] = { pszUnescapedValue, NULL };
5515 2 : SetMetadata( apszMD, pszDomain );
5516 : }
5517 : else
5518 500 : SetMetadataItem( pszKey, pszUnescapedValue, pszDomain );
5519 : }
5520 : else
5521 : {
5522 171 : GDALRasterBand *poBand = GetRasterBand(nBand);
5523 171 : if( poBand != NULL )
5524 : {
5525 171 : if( EQUAL(pszRole,"scale") )
5526 6 : poBand->SetScale( CPLAtofM(pszUnescapedValue) );
5527 165 : else if( EQUAL(pszRole,"offset") )
5528 6 : poBand->SetOffset( CPLAtofM(pszUnescapedValue) );
5529 159 : else if( EQUAL(pszRole,"unittype") )
5530 13 : poBand->SetUnitType( pszUnescapedValue );
5531 : else
5532 : {
5533 146 : if( bIsXML )
5534 : {
5535 0 : char *apszMD[2] = { pszUnescapedValue, NULL };
5536 0 : poBand->SetMetadata( apszMD, pszDomain );
5537 : }
5538 : else
5539 : poBand->SetMetadataItem(pszKey,pszUnescapedValue,
5540 146 : pszDomain );
5541 : }
5542 : }
5543 : }
5544 673 : CPLFree( pszUnescapedValue );
5545 : }
5546 :
5547 195 : CPLDestroyXMLNode( psRoot );
5548 : }
5549 :
5550 3856 : bMetadataChanged = FALSE;
5551 :
5552 : /* -------------------------------------------------------------------- */
5553 : /* Check for RPC metadata in an RPB or _rpc.txt file. */
5554 : /* -------------------------------------------------------------------- */
5555 3856 : if( bBaseIn )
5556 : {
5557 3488 : char **papszRPCMD = NULL;
5558 : /* Read Digital Globe .RPB file */
5559 3488 : if (FindRPBFile(papszSiblingFiles))
5560 3 : papszRPCMD = GDALLoadRPBFile( osRPBFile.c_str(), NULL );
5561 : /* Read GeoEye _rpc.txt file */
5562 3488 : if(papszRPCMD == NULL && FindRPCFile(papszSiblingFiles))
5563 0 : papszRPCMD = GDALLoadRPCFile( osRPCFile.c_str(), NULL );
5564 :
5565 3488 : if( papszRPCMD != NULL )
5566 : {
5567 3 : oGTiffMDMD.SetMetadata( papszRPCMD, "RPC" );
5568 3 : CSLDestroy( papszRPCMD );
5569 3 : bMetadataChanged = FALSE;
5570 : }
5571 : else
5572 3485 : ReadRPCTag();
5573 : }
5574 :
5575 : /* -------------------------------------------------------------------- */
5576 : /* Check for RPC metadata in an RPB file. */
5577 : /* -------------------------------------------------------------------- */
5578 3856 : if( bBaseIn && FindIMDFile(papszSiblingFiles) )
5579 : {
5580 6 : char **papszIMDMD = GDALLoadIMDFile( osIMDFile.c_str(), NULL );
5581 :
5582 6 : if( papszIMDMD != NULL )
5583 : {
5584 6 : oGTiffMDMD.SetMetadata( papszIMDMD, "IMD" );
5585 6 : CSLDestroy( papszIMDMD );
5586 6 : bMetadataChanged = FALSE;
5587 : }
5588 : }
5589 :
5590 : /* -------------------------------------------------------------------- */
5591 : /* Check for NODATA */
5592 : /* -------------------------------------------------------------------- */
5593 3856 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) )
5594 : {
5595 169 : bNoDataSet = TRUE;
5596 169 : dfNoDataValue = CPLAtofM( pszText );
5597 : }
5598 :
5599 : /* -------------------------------------------------------------------- */
5600 : /* If this is a "base" raster, we should scan for any */
5601 : /* associated overviews, internal mask bands and subdatasets. */
5602 : /* -------------------------------------------------------------------- */
5603 3856 : if( bBase )
5604 : {
5605 3488 : char **papszSubdatasets = NULL;
5606 3488 : int iDirIndex = 0;
5607 :
5608 3488 : FlushDirectory();
5609 7357 : while( !TIFFLastDirectory( hTIFF )
5610 : && (iDirIndex == 0 || TIFFReadDirectory( hTIFF ) != 0) )
5611 : {
5612 381 : toff_t nThisDir = TIFFCurrentDirOffset(hTIFF);
5613 381 : uint32 nSubType = 0;
5614 :
5615 381 : *ppoActiveDSRef = NULL; // our directory no longer matches this ds
5616 :
5617 381 : iDirIndex++;
5618 :
5619 381 : if( !TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType) )
5620 103 : nSubType = 0;
5621 :
5622 : /* Embedded overview of the main image */
5623 561 : if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
5624 : (nSubType & FILETYPE_MASK) == 0 &&
5625 : iDirIndex != 1 )
5626 : {
5627 : GTiffDataset *poODS;
5628 :
5629 180 : poODS = new GTiffDataset();
5630 360 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
5631 : eAccess ) != CE_None
5632 : || poODS->GetRasterCount() != GetRasterCount() )
5633 : {
5634 0 : delete poODS;
5635 : }
5636 : else
5637 : {
5638 : CPLDebug( "GTiff", "Opened %dx%d overview.\n",
5639 180 : poODS->GetRasterXSize(), poODS->GetRasterYSize());
5640 180 : nOverviewCount++;
5641 : papoOverviewDS = (GTiffDataset **)
5642 : CPLRealloc(papoOverviewDS,
5643 180 : nOverviewCount * (sizeof(void*)));
5644 180 : papoOverviewDS[nOverviewCount-1] = poODS;
5645 180 : poODS->poBaseDS = this;
5646 : }
5647 : }
5648 :
5649 : /* Embedded mask of the main image */
5650 221 : else if ((nSubType & FILETYPE_MASK) != 0 &&
5651 : (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
5652 : poMaskDS == NULL )
5653 : {
5654 20 : poMaskDS = new GTiffDataset();
5655 :
5656 : /* The TIFF6 specification - page 37 - only allows 1 SamplesPerPixel and 1 BitsPerSample
5657 : Here we support either 1 or 8 bit per sample
5658 : and we support either 1 sample per pixel or as many samples as in the main image
5659 : We don't check the value of the PhotometricInterpretation tag, which should be
5660 : set to "Transparency mask" (4) according to the specification (page 36)
5661 : ... But the TIFF6 specification allows image masks to have a higher resolution than
5662 : the main image, what we don't support here
5663 : */
5664 :
5665 40 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir,
5666 : FALSE, eAccess ) != CE_None
5667 : || poMaskDS->GetRasterCount() == 0
5668 : || !(poMaskDS->GetRasterCount() == 1 || poMaskDS->GetRasterCount() == GetRasterCount())
5669 : || poMaskDS->GetRasterXSize() != GetRasterXSize()
5670 : || poMaskDS->GetRasterYSize() != GetRasterYSize()
5671 : || poMaskDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
5672 : {
5673 0 : delete poMaskDS;
5674 0 : poMaskDS = NULL;
5675 : }
5676 : else
5677 : {
5678 20 : CPLDebug( "GTiff", "Opened band mask.\n");
5679 20 : poMaskDS->poBaseDS = this;
5680 : }
5681 : }
5682 :
5683 : /* Embedded mask of an overview */
5684 : /* The TIFF6 specification allows the combination of the FILETYPE_xxxx masks */
5685 181 : else if (nSubType & (FILETYPE_REDUCEDIMAGE | FILETYPE_MASK))
5686 : {
5687 78 : GTiffDataset* poDS = new GTiffDataset();
5688 156 : if( poDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
5689 : eAccess ) != CE_None
5690 : || poDS->GetRasterCount() == 0
5691 : || poDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
5692 : {
5693 21 : delete poDS;
5694 : }
5695 : else
5696 : {
5697 : int i;
5698 68 : for(i=0;i<nOverviewCount;i++)
5699 : {
5700 35 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS == NULL &&
5701 : poDS->GetRasterXSize() == papoOverviewDS[i]->GetRasterXSize() &&
5702 : poDS->GetRasterYSize() == papoOverviewDS[i]->GetRasterYSize() &&
5703 : (poDS->GetRasterCount() == 1 || poDS->GetRasterCount() == GetRasterCount()))
5704 : {
5705 : CPLDebug( "GTiff", "Opened band mask for %dx%d overview.\n",
5706 24 : poDS->GetRasterXSize(), poDS->GetRasterYSize());
5707 24 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS = poDS;
5708 24 : poDS->poBaseDS = this;
5709 24 : break;
5710 : }
5711 : }
5712 57 : if (i == nOverviewCount)
5713 : {
5714 33 : delete poDS;
5715 : }
5716 : }
5717 : }
5718 103 : else if( nSubType == 0 ) {
5719 103 : CPLString osName, osDesc;
5720 : uint32 nXSize, nYSize;
5721 : uint16 nSPP;
5722 :
5723 103 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
5724 103 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
5725 103 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP ) )
5726 0 : nSPP = 1;
5727 :
5728 : osName.Printf( "SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
5729 103 : iDirIndex, iDirIndex, osFilename.c_str() );
5730 : osDesc.Printf( "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
5731 : iDirIndex, iDirIndex,
5732 103 : (int)nXSize, (int)nYSize, nSPP );
5733 :
5734 : papszSubdatasets =
5735 103 : CSLAddString( papszSubdatasets, osName );
5736 : papszSubdatasets =
5737 103 : CSLAddString( papszSubdatasets, osDesc );
5738 : }
5739 :
5740 : // Make sure we are stepping from the expected directory regardless
5741 : // of churn done processing the above.
5742 381 : if( TIFFCurrentDirOffset(hTIFF) != nThisDir )
5743 0 : TIFFSetSubDirectory( hTIFF, nThisDir );
5744 381 : *ppoActiveDSRef = NULL;
5745 : }
5746 :
5747 : /* If we have a mask for the main image, loop over the overviews, and if they */
5748 : /* have a mask, let's set this mask as an overview of the main mask... */
5749 3488 : if (poMaskDS != NULL)
5750 : {
5751 : int i;
5752 44 : for(i=0;i<nOverviewCount;i++)
5753 : {
5754 24 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS != NULL)
5755 : {
5756 24 : poMaskDS->nOverviewCount++;
5757 : poMaskDS->papoOverviewDS = (GTiffDataset **)
5758 : CPLRealloc(poMaskDS->papoOverviewDS,
5759 24 : poMaskDS->nOverviewCount * (sizeof(void*)));
5760 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] =
5761 24 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS;
5762 : }
5763 : }
5764 : }
5765 :
5766 : /* -------------------------------------------------------------------- */
5767 : /* Only keep track of subdatasets if we have more than one */
5768 : /* subdataset (pair). */
5769 : /* -------------------------------------------------------------------- */
5770 3488 : if( CSLCount(papszSubdatasets) > 2 )
5771 : {
5772 1 : oGTiffMDMD.SetMetadata( papszSubdatasets, "SUBDATASETS" );
5773 : }
5774 3488 : CSLDestroy( papszSubdatasets );
5775 : }
5776 :
5777 3856 : return( CE_None );
5778 : }
5779 :
5780 941 : static int GTiffGetZLevel(char** papszOptions)
5781 : {
5782 941 : int nZLevel = -1;
5783 941 : const char* pszValue = CSLFetchNameValue( papszOptions, "ZLEVEL" );
5784 941 : if( pszValue != NULL )
5785 : {
5786 0 : nZLevel = atoi( pszValue );
5787 0 : if (!(nZLevel >= 1 && nZLevel <= 9))
5788 : {
5789 : CPLError( CE_Warning, CPLE_IllegalArg,
5790 : "ZLEVEL=%s value not recognised, ignoring.",
5791 0 : pszValue );
5792 0 : nZLevel = -1;
5793 : }
5794 : }
5795 941 : return nZLevel;
5796 : }
5797 :
5798 942 : static int GTiffGetJpegQuality(char** papszOptions)
5799 : {
5800 942 : int nJpegQuality = -1;
5801 942 : const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
5802 942 : if( pszValue != NULL )
5803 : {
5804 4 : nJpegQuality = atoi( pszValue );
5805 4 : if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
5806 : {
5807 : CPLError( CE_Warning, CPLE_IllegalArg,
5808 : "JPEG_QUALITY=%s value not recognised, ignoring.",
5809 0 : pszValue );
5810 0 : nJpegQuality = -1;
5811 : }
5812 : }
5813 942 : return nJpegQuality;
5814 : }
5815 :
5816 : /************************************************************************/
5817 : /* GTiffCreate() */
5818 : /* */
5819 : /* Shared functionality between GTiffDataset::Create() and */
5820 : /* GTiffCreateCopy() for creating TIFF file based on a set of */
5821 : /* options and a configuration. */
5822 : /************************************************************************/
5823 :
5824 : TIFF *GTiffDataset::CreateLL( const char * pszFilename,
5825 : int nXSize, int nYSize, int nBands,
5826 : GDALDataType eType,
5827 938 : char **papszParmList )
5828 :
5829 : {
5830 : TIFF *hTIFF;
5831 938 : int nBlockXSize = 0, nBlockYSize = 0;
5832 938 : int bTiled = FALSE;
5833 938 : uint16 nCompression = COMPRESSION_NONE;
5834 938 : int nPredictor = PREDICTOR_NONE, nJpegQuality = -1, nZLevel = -1;
5835 : uint16 nSampleFormat;
5836 : int nPlanar;
5837 : const char *pszValue;
5838 : const char *pszProfile;
5839 938 : int bCreateBigTIFF = FALSE;
5840 :
5841 938 : GTiffOneTimeInit();
5842 :
5843 : /* -------------------------------------------------------------------- */
5844 : /* Blow on a few errors. */
5845 : /* -------------------------------------------------------------------- */
5846 938 : if( nXSize < 1 || nYSize < 1 || nBands < 1 )
5847 : {
5848 : CPLError( CE_Failure, CPLE_AppDefined,
5849 : "Attempt to create %dx%dx%d TIFF file, but width, height and bands\n"
5850 : "must be positive.",
5851 1 : nXSize, nYSize, nBands );
5852 :
5853 1 : return NULL;
5854 : }
5855 :
5856 937 : if (nBands > 65535)
5857 : {
5858 : CPLError( CE_Failure, CPLE_AppDefined,
5859 : "Attempt to create %dx%dx%d TIFF file, but bands\n"
5860 : "must be lesser or equal to 65535.",
5861 0 : nXSize, nYSize, nBands );
5862 :
5863 0 : return NULL;
5864 : }
5865 :
5866 : /* -------------------------------------------------------------------- */
5867 : /* Setup values based on options. */
5868 : /* -------------------------------------------------------------------- */
5869 937 : pszProfile = CSLFetchNameValue(papszParmList,"PROFILE");
5870 937 : if( pszProfile == NULL )
5871 925 : pszProfile = "GDALGeoTIFF";
5872 :
5873 937 : if( CSLFetchBoolean( papszParmList, "TILED", FALSE ) )
5874 18 : bTiled = TRUE;
5875 :
5876 937 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
5877 937 : if( pszValue != NULL )
5878 10 : nBlockXSize = atoi( pszValue );
5879 :
5880 937 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
5881 937 : if( pszValue != NULL )
5882 14 : nBlockYSize = atoi( pszValue );
5883 :
5884 937 : pszValue = CSLFetchNameValue(papszParmList,"INTERLEAVE");
5885 937 : if( pszValue != NULL )
5886 : {
5887 23 : if( EQUAL( pszValue, "PIXEL" ) )
5888 13 : nPlanar = PLANARCONFIG_CONTIG;
5889 10 : else if( EQUAL( pszValue, "BAND" ) )
5890 10 : nPlanar = PLANARCONFIG_SEPARATE;
5891 : else
5892 : {
5893 : CPLError( CE_Failure, CPLE_AppDefined,
5894 : "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
5895 0 : pszValue );
5896 0 : return NULL;
5897 : }
5898 : }
5899 : else
5900 : {
5901 914 : nPlanar = PLANARCONFIG_CONTIG;
5902 : }
5903 :
5904 937 : pszValue = CSLFetchNameValue( papszParmList, "COMPRESS" );
5905 937 : if( pszValue != NULL )
5906 : {
5907 36 : if( EQUAL( pszValue, "NONE" ) )
5908 1 : nCompression = COMPRESSION_NONE;
5909 35 : else if( EQUAL( pszValue, "JPEG" ) )
5910 7 : nCompression = COMPRESSION_JPEG;
5911 28 : else if( EQUAL( pszValue, "LZW" ) )
5912 15 : nCompression = COMPRESSION_LZW;
5913 13 : else if( EQUAL( pszValue, "PACKBITS" ))
5914 2 : nCompression = COMPRESSION_PACKBITS;
5915 20 : else if( EQUAL( pszValue, "DEFLATE" ) || EQUAL( pszValue, "ZIP" ))
5916 9 : nCompression = COMPRESSION_ADOBE_DEFLATE;
5917 2 : else if( EQUAL( pszValue, "FAX3" )
5918 : || EQUAL( pszValue, "CCITTFAX3" ))
5919 0 : nCompression = COMPRESSION_CCITTFAX3;
5920 4 : else if( EQUAL( pszValue, "FAX4" )
5921 : || EQUAL( pszValue, "CCITTFAX4" ))
5922 2 : nCompression = COMPRESSION_CCITTFAX4;
5923 0 : else if( EQUAL( pszValue, "CCITTRLE" ) )
5924 0 : nCompression = COMPRESSION_CCITTRLE;
5925 : else
5926 : CPLError( CE_Warning, CPLE_IllegalArg,
5927 : "COMPRESS=%s value not recognised, ignoring.",
5928 0 : pszValue );
5929 :
5930 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
5931 36 : if (nCompression != COMPRESSION_NONE &&
5932 : !TIFFIsCODECConfigured(nCompression))
5933 : {
5934 : CPLError( CE_Failure, CPLE_AppDefined,
5935 0 : "Cannot create TIFF file due to missing codec for %s.", pszValue );
5936 0 : return NULL;
5937 : }
5938 : #endif
5939 : }
5940 :
5941 937 : pszValue = CSLFetchNameValue( papszParmList, "PREDICTOR" );
5942 937 : if( pszValue != NULL )
5943 4 : nPredictor = atoi( pszValue );
5944 :
5945 937 : nZLevel = GTiffGetZLevel(papszParmList);
5946 :
5947 937 : nJpegQuality = GTiffGetJpegQuality(papszParmList);
5948 :
5949 : /* -------------------------------------------------------------------- */
5950 : /* Compute the uncompressed size. */
5951 : /* -------------------------------------------------------------------- */
5952 : double dfUncompressedImageSize;
5953 :
5954 : dfUncompressedImageSize =
5955 937 : nXSize * ((double)nYSize) * nBands * (GDALGetDataTypeSize(eType)/8);
5956 :
5957 : if( nCompression == COMPRESSION_NONE
5958 : && dfUncompressedImageSize > 4200000000.0 )
5959 : {
5960 : #ifndef BIGTIFF_SUPPORT
5961 : CPLError( CE_Failure, CPLE_NotSupported,
5962 : "A %d pixels x %d lines x %d bands %s image would be larger than 4GB\n"
5963 : "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
5964 : "Creation failed.",
5965 : nXSize, nYSize, nBands, GDALGetDataTypeName(eType) );
5966 : return NULL;
5967 : #endif
5968 : }
5969 :
5970 : /* -------------------------------------------------------------------- */
5971 : /* Should the file be created as a bigtiff file? */
5972 : /* -------------------------------------------------------------------- */
5973 937 : const char *pszBIGTIFF = CSLFetchNameValue(papszParmList, "BIGTIFF");
5974 :
5975 937 : if( pszBIGTIFF == NULL )
5976 933 : pszBIGTIFF = "IF_NEEDED";
5977 :
5978 937 : if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
5979 : {
5980 934 : if( nCompression == COMPRESSION_NONE
5981 : && dfUncompressedImageSize > 4200000000.0 )
5982 9 : bCreateBigTIFF = TRUE;
5983 : }
5984 3 : else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
5985 : {
5986 1 : if( dfUncompressedImageSize > 2000000000.0 )
5987 1 : bCreateBigTIFF = TRUE;
5988 : }
5989 :
5990 : else
5991 : {
5992 2 : bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
5993 2 : if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE &&
5994 : dfUncompressedImageSize > 4200000000.0 )
5995 : {
5996 : CPLError( CE_Failure, CPLE_NotSupported,
5997 : "The TIFF file will be larger than 4GB, so BigTIFF is necessary.\n"
5998 1 : "Creation failed.");
5999 1 : return NULL;
6000 : }
6001 : }
6002 :
6003 : #ifndef BIGTIFF_SUPPORT
6004 : if( bCreateBigTIFF )
6005 : {
6006 : CPLError( CE_Warning, CPLE_NotSupported,
6007 : "BigTIFF requested, but GDAL built without BigTIFF\n"
6008 : "enabled libtiff, request ignored." );
6009 : bCreateBigTIFF = FALSE;
6010 : }
6011 : #endif
6012 :
6013 936 : if( bCreateBigTIFF )
6014 11 : CPLDebug( "GTiff", "File being created as a BigTIFF." );
6015 :
6016 : /* -------------------------------------------------------------------- */
6017 : /* Check if the user wishes a particular endianness */
6018 : /* -------------------------------------------------------------------- */
6019 :
6020 936 : int eEndianness = ENDIANNESS_NATIVE;
6021 936 : pszValue = CSLFetchNameValue(papszParmList, "ENDIANNESS");
6022 936 : if ( pszValue == NULL )
6023 932 : pszValue = CPLGetConfigOption( "GDAL_TIFF_ENDIANNESS", NULL );
6024 936 : if ( pszValue != NULL )
6025 : {
6026 413 : if (EQUAL(pszValue, "LITTLE"))
6027 4 : eEndianness = ENDIANNESS_LITTLE;
6028 409 : else if (EQUAL(pszValue, "BIG"))
6029 0 : eEndianness = ENDIANNESS_BIG;
6030 409 : else if (EQUAL(pszValue, "INVERTED"))
6031 : {
6032 : #ifdef CPL_LSB
6033 26 : eEndianness = ENDIANNESS_BIG;
6034 : #else
6035 : eEndianness = ENDIANNESS_LITTLE;
6036 : #endif
6037 : }
6038 383 : else if (!EQUAL(pszValue, "NATIVE"))
6039 : {
6040 : CPLError( CE_Warning, CPLE_NotSupported,
6041 0 : "ENDIANNESS=%s not supported. Defaulting to NATIVE", pszValue );
6042 : }
6043 : }
6044 :
6045 : /* -------------------------------------------------------------------- */
6046 : /* Try opening the dataset. */
6047 : /* -------------------------------------------------------------------- */
6048 :
6049 : char szOpeningFlag[5];
6050 936 : strcpy(szOpeningFlag, "w+");
6051 936 : if (bCreateBigTIFF)
6052 11 : strcat(szOpeningFlag, "8");
6053 936 : if (eEndianness == ENDIANNESS_BIG)
6054 26 : strcat(szOpeningFlag, "b");
6055 910 : else if (eEndianness == ENDIANNESS_LITTLE)
6056 4 : strcat(szOpeningFlag, "l");
6057 936 : hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag );
6058 936 : if( hTIFF == NULL )
6059 : {
6060 0 : if( CPLGetLastErrorNo() == 0 )
6061 : CPLError( CE_Failure, CPLE_OpenFailed,
6062 : "Attempt to create new tiff file `%s'\n"
6063 : "failed in XTIFFOpen().\n",
6064 0 : pszFilename );
6065 0 : return NULL;
6066 : }
6067 :
6068 : /* -------------------------------------------------------------------- */
6069 : /* How many bits per sample? We have a special case if NBITS */
6070 : /* specified for GDT_Byte, GDT_UInt16, GDT_UInt32. */
6071 : /* -------------------------------------------------------------------- */
6072 936 : int nBitsPerSample = GDALGetDataTypeSize(eType);
6073 936 : if (CSLFetchNameValue(papszParmList, "NBITS") != NULL)
6074 : {
6075 38 : int nMinBits = 0, nMaxBits = 0;
6076 38 : nBitsPerSample = atoi(CSLFetchNameValue(papszParmList, "NBITS"));
6077 38 : if( eType == GDT_Byte )
6078 : {
6079 13 : nMinBits = 1;
6080 13 : nMaxBits = 8;
6081 : }
6082 25 : else if( eType == GDT_UInt16 )
6083 : {
6084 13 : nMinBits = 9;
6085 13 : nMaxBits = 16;
6086 : }
6087 12 : else if( eType == GDT_UInt32 )
6088 : {
6089 12 : nMinBits = 17;
6090 12 : nMaxBits = 32;
6091 : }
6092 : else
6093 : {
6094 : CPLError(CE_Warning, CPLE_NotSupported,
6095 : "NBITS is not supported for data type %s",
6096 0 : GDALGetDataTypeName(eType));
6097 0 : nBitsPerSample = GDALGetDataTypeSize(eType);
6098 : }
6099 :
6100 38 : if (nMinBits != 0)
6101 : {
6102 38 : if (nBitsPerSample < nMinBits)
6103 : {
6104 : CPLError(CE_Warning, CPLE_AppDefined,
6105 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
6106 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMinBits);
6107 0 : nBitsPerSample = nMinBits;
6108 : }
6109 38 : else if (nBitsPerSample > nMaxBits)
6110 : {
6111 : CPLError(CE_Warning, CPLE_AppDefined,
6112 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
6113 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMaxBits);
6114 0 : nBitsPerSample = nMaxBits;
6115 : }
6116 : }
6117 : }
6118 :
6119 : /* -------------------------------------------------------------------- */
6120 : /* Do we have a custom pixel type (just used for signed byte now). */
6121 : /* -------------------------------------------------------------------- */
6122 936 : const char *pszPixelType = CSLFetchNameValue( papszParmList, "PIXELTYPE" );
6123 936 : if( pszPixelType == NULL )
6124 934 : pszPixelType = "";
6125 :
6126 : /* -------------------------------------------------------------------- */
6127 : /* Setup some standard flags. */
6128 : /* -------------------------------------------------------------------- */
6129 936 : TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
6130 936 : TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
6131 936 : TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerSample );
6132 :
6133 1057 : if( (eType == GDT_Byte && EQUAL(pszPixelType,"SIGNEDBYTE"))
6134 : || eType == GDT_Int16 || eType == GDT_Int32 )
6135 121 : nSampleFormat = SAMPLEFORMAT_INT;
6136 917 : else if( eType == GDT_CInt16 || eType == GDT_CInt32 )
6137 102 : nSampleFormat = SAMPLEFORMAT_COMPLEXINT;
6138 835 : else if( eType == GDT_Float32 || eType == GDT_Float64 )
6139 122 : nSampleFormat = SAMPLEFORMAT_IEEEFP;
6140 698 : else if( eType == GDT_CFloat32 || eType == GDT_CFloat64 )
6141 107 : nSampleFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
6142 : else
6143 484 : nSampleFormat = SAMPLEFORMAT_UINT;
6144 :
6145 936 : TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
6146 936 : TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nBands );
6147 936 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanar );
6148 :
6149 : /* -------------------------------------------------------------------- */
6150 : /* Setup Photometric Interpretation. Take this value from the user */
6151 : /* passed option or guess correct value otherwise. */
6152 : /* -------------------------------------------------------------------- */
6153 936 : int nSamplesAccountedFor = 1;
6154 936 : int bForceColorTable = FALSE;
6155 :
6156 936 : pszValue = CSLFetchNameValue(papszParmList,"PHOTOMETRIC");
6157 936 : if( pszValue != NULL )
6158 : {
6159 15 : if( EQUAL( pszValue, "MINISBLACK" ) )
6160 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6161 15 : else if( EQUAL( pszValue, "MINISWHITE" ) )
6162 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE );
6163 13 : else if( EQUAL( pszValue, "PALETTE" ))
6164 : {
6165 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
6166 3 : nSamplesAccountedFor = 1;
6167 3 : bForceColorTable = TRUE;
6168 : }
6169 10 : else if( EQUAL( pszValue, "RGB" ))
6170 : {
6171 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6172 2 : nSamplesAccountedFor = 3;
6173 : }
6174 8 : else if( EQUAL( pszValue, "CMYK" ))
6175 : {
6176 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED );
6177 2 : nSamplesAccountedFor = 4;
6178 : }
6179 6 : else if( EQUAL( pszValue, "YCBCR" ))
6180 : {
6181 : /* Because of subsampling, setting YCBCR without JPEG compression leads */
6182 : /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
6183 : /* aware of subsampling so that it doesn't overrun buffer size returned */
6184 : /* by libtiff */
6185 6 : if ( nCompression != COMPRESSION_JPEG )
6186 : {
6187 : CPLError(CE_Failure, CPLE_NotSupported,
6188 0 : "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
6189 0 : XTIFFClose(hTIFF);
6190 0 : return NULL;
6191 : }
6192 :
6193 6 : if ( nPlanar == PLANARCONFIG_SEPARATE )
6194 : {
6195 : CPLError(CE_Failure, CPLE_NotSupported,
6196 0 : "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
6197 0 : XTIFFClose(hTIFF);
6198 0 : return NULL;
6199 : }
6200 :
6201 : /* YCBCR strictly requires 3 bands. Not less, not more */
6202 : /* Issue an explicit error message as libtiff one is a bit cryptic : */
6203 : /* TIFFVStripSize64:Invalid td_samplesperpixel value */
6204 6 : if ( nBands != 3 )
6205 : {
6206 : CPLError(CE_Failure, CPLE_NotSupported,
6207 0 : "PHOTOMETRIC=YCBCR requires a source raster with only 3 bands (RGB)");
6208 0 : XTIFFClose(hTIFF);
6209 0 : return NULL;
6210 : }
6211 :
6212 6 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR );
6213 6 : nSamplesAccountedFor = 3;
6214 : }
6215 0 : else if( EQUAL( pszValue, "CIELAB" ))
6216 : {
6217 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
6218 0 : nSamplesAccountedFor = 3;
6219 : }
6220 0 : else if( EQUAL( pszValue, "ICCLAB" ))
6221 : {
6222 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ICCLAB );
6223 0 : nSamplesAccountedFor = 3;
6224 : }
6225 0 : else if( EQUAL( pszValue, "ITULAB" ))
6226 : {
6227 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB );
6228 0 : nSamplesAccountedFor = 3;
6229 : }
6230 : else
6231 : {
6232 : CPLError( CE_Warning, CPLE_IllegalArg,
6233 : "PHOTOMETRIC=%s value not recognised, ignoring.\n"
6234 : "Set the Photometric Interpretation as MINISBLACK.",
6235 0 : pszValue );
6236 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6237 : }
6238 :
6239 15 : if ( nBands < nSamplesAccountedFor )
6240 : {
6241 : CPLError( CE_Warning, CPLE_IllegalArg,
6242 : "PHOTOMETRIC=%s value does not correspond to number "
6243 : "of bands (%d), ignoring.\n"
6244 : "Set the Photometric Interpretation as MINISBLACK.",
6245 0 : pszValue, nBands );
6246 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6247 : }
6248 : }
6249 : else
6250 : {
6251 : /*
6252 : * If image contains 3 or 4 bands and datatype is Byte then we will
6253 : * assume it is RGB. In all other cases assume it is MINISBLACK.
6254 : */
6255 962 : if( nBands == 3 && eType == GDT_Byte )
6256 : {
6257 41 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6258 41 : nSamplesAccountedFor = 3;
6259 : }
6260 900 : else if( nBands == 4 && eType == GDT_Byte )
6261 : {
6262 : uint16 v[1];
6263 :
6264 20 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6265 20 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
6266 20 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6267 20 : nSamplesAccountedFor = 4;
6268 : }
6269 : else
6270 : {
6271 860 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6272 860 : nSamplesAccountedFor = 1;
6273 : }
6274 : }
6275 :
6276 : /* -------------------------------------------------------------------- */
6277 : /* If there are extra samples, we need to mark them with an */
6278 : /* appropriate extrasamples definition here. */
6279 : /* -------------------------------------------------------------------- */
6280 936 : if( nBands > nSamplesAccountedFor )
6281 : {
6282 : uint16 *v;
6283 : int i;
6284 71 : int nExtraSamples = nBands - nSamplesAccountedFor;
6285 :
6286 71 : v = (uint16 *) CPLMalloc( sizeof(uint16) * nExtraSamples );
6287 :
6288 71 : if( CSLFetchBoolean(papszParmList,"ALPHA",FALSE) )
6289 1 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6290 : else
6291 70 : v[0] = EXTRASAMPLE_UNSPECIFIED;
6292 :
6293 131193 : for( i = 1; i < nExtraSamples; i++ )
6294 131122 : v[i] = EXTRASAMPLE_UNSPECIFIED;
6295 :
6296 71 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, v );
6297 :
6298 71 : CPLFree(v);
6299 : }
6300 :
6301 : /* Set the compression method before asking the default strip size */
6302 : /* This is usefull when translating to a JPEG-In-TIFF file where */
6303 : /* the default strip size is 8 or 16 depending on the photometric value */
6304 936 : TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompression );
6305 :
6306 : /* -------------------------------------------------------------------- */
6307 : /* Setup tiling/stripping flags. */
6308 : /* -------------------------------------------------------------------- */
6309 936 : if( bTiled )
6310 : {
6311 18 : if( nBlockXSize == 0 )
6312 8 : nBlockXSize = 256;
6313 :
6314 18 : if( nBlockYSize == 0 )
6315 8 : nBlockYSize = 256;
6316 :
6317 18 : if (!TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ) ||
6318 : !TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ))
6319 : {
6320 0 : XTIFFClose(hTIFF);
6321 0 : return NULL;
6322 : }
6323 : }
6324 : else
6325 : {
6326 : uint32 nRowsPerStrip;
6327 :
6328 918 : if( nBlockYSize == 0 )
6329 914 : nRowsPerStrip = MIN(nYSize, (int)TIFFDefaultStripSize(hTIFF,0));
6330 : else
6331 4 : nRowsPerStrip = nBlockYSize;
6332 :
6333 918 : TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nRowsPerStrip );
6334 : }
6335 :
6336 : /* -------------------------------------------------------------------- */
6337 : /* Set compression related tags. */
6338 : /* -------------------------------------------------------------------- */
6339 936 : if ( nCompression == COMPRESSION_LZW ||
6340 : nCompression == COMPRESSION_ADOBE_DEFLATE )
6341 24 : TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor );
6342 936 : if (nCompression == COMPRESSION_ADOBE_DEFLATE
6343 : && nZLevel != -1)
6344 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
6345 936 : if( nCompression == COMPRESSION_JPEG
6346 : && nJpegQuality != -1 )
6347 2 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
6348 :
6349 : /* -------------------------------------------------------------------- */
6350 : /* If we forced production of a file with photometric=palette, */
6351 : /* we need to push out a default color table. */
6352 : /* -------------------------------------------------------------------- */
6353 936 : if( bForceColorTable )
6354 : {
6355 : int nColors;
6356 :
6357 3 : if( eType == GDT_Byte )
6358 3 : nColors = 256;
6359 : else
6360 0 : nColors = 65536;
6361 :
6362 : unsigned short *panTRed, *panTGreen, *panTBlue;
6363 :
6364 3 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6365 3 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6366 3 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6367 :
6368 771 : for( int iColor = 0; iColor < nColors; iColor++ )
6369 : {
6370 768 : if( eType == GDT_Byte )
6371 : {
6372 768 : panTRed[iColor] = (unsigned short) (257 * iColor);
6373 768 : panTGreen[iColor] = (unsigned short) (257 * iColor);
6374 768 : panTBlue[iColor] = (unsigned short) (257 * iColor);
6375 : }
6376 : else
6377 : {
6378 0 : panTRed[iColor] = (unsigned short) iColor;
6379 0 : panTGreen[iColor] = (unsigned short) iColor;
6380 0 : panTBlue[iColor] = (unsigned short) iColor;
6381 : }
6382 : }
6383 :
6384 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
6385 3 : panTRed, panTGreen, panTBlue );
6386 :
6387 3 : CPLFree( panTRed );
6388 3 : CPLFree( panTGreen );
6389 3 : CPLFree( panTBlue );
6390 : }
6391 :
6392 936 : return( hTIFF );
6393 : }
6394 :
6395 : /************************************************************************/
6396 : /* Create() */
6397 : /* */
6398 : /* Create a new GeoTIFF or TIFF file. */
6399 : /************************************************************************/
6400 :
6401 : GDALDataset *GTiffDataset::Create( const char * pszFilename,
6402 : int nXSize, int nYSize, int nBands,
6403 : GDALDataType eType,
6404 781 : char **papszParmList )
6405 :
6406 : {
6407 : GTiffDataset * poDS;
6408 : TIFF *hTIFF;
6409 :
6410 : /* -------------------------------------------------------------------- */
6411 : /* Create the underlying TIFF file. */
6412 : /* -------------------------------------------------------------------- */
6413 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
6414 781 : eType, papszParmList );
6415 :
6416 781 : if( hTIFF == NULL )
6417 2 : return NULL;
6418 :
6419 : /* -------------------------------------------------------------------- */
6420 : /* Create the new GTiffDataset object. */
6421 : /* -------------------------------------------------------------------- */
6422 779 : poDS = new GTiffDataset();
6423 779 : poDS->hTIFF = hTIFF;
6424 779 : poDS->poActiveDS = poDS;
6425 779 : poDS->ppoActiveDSRef = &(poDS->poActiveDS);
6426 :
6427 779 : poDS->nRasterXSize = nXSize;
6428 779 : poDS->nRasterYSize = nYSize;
6429 779 : poDS->eAccess = GA_Update;
6430 779 : poDS->bCrystalized = FALSE;
6431 779 : poDS->nSamplesPerPixel = (uint16) nBands;
6432 1558 : poDS->osFilename = pszFilename;
6433 :
6434 : /* Avoid premature crystalization that will cause directory re-writting */
6435 : /* if GetProjectionRef() or GetGeoTransform() are called on the newly created GeoTIFF */
6436 779 : poDS->bLookedForProjection = TRUE;
6437 :
6438 779 : TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->nSampleFormat) );
6439 779 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->nPlanarConfig) );
6440 779 : TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) );
6441 779 : TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->nBitsPerSample) );
6442 779 : TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(poDS->nCompression) );
6443 :
6444 779 : if( TIFFIsTiled(hTIFF) )
6445 : {
6446 15 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(poDS->nBlockXSize) );
6447 15 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(poDS->nBlockYSize) );
6448 : }
6449 : else
6450 : {
6451 764 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
6452 : &(poDS->nRowsPerStrip) ) )
6453 0 : poDS->nRowsPerStrip = 1; /* dummy value */
6454 :
6455 764 : poDS->nBlockXSize = nXSize;
6456 764 : poDS->nBlockYSize = MIN((int)poDS->nRowsPerStrip,nYSize);
6457 : }
6458 :
6459 : poDS->nBlocksPerBand =
6460 : ((nYSize + poDS->nBlockYSize - 1) / poDS->nBlockYSize)
6461 779 : * ((nXSize + poDS->nBlockXSize - 1) / poDS->nBlockXSize);
6462 :
6463 779 : if( CSLFetchNameValue( papszParmList, "PROFILE" ) != NULL )
6464 4 : poDS->osProfile = CSLFetchNameValue( papszParmList, "PROFILE" );
6465 :
6466 : /* -------------------------------------------------------------------- */
6467 : /* YCbCr JPEG compressed images should be translated on the fly */
6468 : /* to RGB by libtiff/libjpeg unless specifically requested */
6469 : /* otherwise. */
6470 : /* -------------------------------------------------------------------- */
6471 779 : if( poDS->nCompression == COMPRESSION_JPEG
6472 : && poDS->nPhotometric == PHOTOMETRIC_YCBCR
6473 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
6474 : "YES") ) )
6475 : {
6476 : int nColorMode;
6477 :
6478 1 : poDS->SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
6479 1 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
6480 : nColorMode != JPEGCOLORMODE_RGB )
6481 1 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
6482 : }
6483 :
6484 : /* -------------------------------------------------------------------- */
6485 : /* Read palette back as a color table if it has one. */
6486 : /* -------------------------------------------------------------------- */
6487 : unsigned short *panRed, *panGreen, *panBlue;
6488 :
6489 779 : if( poDS->nPhotometric == PHOTOMETRIC_PALETTE
6490 : && TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
6491 : &panRed, &panGreen, &panBlue) )
6492 : {
6493 : int nColorCount;
6494 : GDALColorEntry oEntry;
6495 :
6496 3 : poDS->poColorTable = new GDALColorTable();
6497 :
6498 3 : nColorCount = 1 << poDS->nBitsPerSample;
6499 :
6500 771 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6501 : {
6502 768 : oEntry.c1 = panRed[iColor] / 256;
6503 768 : oEntry.c2 = panGreen[iColor] / 256;
6504 768 : oEntry.c3 = panBlue[iColor] / 256;
6505 768 : oEntry.c4 = 255;
6506 :
6507 768 : poDS->poColorTable->SetColorEntry( iColor, &oEntry );
6508 : }
6509 : }
6510 :
6511 : /* -------------------------------------------------------------------- */
6512 : /* Do we want to ensure all blocks get written out on close to */
6513 : /* avoid sparse files? */
6514 : /* -------------------------------------------------------------------- */
6515 779 : if( !CSLFetchBoolean( papszParmList, "SPARSE_OK", FALSE ) )
6516 764 : poDS->bFillEmptyTiles = TRUE;
6517 :
6518 : /* -------------------------------------------------------------------- */
6519 : /* Preserve creation options for consulting later (for instance */
6520 : /* to decide if a TFW file should be written). */
6521 : /* -------------------------------------------------------------------- */
6522 779 : poDS->papszCreationOptions = CSLDuplicate( papszParmList );
6523 :
6524 : /* -------------------------------------------------------------------- */
6525 : /* Create band information objects. */
6526 : /* -------------------------------------------------------------------- */
6527 : int iBand;
6528 :
6529 132821 : for( iBand = 0; iBand < nBands; iBand++ )
6530 : {
6531 264061 : if( poDS->nBitsPerSample == 8 ||
6532 : poDS->nBitsPerSample == 16 ||
6533 : poDS->nBitsPerSample == 32 ||
6534 : poDS->nBitsPerSample == 64 ||
6535 : poDS->nBitsPerSample == 128)
6536 132019 : poDS->SetBand( iBand+1, new GTiffRasterBand( poDS, iBand+1 ) );
6537 : else
6538 : {
6539 23 : poDS->SetBand( iBand+1, new GTiffOddBitsBand( poDS, iBand+1 ) );
6540 : poDS->GetRasterBand( iBand+1 )->
6541 : SetMetadataItem( "NBITS",
6542 : CPLString().Printf("%d",poDS->nBitsPerSample),
6543 46 : "IMAGE_STRUCTURE" );
6544 : }
6545 : }
6546 :
6547 779 : poDS->oOvManager.Initialize( poDS, pszFilename );
6548 :
6549 779 : return( poDS );
6550 : }
6551 :
6552 : /************************************************************************/
6553 : /* CreateCopy() */
6554 : /************************************************************************/
6555 :
6556 : GDALDataset *
6557 : GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
6558 : int bStrict, char ** papszOptions,
6559 158 : GDALProgressFunc pfnProgress, void * pProgressData )
6560 :
6561 : {
6562 : TIFF *hTIFF;
6563 158 : int nXSize = poSrcDS->GetRasterXSize();
6564 158 : int nYSize = poSrcDS->GetRasterYSize();
6565 158 : int nBands = poSrcDS->GetRasterCount();
6566 : int iBand;
6567 158 : CPLErr eErr = CE_None;
6568 : uint16 nPlanarConfig;
6569 : uint16 nBitsPerSample;
6570 : GDALRasterBand *poPBand;
6571 :
6572 158 : if( poSrcDS->GetRasterCount() == 0 )
6573 : {
6574 : CPLError( CE_Failure, CPLE_AppDefined,
6575 1 : "Unable to export GeoTIFF files with zero bands." );
6576 1 : return NULL;
6577 : }
6578 :
6579 157 : poPBand = poSrcDS->GetRasterBand(1);
6580 157 : GDALDataType eType = poPBand->GetRasterDataType();
6581 :
6582 : /* -------------------------------------------------------------------- */
6583 : /* Check, whether all bands in input dataset has the same type. */
6584 : /* -------------------------------------------------------------------- */
6585 251 : for ( iBand = 2; iBand <= nBands; iBand++ )
6586 : {
6587 94 : if ( eType != poSrcDS->GetRasterBand(iBand)->GetRasterDataType() )
6588 : {
6589 0 : if ( bStrict )
6590 : {
6591 : CPLError( CE_Failure, CPLE_AppDefined,
6592 : "Unable to export GeoTIFF file with different datatypes per\n"
6593 0 : "different bands. All bands should have the same types in TIFF." );
6594 0 : return NULL;
6595 : }
6596 : else
6597 : {
6598 : CPLError( CE_Warning, CPLE_AppDefined,
6599 : "Unable to export GeoTIFF file with different datatypes per\n"
6600 0 : "different bands. All bands should have the same types in TIFF." );
6601 : }
6602 : }
6603 : }
6604 :
6605 157 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
6606 0 : return NULL;
6607 :
6608 : /* -------------------------------------------------------------------- */
6609 : /* Capture the profile. */
6610 : /* -------------------------------------------------------------------- */
6611 : const char *pszProfile;
6612 : int bGeoTIFF;
6613 :
6614 157 : pszProfile = CSLFetchNameValue(papszOptions,"PROFILE");
6615 157 : if( pszProfile == NULL )
6616 149 : pszProfile = "GDALGeoTIFF";
6617 :
6618 157 : if( !EQUAL(pszProfile,"BASELINE")
6619 : && !EQUAL(pszProfile,"GeoTIFF")
6620 : && !EQUAL(pszProfile,"GDALGeoTIFF") )
6621 : {
6622 : CPLError( CE_Failure, CPLE_AppDefined,
6623 : "PROFILE=%s not supported in GTIFF driver.",
6624 0 : pszProfile );
6625 0 : return NULL;
6626 : }
6627 :
6628 157 : if( EQUAL(pszProfile,"BASELINE") )
6629 5 : bGeoTIFF = FALSE;
6630 : else
6631 152 : bGeoTIFF = TRUE;
6632 :
6633 : /* -------------------------------------------------------------------- */
6634 : /* Special handling for NBITS. Copy from band metadata if found. */
6635 : /* -------------------------------------------------------------------- */
6636 157 : char **papszCreateOptions = CSLDuplicate( papszOptions );
6637 :
6638 157 : if( poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
6639 : && atoi(poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) > 0
6640 : && CSLFetchNameValue( papszCreateOptions, "NBITS") == NULL )
6641 : {
6642 : papszCreateOptions =
6643 : CSLSetNameValue( papszCreateOptions, "NBITS",
6644 : poPBand->GetMetadataItem( "NBITS",
6645 3 : "IMAGE_STRUCTURE" ) );
6646 : }
6647 :
6648 157 : if( CSLFetchNameValue( papszOptions, "PIXELTYPE" ) == NULL
6649 : && eType == GDT_Byte
6650 : && poPBand->GetMetadataItem( "PIXELTYPE", "IMAGE_STRUCTURE" ) )
6651 : {
6652 : papszCreateOptions =
6653 : CSLSetNameValue( papszCreateOptions, "PIXELTYPE",
6654 : poPBand->GetMetadataItem(
6655 0 : "PIXELTYPE", "IMAGE_STRUCTURE" ) );
6656 : }
6657 :
6658 : /* -------------------------------------------------------------------- */
6659 : /* Create the file. */
6660 : /* -------------------------------------------------------------------- */
6661 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
6662 157 : eType, papszCreateOptions );
6663 :
6664 157 : CSLDestroy( papszCreateOptions );
6665 :
6666 157 : if( hTIFF == NULL )
6667 0 : return NULL;
6668 :
6669 157 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
6670 157 : TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample );
6671 :
6672 : /* -------------------------------------------------------------------- */
6673 : /* Are we really producing an RGBA image? If so, set the */
6674 : /* associated alpha information. */
6675 : /* -------------------------------------------------------------------- */
6676 : int bForcePhotometric =
6677 157 : CSLFetchNameValue(papszOptions,"PHOTOMETRIC") != NULL;
6678 :
6679 157 : if( nBands == 4 && !bForcePhotometric
6680 : && poSrcDS->GetRasterBand(4)->GetColorInterpretation()==GCI_AlphaBand)
6681 : {
6682 : uint16 v[1];
6683 :
6684 2 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6685 2 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
6686 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6687 : }
6688 :
6689 : /* -------------------------------------------------------------------- */
6690 : /* If the output is jpeg compressed, and the input is RGB make */
6691 : /* sure we note that. */
6692 : /* -------------------------------------------------------------------- */
6693 : uint16 nCompression;
6694 :
6695 157 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
6696 0 : nCompression = COMPRESSION_NONE;
6697 :
6698 157 : if( nCompression == COMPRESSION_JPEG )
6699 : {
6700 5 : if( nBands >= 3
6701 : && (poSrcDS->GetRasterBand(1)->GetColorInterpretation()
6702 : == GCI_YCbCr_YBand)
6703 : && (poSrcDS->GetRasterBand(2)->GetColorInterpretation()
6704 : == GCI_YCbCr_CbBand)
6705 : && (poSrcDS->GetRasterBand(3)->GetColorInterpretation()
6706 : == GCI_YCbCr_CrBand) )
6707 : {
6708 : /* do nothing ... */
6709 : }
6710 : else
6711 : {
6712 : /* we assume RGB if it isn't explicitly YCbCr */
6713 5 : CPLDebug( "GTiff", "Setting JPEGCOLORMODE_RGB" );
6714 5 : TIFFSetField( hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
6715 : }
6716 : }
6717 :
6718 : /* -------------------------------------------------------------------- */
6719 : /* Does the source image consist of one band, with a palette? */
6720 : /* If so, copy over. */
6721 : /* -------------------------------------------------------------------- */
6722 157 : if( (nBands == 1 || nBands == 2) && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
6723 : && eType == GDT_Byte )
6724 : {
6725 : unsigned short anTRed[256], anTGreen[256], anTBlue[256];
6726 : GDALColorTable *poCT;
6727 :
6728 4 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
6729 :
6730 1028 : for( int iColor = 0; iColor < 256; iColor++ )
6731 : {
6732 1024 : if( iColor < poCT->GetColorEntryCount() )
6733 : {
6734 : GDALColorEntry sRGB;
6735 :
6736 477 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
6737 :
6738 477 : anTRed[iColor] = (unsigned short) (257 * sRGB.c1);
6739 477 : anTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
6740 477 : anTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
6741 : }
6742 : else
6743 : {
6744 547 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
6745 : }
6746 : }
6747 :
6748 4 : if( !bForcePhotometric )
6749 4 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
6750 4 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, anTRed, anTGreen, anTBlue );
6751 : }
6752 153 : else if( (nBands == 1 || nBands == 2)
6753 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
6754 : && eType == GDT_UInt16 )
6755 : {
6756 : unsigned short *panTRed, *panTGreen, *panTBlue;
6757 : GDALColorTable *poCT;
6758 :
6759 1 : panTRed = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6760 1 : panTGreen = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6761 1 : panTBlue = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6762 :
6763 1 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
6764 :
6765 65537 : for( int iColor = 0; iColor < 65536; iColor++ )
6766 : {
6767 65536 : if( iColor < poCT->GetColorEntryCount() )
6768 : {
6769 : GDALColorEntry sRGB;
6770 :
6771 65536 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
6772 :
6773 65536 : panTRed[iColor] = (unsigned short) (256 * sRGB.c1);
6774 65536 : panTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
6775 65536 : panTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
6776 : }
6777 : else
6778 : {
6779 0 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
6780 : }
6781 : }
6782 :
6783 1 : if( !bForcePhotometric )
6784 1 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
6785 1 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue );
6786 :
6787 1 : CPLFree( panTRed );
6788 1 : CPLFree( panTGreen );
6789 1 : CPLFree( panTBlue );
6790 : }
6791 152 : else if( poSrcDS->GetRasterBand(1)->GetColorTable() != NULL )
6792 : CPLError( CE_Warning, CPLE_AppDefined,
6793 : "Unable to export color table to GeoTIFF file. Color tables\n"
6794 0 : "can only be written to 1 band or 2 bands Byte or UInt16 GeoTIFF files." );
6795 :
6796 157 : if( nBands == 2
6797 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
6798 : && (eType == GDT_Byte || eType == GDT_UInt16) )
6799 : {
6800 1 : uint16 v[1] = { EXTRASAMPLE_UNASSALPHA };
6801 :
6802 1 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v );
6803 : }
6804 :
6805 : /* -------------------------------------------------------------------- */
6806 : /* Transfer some TIFF specific metadata, if available. */
6807 : /* The return value will tell us if we need to try again later with*/
6808 : /* PAM because the profile doesn't allow to write some metadata */
6809 : /* as TIFF tag */
6810 : /* -------------------------------------------------------------------- */
6811 : int bHasWrittenMDInGeotiffTAG =
6812 : GTiffDataset::WriteMetadata( poSrcDS, hTIFF, FALSE, pszProfile,
6813 157 : pszFilename, papszOptions );
6814 :
6815 : /* -------------------------------------------------------------------- */
6816 : /* Write NoData value, if exist. */
6817 : /* -------------------------------------------------------------------- */
6818 157 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
6819 : {
6820 : int bSuccess;
6821 : double dfNoData;
6822 :
6823 150 : dfNoData = poSrcDS->GetRasterBand(1)->GetNoDataValue( &bSuccess );
6824 150 : if ( bSuccess )
6825 20 : GTiffDataset::WriteNoDataValue( hTIFF, dfNoData );
6826 : }
6827 :
6828 : /* -------------------------------------------------------------------- */
6829 : /* Write affine transform if it is meaningful. */
6830 : /* -------------------------------------------------------------------- */
6831 157 : const char *pszProjection = NULL;
6832 : double adfGeoTransform[6];
6833 :
6834 157 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
6835 : && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
6836 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
6837 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 ))
6838 : {
6839 108 : if( bGeoTIFF )
6840 : {
6841 207 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
6842 : && adfGeoTransform[5] < 0.0 )
6843 : {
6844 :
6845 : double adfPixelScale[3], adfTiePoints[6];
6846 :
6847 103 : adfPixelScale[0] = adfGeoTransform[1];
6848 103 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
6849 103 : adfPixelScale[2] = 0.0;
6850 :
6851 103 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
6852 :
6853 103 : adfTiePoints[0] = 0.0;
6854 103 : adfTiePoints[1] = 0.0;
6855 103 : adfTiePoints[2] = 0.0;
6856 103 : adfTiePoints[3] = adfGeoTransform[0];
6857 103 : adfTiePoints[4] = adfGeoTransform[3];
6858 103 : adfTiePoints[5] = 0.0;
6859 :
6860 103 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
6861 : }
6862 : else
6863 : {
6864 : double adfMatrix[16];
6865 :
6866 1 : memset(adfMatrix,0,sizeof(double) * 16);
6867 :
6868 1 : adfMatrix[0] = adfGeoTransform[1];
6869 1 : adfMatrix[1] = adfGeoTransform[2];
6870 1 : adfMatrix[3] = adfGeoTransform[0];
6871 1 : adfMatrix[4] = adfGeoTransform[4];
6872 1 : adfMatrix[5] = adfGeoTransform[5];
6873 1 : adfMatrix[7] = adfGeoTransform[3];
6874 1 : adfMatrix[15] = 1.0;
6875 :
6876 1 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
6877 : }
6878 :
6879 104 : pszProjection = poSrcDS->GetProjectionRef();
6880 : }
6881 :
6882 : /* -------------------------------------------------------------------- */
6883 : /* Do we need a TFW file? */
6884 : /* -------------------------------------------------------------------- */
6885 108 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE ) )
6886 1 : GDALWriteWorldFile( pszFilename, "tfw", adfGeoTransform );
6887 107 : else if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
6888 1 : GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
6889 : }
6890 :
6891 : /* -------------------------------------------------------------------- */
6892 : /* Otherwise write tiepoints if they are available. */
6893 : /* -------------------------------------------------------------------- */
6894 49 : else if( poSrcDS->GetGCPCount() > 0 && bGeoTIFF )
6895 : {
6896 3 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
6897 : double *padfTiePoints;
6898 :
6899 : padfTiePoints = (double *)
6900 3 : CPLMalloc(6*sizeof(double)*poSrcDS->GetGCPCount());
6901 :
6902 15 : for( int iGCP = 0; iGCP < poSrcDS->GetGCPCount(); iGCP++ )
6903 : {
6904 :
6905 12 : padfTiePoints[iGCP*6+0] = pasGCPs[iGCP].dfGCPPixel;
6906 12 : padfTiePoints[iGCP*6+1] = pasGCPs[iGCP].dfGCPLine;
6907 12 : padfTiePoints[iGCP*6+2] = 0;
6908 12 : padfTiePoints[iGCP*6+3] = pasGCPs[iGCP].dfGCPX;
6909 12 : padfTiePoints[iGCP*6+4] = pasGCPs[iGCP].dfGCPY;
6910 12 : padfTiePoints[iGCP*6+5] = pasGCPs[iGCP].dfGCPZ;
6911 : }
6912 :
6913 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
6914 3 : 6*poSrcDS->GetGCPCount(), padfTiePoints );
6915 3 : CPLFree( padfTiePoints );
6916 :
6917 3 : pszProjection = poSrcDS->GetGCPProjection();
6918 :
6919 3 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE )
6920 : || CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
6921 : {
6922 : CPLError(CE_Warning, CPLE_AppDefined,
6923 0 : "TFW=ON or WORLDFILE=ON creation options are ignored when GCPs are available");
6924 : }
6925 : }
6926 :
6927 : else
6928 46 : pszProjection = poSrcDS->GetProjectionRef();
6929 :
6930 : /* -------------------------------------------------------------------- */
6931 : /* Write the projection information, if possible. */
6932 : /* -------------------------------------------------------------------- */
6933 157 : if( pszProjection != NULL && strlen(pszProjection) > 0 && bGeoTIFF )
6934 : {
6935 : GTIF *psGTIF;
6936 :
6937 105 : psGTIF = GTIFNew( hTIFF );
6938 105 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
6939 :
6940 105 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
6941 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
6942 : GDALMD_AOP_POINT) )
6943 : {
6944 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
6945 3 : RasterPixelIsPoint);
6946 : }
6947 :
6948 105 : GTIFWriteKeys( psGTIF );
6949 105 : GTIFFree( psGTIF );
6950 : }
6951 :
6952 : /* -------------------------------------------------------------------- */
6953 : /* If we are writing jpeg compression we need to write some */
6954 : /* imagery to force the jpegtables to get created. This is, */
6955 : /* likely only needed with libtiff 3.9.x. */
6956 : /* -------------------------------------------------------------------- */
6957 : if( nCompression == COMPRESSION_JPEG
6958 : && strstr(TIFFLIB_VERSION_STR, "Version 3.9") != NULL )
6959 : {
6960 : CPLDebug( "GDAL",
6961 : "Writing zero block to force creation of JPEG tables." );
6962 : if( TIFFIsTiled( hTIFF ) )
6963 : {
6964 : int cc = TIFFTileSize( hTIFF );
6965 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
6966 : TIFFWriteEncodedTile(hTIFF, 0, pabyZeros, cc);
6967 : CPLFree( pabyZeros );
6968 : }
6969 : else
6970 : {
6971 : int cc = TIFFStripSize( hTIFF );
6972 : unsigned char *pabyZeros = (unsigned char *) CPLCalloc(cc,1);
6973 : TIFFWriteEncodedStrip(hTIFF, 0, pabyZeros, cc);
6974 : CPLFree( pabyZeros );
6975 : }
6976 : }
6977 :
6978 : /* -------------------------------------------------------------------- */
6979 : /* Cleanup */
6980 : /* -------------------------------------------------------------------- */
6981 :
6982 157 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffCreateCopy()");
6983 157 : TIFFWriteDirectory( hTIFF );
6984 157 : TIFFFlush( hTIFF );
6985 157 : XTIFFClose( hTIFF );
6986 157 : hTIFF = NULL;
6987 :
6988 157 : if( eErr != CE_None )
6989 : {
6990 0 : VSIUnlink( pszFilename );
6991 0 : return NULL;
6992 : }
6993 :
6994 : /* -------------------------------------------------------------------- */
6995 : /* Re-open as a dataset and copy over missing metadata using */
6996 : /* PAM facilities. */
6997 : /* -------------------------------------------------------------------- */
6998 : GTiffDataset *poDS;
6999 157 : CPLString osFileName("GTIFF_RAW:");
7000 :
7001 157 : osFileName += pszFilename;
7002 :
7003 157 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_Update );
7004 157 : if( poDS == NULL )
7005 0 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_ReadOnly );
7006 :
7007 157 : if ( poDS == NULL )
7008 : {
7009 0 : VSIUnlink( pszFilename );
7010 157 : return NULL;
7011 : }
7012 :
7013 157 : poDS->osProfile = pszProfile;
7014 157 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
7015 157 : poDS->papszCreationOptions = CSLDuplicate( papszOptions );
7016 :
7017 : /* -------------------------------------------------------------------- */
7018 : /* CloneInfo() doesn't merge metadata, it just replaces it totally */
7019 : /* So we have to merge it */
7020 : /* -------------------------------------------------------------------- */
7021 :
7022 157 : char **papszSRC_MD = poSrcDS->GetMetadata();
7023 157 : char **papszDST_MD = CSLDuplicate(poDS->GetMetadata());
7024 :
7025 157 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
7026 :
7027 157 : poDS->SetMetadata( papszDST_MD );
7028 157 : CSLDestroy( papszDST_MD );
7029 :
7030 : /* Depending on the PHOTOMETRIC tag, the TIFF file may not have */
7031 : /* the same band count as the source. Will fail later in GDALDatasetCopyWholeRaster anyway... */
7032 408 : for( int nBand = 1;
7033 : nBand <= MIN(poDS->GetRasterCount(), poSrcDS->GetRasterCount()) ;
7034 : nBand++ )
7035 : {
7036 251 : char **papszSRC_MD = poSrcDS->GetRasterBand(nBand)->GetMetadata();
7037 251 : char **papszDST_MD = CSLDuplicate(poDS->GetRasterBand(nBand)->GetMetadata());
7038 :
7039 251 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
7040 :
7041 251 : poDS->GetRasterBand(nBand)->SetMetadata( papszDST_MD );
7042 251 : CSLDestroy( papszDST_MD );
7043 : }
7044 :
7045 157 : hTIFF = (TIFF*) poDS->GetInternalHandle(NULL);
7046 :
7047 : /* -------------------------------------------------------------------- */
7048 : /* Second chance : now that we have a PAM dataset, it is possible */
7049 : /* to write metadata that we couldn't be writen as TIFF tag */
7050 : /* -------------------------------------------------------------------- */
7051 157 : if (!bHasWrittenMDInGeotiffTAG)
7052 : GTiffDataset::WriteMetadata( poDS, hTIFF, TRUE, pszProfile,
7053 4 : pszFilename, papszOptions, TRUE /* don't write RPC and IMD file again */);
7054 :
7055 : /* To avoid unnecessary directory rewriting */
7056 157 : poDS->bMetadataChanged = FALSE;
7057 157 : poDS->bGeoTIFFInfoChanged = FALSE;
7058 :
7059 : /* We must re-set the compression level at this point, since it has */
7060 : /* been lost a few lines above when closing the newly create TIFF file */
7061 : /* The TIFFTAG_ZIPQUALITY & TIFFTAG_JPEGQUALITY are not store in the TIFF file. */
7062 : /* They are just TIFF session parameters */
7063 157 : if (nCompression == COMPRESSION_ADOBE_DEFLATE)
7064 : {
7065 4 : int nZLevel = GTiffGetZLevel(papszOptions);
7066 4 : if (nZLevel != -1)
7067 : {
7068 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
7069 : }
7070 : }
7071 153 : else if( nCompression == COMPRESSION_JPEG)
7072 : {
7073 5 : int nJpegQuality = GTiffGetJpegQuality(papszOptions);
7074 5 : if (nJpegQuality != -1)
7075 : {
7076 2 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
7077 : }
7078 : }
7079 :
7080 : /* -------------------------------------------------------------------- */
7081 : /* Copy actual imagery. */
7082 : /* -------------------------------------------------------------------- */
7083 :
7084 160 : if (poDS->bTreatAsSplit || poDS->bTreatAsSplitBitmap)
7085 : {
7086 : /* For split bands, we use TIFFWriteScanline() interface */
7087 3 : CPLAssert(poDS->nBitsPerSample == 8 || poDS->nBitsPerSample == 1);
7088 :
7089 5 : if (poDS->nPlanarConfig == PLANARCONFIG_CONTIG && poDS->nBands > 1)
7090 : {
7091 : int j;
7092 2 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
7093 2 : eErr = CE_None;
7094 7050 : for(j=0;j<nYSize && eErr == CE_None;j++)
7095 : {
7096 : eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1,
7097 : pabyScanline, nXSize, 1,
7098 7048 : GDT_Byte, nBands, NULL, poDS->nBands, 0, 1);
7099 7048 : if (eErr == CE_None &&
7100 : TIFFWriteScanline( hTIFF, pabyScanline, j, 0) == -1)
7101 : {
7102 : CPLError( CE_Failure, CPLE_AppDefined,
7103 0 : "TIFFWriteScanline() failed." );
7104 0 : eErr = CE_Failure;
7105 : }
7106 7048 : if( !pfnProgress( (j+1) * 1.0 / nYSize, NULL, pProgressData ) )
7107 0 : eErr = CE_Failure;
7108 : }
7109 2 : CPLFree(pabyScanline);
7110 : }
7111 : else
7112 : {
7113 : int iBand, j;
7114 1 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
7115 1 : eErr = CE_None;
7116 4 : for(iBand=1;iBand<=nBands && eErr == CE_None;iBand++)
7117 : {
7118 15003 : for(j=0;j<nYSize && eErr == CE_None;j++)
7119 : {
7120 : eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
7121 : GF_Read, 0, j, nXSize, 1,
7122 : pabyScanline, nXSize, 1,
7123 15000 : GDT_Byte, 0, 0);
7124 15000 : if (poDS->bTreatAsSplitBitmap)
7125 : {
7126 0 : for(int i=0;i<nXSize;i++)
7127 : {
7128 0 : GByte byVal = pabyScanline[i];
7129 0 : if ((i & 0x7) == 0)
7130 0 : pabyScanline[i >> 3] = 0;
7131 0 : if (byVal)
7132 0 : pabyScanline[i >> 3] |= (0x80 >> (i & 0x7));
7133 : }
7134 : }
7135 15000 : if (eErr == CE_None &&
7136 : TIFFWriteScanline( hTIFF, pabyScanline, j, iBand - 1) == -1)
7137 : {
7138 : CPLError( CE_Failure, CPLE_AppDefined,
7139 0 : "TIFFWriteScanline() failed." );
7140 0 : eErr = CE_Failure;
7141 : }
7142 15000 : if( !pfnProgress( (j+1 + (iBand - 1) * nYSize) * 1.0 /
7143 : (nBands * nYSize), NULL, pProgressData ) )
7144 0 : eErr = CE_Failure;
7145 : }
7146 : }
7147 1 : CPLFree(pabyScanline);
7148 : }
7149 :
7150 : /* Necessary to be able to read the file without re-opening */
7151 : #if defined(HAVE_TIFFGETSIZEPROC)
7152 3 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
7153 :
7154 3 : TIFFFlushData( hTIFF );
7155 :
7156 3 : toff_t nNewDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
7157 3 : if( (nNewDirOffset % 2) == 1 )
7158 3 : nNewDirOffset++;
7159 : #endif
7160 :
7161 3 : TIFFFlush( hTIFF );
7162 :
7163 : #if defined(HAVE_TIFFGETSIZEPROC)
7164 3 : if( poDS->nDirOffset != TIFFCurrentDirOffset( hTIFF ) )
7165 : {
7166 1 : poDS->nDirOffset = nNewDirOffset;
7167 1 : CPLDebug( "GTiff", "directory moved during flush." );
7168 : }
7169 : #endif
7170 : }
7171 : else
7172 : {
7173 154 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
7174 154 : if (nCompression != COMPRESSION_NONE)
7175 13 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
7176 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
7177 : (GDALDatasetH) poDS,
7178 : papszCopyWholeRasterOptions,
7179 154 : pfnProgress, pProgressData );
7180 : }
7181 :
7182 157 : if( eErr == CE_Failure )
7183 : {
7184 0 : delete poDS;
7185 0 : poDS = NULL;
7186 :
7187 0 : VSIUnlink( pszFilename ); // should really delete more carefully.
7188 : }
7189 :
7190 157 : return poDS;
7191 : }
7192 :
7193 : /************************************************************************/
7194 : /* GetProjectionRef() */
7195 : /************************************************************************/
7196 :
7197 3127 : const char *GTiffDataset::GetProjectionRef()
7198 :
7199 : {
7200 3127 : if( nGCPCount == 0 )
7201 : {
7202 3097 : LookForProjection();
7203 :
7204 3097 : if( EQUAL(pszProjection,"") )
7205 70 : return GDALPamDataset::GetProjectionRef();
7206 : else
7207 3027 : return( pszProjection );
7208 : }
7209 : else
7210 30 : return "";
7211 : }
7212 :
7213 : /************************************************************************/
7214 : /* SetProjection() */
7215 : /************************************************************************/
7216 :
7217 589 : CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
7218 :
7219 : {
7220 589 : LookForProjection();
7221 :
7222 589 : if( !EQUALN(pszNewProjection,"GEOGCS",6)
7223 : && !EQUALN(pszNewProjection,"PROJCS",6)
7224 : && !EQUALN(pszNewProjection,"LOCAL_CS",6)
7225 : && !EQUAL(pszNewProjection,"") )
7226 : {
7227 : CPLError( CE_Failure, CPLE_AppDefined,
7228 : "Only OGC WKT Projections supported for writing to GeoTIFF.\n"
7229 : "%s not supported.",
7230 0 : pszNewProjection );
7231 :
7232 0 : return CE_Failure;
7233 : }
7234 :
7235 589 : CPLFree( pszProjection );
7236 589 : pszProjection = CPLStrdup( pszNewProjection );
7237 :
7238 589 : bGeoTIFFInfoChanged = TRUE;
7239 :
7240 589 : return CE_None;
7241 : }
7242 :
7243 : /************************************************************************/
7244 : /* GetGeoTransform() */
7245 : /************************************************************************/
7246 :
7247 2108 : CPLErr GTiffDataset::GetGeoTransform( double * padfTransform )
7248 :
7249 : {
7250 2108 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
7251 :
7252 2108 : if( !bGeoTransformValid )
7253 89 : return CE_Failure;
7254 : else
7255 2019 : return CE_None;
7256 : }
7257 :
7258 : /************************************************************************/
7259 : /* SetGeoTransform() */
7260 : /************************************************************************/
7261 :
7262 594 : CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
7263 :
7264 : {
7265 594 : if( GetAccess() == GA_Update )
7266 : {
7267 594 : memcpy( adfGeoTransform, padfTransform, sizeof(double)*6 );
7268 594 : bGeoTransformValid = TRUE;
7269 594 : bGeoTIFFInfoChanged = TRUE;
7270 :
7271 594 : return( CE_None );
7272 : }
7273 : else
7274 : {
7275 : CPLError( CE_Failure, CPLE_NotSupported,
7276 0 : "Attempt to call SetGeoTransform() on a read-only GeoTIFF file." );
7277 0 : return CE_Failure;
7278 : }
7279 : }
7280 :
7281 : /************************************************************************/
7282 : /* GetGCPCount() */
7283 : /************************************************************************/
7284 :
7285 823 : int GTiffDataset::GetGCPCount()
7286 :
7287 : {
7288 823 : return nGCPCount;
7289 : }
7290 :
7291 : /************************************************************************/
7292 : /* GetGCPProjection() */
7293 : /************************************************************************/
7294 :
7295 79 : const char *GTiffDataset::GetGCPProjection()
7296 :
7297 : {
7298 79 : if( nGCPCount > 0 )
7299 : {
7300 79 : LookForProjection();
7301 : }
7302 79 : if (pszProjection != NULL)
7303 79 : return pszProjection;
7304 : else
7305 0 : return "";
7306 : }
7307 :
7308 : /************************************************************************/
7309 : /* GetGCPs() */
7310 : /************************************************************************/
7311 :
7312 35 : const GDAL_GCP *GTiffDataset::GetGCPs()
7313 :
7314 : {
7315 35 : return pasGCPList;
7316 : }
7317 :
7318 : /************************************************************************/
7319 : /* SetGCPs() */
7320 : /************************************************************************/
7321 :
7322 : CPLErr GTiffDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
7323 2 : const char *pszGCPProjection )
7324 : {
7325 2 : if( GetAccess() == GA_Update )
7326 : {
7327 2 : bLookedForProjection = TRUE;
7328 :
7329 2 : if( this->nGCPCount > 0 )
7330 : {
7331 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
7332 0 : CPLFree( this->pasGCPList );
7333 : }
7334 :
7335 2 : this->nGCPCount = nGCPCount;
7336 2 : this->pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPList);
7337 :
7338 2 : CPLFree( this->pszProjection );
7339 2 : this->pszProjection = CPLStrdup( pszGCPProjection );
7340 2 : bGeoTIFFInfoChanged = TRUE;
7341 :
7342 2 : return CE_None;
7343 : }
7344 : else
7345 : {
7346 : CPLError( CE_Failure, CPLE_NotSupported,
7347 0 : "SetGCPs() is only supported on newly created GeoTIFF files." );
7348 0 : return CE_Failure;
7349 : }
7350 : }
7351 :
7352 : /************************************************************************/
7353 : /* GetMetadata() */
7354 : /************************************************************************/
7355 :
7356 4154 : char **GTiffDataset::GetMetadata( const char * pszDomain )
7357 :
7358 : {
7359 4154 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
7360 0 : return GDALPamDataset::GetMetadata( pszDomain );
7361 :
7362 : /* FIXME ? Should we call LookForProjection() to load GDALMD_AREA_OR_POINT ? */
7363 : /* This can impact performances */
7364 :
7365 4154 : return oGTiffMDMD.GetMetadata( pszDomain );
7366 : }
7367 :
7368 : /************************************************************************/
7369 : /* SetMetadata() */
7370 : /************************************************************************/
7371 200 : CPLErr GTiffDataset::SetMetadata( char ** papszMD, const char *pszDomain )
7372 :
7373 : {
7374 200 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
7375 200 : bMetadataChanged = TRUE;
7376 :
7377 200 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
7378 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT) != NULL )
7379 : {
7380 : const char* pszPrevValue =
7381 107 : GetMetadataItem(GDALMD_AREA_OR_POINT);
7382 : const char* pszNewValue =
7383 107 : CSLFetchNameValue(papszMD, GDALMD_AREA_OR_POINT);
7384 107 : if (pszPrevValue == NULL || pszNewValue == NULL ||
7385 : !EQUAL(pszPrevValue, pszNewValue))
7386 : {
7387 7 : LookForProjection();
7388 7 : bGeoTIFFInfoChanged = TRUE;
7389 : }
7390 : }
7391 :
7392 200 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
7393 : }
7394 :
7395 : /************************************************************************/
7396 : /* GetMetadataItem() */
7397 : /************************************************************************/
7398 :
7399 : const char *GTiffDataset::GetMetadataItem( const char * pszName,
7400 18536 : const char * pszDomain )
7401 :
7402 : {
7403 18536 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
7404 2 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
7405 :
7406 18534 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
7407 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
7408 : {
7409 838 : LookForProjection();
7410 : }
7411 :
7412 18534 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
7413 : }
7414 :
7415 : /************************************************************************/
7416 : /* SetMetadataItem() */
7417 : /************************************************************************/
7418 :
7419 : CPLErr GTiffDataset::SetMetadataItem( const char *pszName,
7420 : const char *pszValue,
7421 4800 : const char *pszDomain )
7422 :
7423 : {
7424 4800 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
7425 4800 : bMetadataChanged = TRUE;
7426 :
7427 4800 : if( (pszDomain == NULL || EQUAL(pszDomain, "")) &&
7428 : pszName != NULL && EQUAL(pszName, GDALMD_AREA_OR_POINT) )
7429 : {
7430 8 : LookForProjection();
7431 8 : bGeoTIFFInfoChanged = TRUE;
7432 : }
7433 :
7434 4800 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
7435 : }
7436 :
7437 : /************************************************************************/
7438 : /* GetInternalHandle() */
7439 : /************************************************************************/
7440 :
7441 225 : void *GTiffDataset::GetInternalHandle( const char * /* pszHandleName */ )
7442 :
7443 : {
7444 225 : return hTIFF;
7445 : }
7446 :
7447 :
7448 : /************************************************************************/
7449 : /* FindRPBFile() */
7450 : /************************************************************************/
7451 :
7452 3488 : int GTiffDataset::FindRPBFile(char** papszSiblingFiles)
7453 : {
7454 3488 : CPLString osTarget = CPLResetExtension( osFilename, "RPB" );
7455 :
7456 3488 : if( papszSiblingFiles == NULL )
7457 : {
7458 : VSIStatBufL sStatBuf;
7459 :
7460 219 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7461 : {
7462 218 : osTarget = CPLResetExtension( osFilename, "rpb" );
7463 :
7464 218 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7465 218 : return FALSE;
7466 : }
7467 : }
7468 : else
7469 : {
7470 : int iSibling = CSLFindString( papszSiblingFiles,
7471 3269 : CPLGetFilename(osTarget) );
7472 3269 : if( iSibling < 0 )
7473 3267 : return FALSE;
7474 :
7475 2 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
7476 2 : osTarget += papszSiblingFiles[iSibling];
7477 : }
7478 :
7479 3 : osRPBFile = osTarget;
7480 3 : return TRUE;
7481 : }
7482 :
7483 :
7484 : /************************************************************************/
7485 : /* FindRPCFile() */
7486 : /************************************************************************/
7487 :
7488 3485 : int GTiffDataset::FindRPCFile(char** papszSiblingFiles)
7489 : {
7490 3485 : CPLString osSrcPath = osFilename;
7491 3485 : CPLString soPt(".");
7492 3485 : size_t found = osSrcPath.rfind(soPt);
7493 3485 : if (found == CPLString::npos)
7494 109 : return NULL;
7495 3376 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.txt");
7496 3376 : CPLString osTarget = osSrcPath;
7497 :
7498 3376 : if( papszSiblingFiles == NULL )
7499 : {
7500 : VSIStatBufL sStatBuf;
7501 :
7502 137 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7503 : {
7504 137 : osSrcPath = osFilename;
7505 137 : osSrcPath.replace (found, osSrcPath.size() - found, "_RPC.TXT");
7506 137 : osTarget = osSrcPath;
7507 :
7508 137 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7509 : {
7510 137 : osSrcPath = osFilename;
7511 137 : osSrcPath.replace (found, osSrcPath.size() - found, "_rpc.TXT");
7512 137 : osTarget = osSrcPath;
7513 :
7514 137 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7515 : {
7516 137 : return FALSE;
7517 : }
7518 : }
7519 : }
7520 : }
7521 : else
7522 : {
7523 : int iSibling = CSLFindString( papszSiblingFiles,
7524 3239 : CPLGetFilename(osTarget) );
7525 3239 : if( iSibling < 0 )
7526 3239 : return FALSE;
7527 :
7528 0 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
7529 0 : osTarget += papszSiblingFiles[iSibling];
7530 : }
7531 :
7532 0 : osRPCFile = osTarget;
7533 0 : return TRUE;
7534 : }
7535 :
7536 : /************************************************************************/
7537 : /* FindIMDFile() */
7538 : /************************************************************************/
7539 :
7540 3488 : int GTiffDataset::FindIMDFile(char** papszSiblingFiles)
7541 : {
7542 3488 : CPLString osTarget = CPLResetExtension( osFilename, "IMD" );
7543 :
7544 3488 : if( papszSiblingFiles == NULL )
7545 : {
7546 : VSIStatBufL sStatBuf;
7547 :
7548 219 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7549 : {
7550 217 : osTarget = CPLResetExtension( osFilename, "imd" );
7551 :
7552 217 : if( VSIStatL( osTarget, &sStatBuf ) != 0 )
7553 217 : return FALSE;
7554 : }
7555 : }
7556 : else
7557 : {
7558 : int iSibling = CSLFindString( papszSiblingFiles,
7559 3269 : CPLGetFilename(osTarget) );
7560 3269 : if( iSibling < 0 )
7561 3265 : return FALSE;
7562 :
7563 4 : osTarget.resize(osTarget.size() - strlen(papszSiblingFiles[iSibling]));
7564 4 : osTarget += papszSiblingFiles[iSibling];
7565 : }
7566 :
7567 6 : osIMDFile = osTarget;
7568 6 : return TRUE;
7569 : }
7570 :
7571 : /************************************************************************/
7572 : /* GetFileList() */
7573 : /************************************************************************/
7574 :
7575 884 : char **GTiffDataset::GetFileList()
7576 :
7577 : {
7578 884 : char **papszFileList = GDALPamDataset::GetFileList();
7579 :
7580 884 : if (osIMDFile.size() != 0)
7581 2 : papszFileList = CSLAddString( papszFileList, osIMDFile );
7582 884 : if (osRPBFile.size() != 0)
7583 1 : papszFileList = CSLAddString( papszFileList, osRPBFile );
7584 884 : if (osRPCFile.size() != 0)
7585 0 : papszFileList = CSLAddString( papszFileList, osRPCFile );
7586 :
7587 884 : return papszFileList;
7588 : }
7589 :
7590 : /************************************************************************/
7591 : /* CreateMaskBand() */
7592 : /************************************************************************/
7593 :
7594 13 : CPLErr GTiffDataset::CreateMaskBand(int nFlags)
7595 : {
7596 13 : if (poMaskDS != NULL)
7597 : {
7598 : CPLError(CE_Failure, CPLE_AppDefined,
7599 0 : "This TIFF dataset has already an internal mask band");
7600 0 : return CE_Failure;
7601 : }
7602 13 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
7603 : {
7604 : toff_t nOffset;
7605 : int bIsTiled;
7606 11 : int bIsOverview = FALSE;
7607 : uint32 nSubType;
7608 :
7609 11 : if (nFlags != GMF_PER_DATASET)
7610 : {
7611 : CPLError(CE_Failure, CPLE_AppDefined,
7612 0 : "The only flag value supported for internal mask is GMF_PER_DATASET");
7613 0 : return CE_Failure;
7614 : }
7615 :
7616 : /* -------------------------------------------------------------------- */
7617 : /* If we don't have read access, then create the mask externally. */
7618 : /* -------------------------------------------------------------------- */
7619 11 : if( GetAccess() != GA_Update )
7620 : {
7621 : CPLError( CE_Warning, CPLE_AppDefined,
7622 : "File open for read-only accessing, "
7623 0 : "creating mask externally." );
7624 :
7625 0 : return GDALPamDataset::CreateMaskBand(nFlags);
7626 : }
7627 :
7628 11 : if (poBaseDS)
7629 : {
7630 6 : if (!poBaseDS->SetDirectory())
7631 0 : return CE_Failure;
7632 : }
7633 11 : if (!SetDirectory())
7634 0 : return CE_Failure;
7635 :
7636 11 : if( TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
7637 : {
7638 6 : bIsOverview = (nSubType & FILETYPE_REDUCEDIMAGE) != 0;
7639 :
7640 6 : if ((nSubType & FILETYPE_MASK) != 0)
7641 : {
7642 : CPLError( CE_Failure, CPLE_AppDefined,
7643 0 : "Cannot create a mask on a TIFF mask IFD !" );
7644 0 : return CE_Failure;
7645 : }
7646 : }
7647 :
7648 11 : TIFFFlush( hTIFF );
7649 :
7650 11 : bIsTiled = TIFFIsTiled(hTIFF);
7651 :
7652 : nOffset = GTIFFWriteDirectory(hTIFF,
7653 : (bIsOverview) ? FILETYPE_REDUCEDIMAGE | FILETYPE_MASK : FILETYPE_MASK,
7654 : nRasterXSize, nRasterYSize,
7655 : 1, PLANARCONFIG_CONTIG, 1,
7656 : nBlockXSize, nBlockYSize,
7657 : bIsTiled, COMPRESSION_NONE, PHOTOMETRIC_MASK, PREDICTOR_NONE,
7658 11 : SAMPLEFORMAT_UINT, NULL, NULL, NULL, 0, NULL, "");
7659 11 : if (nOffset == 0)
7660 0 : return CE_Failure;
7661 :
7662 11 : poMaskDS = new GTiffDataset();
7663 11 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nOffset,
7664 : FALSE, GA_Update ) != CE_None)
7665 : {
7666 0 : delete poMaskDS;
7667 0 : poMaskDS = NULL;
7668 0 : return CE_Failure;
7669 : }
7670 :
7671 11 : return CE_None;
7672 : }
7673 : else
7674 : {
7675 2 : return GDALPamDataset::CreateMaskBand(nFlags);
7676 : }
7677 : }
7678 :
7679 : /************************************************************************/
7680 : /* CreateMaskBand() */
7681 : /************************************************************************/
7682 :
7683 6 : CPLErr GTiffRasterBand::CreateMaskBand(int nFlags)
7684 : {
7685 6 : if (poGDS->poMaskDS != NULL)
7686 : {
7687 : CPLError(CE_Failure, CPLE_AppDefined,
7688 0 : "This TIFF dataset has already an internal mask band");
7689 0 : return CE_Failure;
7690 : }
7691 6 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
7692 : {
7693 6 : return poGDS->CreateMaskBand(nFlags);
7694 : }
7695 : else
7696 : {
7697 0 : return GDALPamRasterBand::CreateMaskBand(nFlags);
7698 : }
7699 : }
7700 :
7701 : /************************************************************************/
7702 : /* PrepareTIFFErrorFormat() */
7703 : /* */
7704 : /* sometimes the "module" has stuff in it that has special */
7705 : /* meaning in a printf() style format, so we try to escape it. */
7706 : /* For now we hope the only thing we have to escape is %'s. */
7707 : /************************************************************************/
7708 :
7709 0 : static char *PrepareTIFFErrorFormat( const char *module, const char *fmt )
7710 :
7711 : {
7712 : char *pszModFmt;
7713 : int iIn, iOut;
7714 :
7715 0 : pszModFmt = (char *) CPLMalloc( strlen(module)*2 + strlen(fmt) + 2 );
7716 0 : for( iOut = 0, iIn = 0; module[iIn] != '\0'; iIn++ )
7717 : {
7718 0 : if( module[iIn] == '%' )
7719 : {
7720 0 : pszModFmt[iOut++] = '%';
7721 0 : pszModFmt[iOut++] = '%';
7722 : }
7723 : else
7724 0 : pszModFmt[iOut++] = module[iIn];
7725 : }
7726 0 : pszModFmt[iOut] = '\0';
7727 0 : strcat( pszModFmt, ":" );
7728 0 : strcat( pszModFmt, fmt );
7729 :
7730 0 : return pszModFmt;
7731 : }
7732 :
7733 : /************************************************************************/
7734 : /* GTiffWarningHandler() */
7735 : /************************************************************************/
7736 : void
7737 0 : GTiffWarningHandler(const char* module, const char* fmt, va_list ap )
7738 : {
7739 : char *pszModFmt;
7740 :
7741 0 : if( strstr(fmt,"unknown field") != NULL )
7742 0 : return;
7743 :
7744 0 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
7745 0 : CPLErrorV( CE_Warning, CPLE_AppDefined, pszModFmt, ap );
7746 0 : CPLFree( pszModFmt );
7747 : }
7748 :
7749 : /************************************************************************/
7750 : /* GTiffWarningHandler() */
7751 : /************************************************************************/
7752 : void
7753 0 : GTiffErrorHandler(const char* module, const char* fmt, va_list ap )
7754 : {
7755 : char *pszModFmt;
7756 :
7757 0 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
7758 0 : CPLErrorV( CE_Failure, CPLE_AppDefined, pszModFmt, ap );
7759 0 : CPLFree( pszModFmt );
7760 0 : }
7761 :
7762 : /************************************************************************/
7763 : /* GTiffTagExtender() */
7764 : /* */
7765 : /* Install tags specially known to GDAL. */
7766 : /************************************************************************/
7767 :
7768 : static TIFFExtendProc _ParentExtender = NULL;
7769 :
7770 8307 : static void GTiffTagExtender(TIFF *tif)
7771 :
7772 : {
7773 : static const TIFFFieldInfo xtiffFieldInfo[] = {
7774 : { TIFFTAG_GDAL_METADATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
7775 : TRUE, FALSE, (char*) "GDALMetadata" },
7776 : { TIFFTAG_GDAL_NODATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
7777 : TRUE, FALSE, (char*) "GDALNoDataValue" },
7778 : { TIFFTAG_RPCCOEFFICIENT, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
7779 : TRUE, TRUE, (char*) "RPCCoefficient" }
7780 : };
7781 :
7782 8307 : if (_ParentExtender)
7783 0 : (*_ParentExtender)(tif);
7784 :
7785 : TIFFMergeFieldInfo( tif, xtiffFieldInfo,
7786 8307 : sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]) );
7787 8307 : }
7788 :
7789 : /************************************************************************/
7790 : /* GTiffOneTimeInit() */
7791 : /* */
7792 : /* This is stuff that is initialized for the TIFF library just */
7793 : /* once. We deliberately defer the initialization till the */
7794 : /* first time we are likely to call into libtiff to avoid */
7795 : /* unnecessary paging in of the library for GDAL apps that */
7796 : /* don't use it. */
7797 : /************************************************************************/
7798 :
7799 4500 : void GTiffOneTimeInit()
7800 :
7801 : {
7802 : static int bOneTimeInitDone = FALSE;
7803 :
7804 4500 : if( bOneTimeInitDone )
7805 4141 : return;
7806 :
7807 359 : bOneTimeInitDone = TRUE;
7808 :
7809 359 : _ParentExtender = TIFFSetTagExtender(GTiffTagExtender);
7810 :
7811 359 : TIFFSetWarningHandler( GTiffWarningHandler );
7812 359 : TIFFSetErrorHandler( GTiffErrorHandler );
7813 :
7814 : // This only really needed if we are linked to an external libgeotiff
7815 : // with its own (lame) file searching logic.
7816 359 : SetCSVFilenameHook( GDALDefaultCSVFilename );
7817 : }
7818 :
7819 : /************************************************************************/
7820 : /* GDALDeregister_GTiff() */
7821 : /************************************************************************/
7822 :
7823 380 : void GDALDeregister_GTiff( GDALDriver * )
7824 :
7825 : {
7826 380 : CPLDebug( "GDAL", "GDALDeregister_GTiff() called." );
7827 380 : CSVDeaccess( NULL );
7828 :
7829 : #if defined(LIBGEOTIFF_VERSION) && LIBGEOTIFF_VERSION > 1150
7830 380 : GTIFDeaccessCSV();
7831 : #endif
7832 380 : }
7833 :
7834 : /************************************************************************/
7835 : /* GDALRegister_GTiff() */
7836 : /************************************************************************/
7837 :
7838 409 : void GDALRegister_GTiff()
7839 :
7840 : {
7841 409 : if( GDALGetDriverByName( "GTiff" ) == NULL )
7842 : {
7843 : GDALDriver *poDriver;
7844 : char szCreateOptions[3072];
7845 : char szOptionalCompressItems[500];
7846 392 : int bHasJPEG = FALSE, bHasLZW = FALSE, bHasDEFLATE = FALSE;
7847 :
7848 392 : poDriver = new GDALDriver();
7849 :
7850 : /* -------------------------------------------------------------------- */
7851 : /* Determine which compression codecs are available that we */
7852 : /* want to advertise. If we are using an old libtiff we won't */
7853 : /* be able to find out so we just assume all are available. */
7854 : /* -------------------------------------------------------------------- */
7855 : strcpy( szOptionalCompressItems,
7856 392 : " <Value>NONE</Value>" );
7857 :
7858 : #if TIFFLIB_VERSION <= 20040919
7859 : strcat( szOptionalCompressItems,
7860 : " <Value>PACKBITS</Value>"
7861 : " <Value>JPEG</Value>"
7862 : " <Value>LZW</Value>"
7863 : " <Value>DEFLATE</Value>" );
7864 : bHasLZW = bHasDEFLATE = TRUE;
7865 : #else
7866 392 : TIFFCodec *c, *codecs = TIFFGetConfiguredCODECs();
7867 :
7868 6664 : for( c = codecs; c->name; c++ )
7869 : {
7870 6272 : if( c->scheme == COMPRESSION_PACKBITS )
7871 : strcat( szOptionalCompressItems,
7872 392 : " <Value>PACKBITS</Value>" );
7873 5880 : else if( c->scheme == COMPRESSION_JPEG )
7874 : {
7875 392 : bHasJPEG = TRUE;
7876 : strcat( szOptionalCompressItems,
7877 392 : " <Value>JPEG</Value>" );
7878 : }
7879 5488 : else if( c->scheme == COMPRESSION_LZW )
7880 : {
7881 392 : bHasLZW = TRUE;
7882 : strcat( szOptionalCompressItems,
7883 392 : " <Value>LZW</Value>" );
7884 : }
7885 5096 : else if( c->scheme == COMPRESSION_ADOBE_DEFLATE )
7886 : {
7887 392 : bHasDEFLATE = TRUE;
7888 : strcat( szOptionalCompressItems,
7889 392 : " <Value>DEFLATE</Value>" );
7890 : }
7891 4704 : else if( c->scheme == COMPRESSION_CCITTRLE )
7892 : strcat( szOptionalCompressItems,
7893 392 : " <Value>CCITTRLE</Value>" );
7894 4312 : else if( c->scheme == COMPRESSION_CCITTFAX3 )
7895 : strcat( szOptionalCompressItems,
7896 392 : " <Value>CCITTFAX3</Value>" );
7897 3920 : else if( c->scheme == COMPRESSION_CCITTFAX4 )
7898 : strcat( szOptionalCompressItems,
7899 392 : " <Value>CCITTFAX4</Value>" );
7900 : }
7901 392 : _TIFFfree( codecs );
7902 : #endif
7903 :
7904 : /* -------------------------------------------------------------------- */
7905 : /* Build full creation option list. */
7906 : /* -------------------------------------------------------------------- */
7907 : sprintf( szCreateOptions, "%s%s%s",
7908 : "<CreationOptionList>"
7909 : " <Option name='COMPRESS' type='string-select'>",
7910 : szOptionalCompressItems,
7911 392 : " </Option>");
7912 392 : if (bHasLZW || bHasDEFLATE)
7913 : strcat( szCreateOptions, ""
7914 392 : " <Option name='PREDICTOR' type='int' description='Predictor Type'/>");
7915 392 : if (bHasJPEG)
7916 : strcat( szCreateOptions, ""
7917 392 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>");
7918 392 : if (bHasDEFLATE)
7919 : strcat( szCreateOptions, ""
7920 392 : " <Option name='ZLEVEL' type='int' description='DEFLATE compression level 1-9' default='6'/>");
7921 : strcat( szCreateOptions, ""
7922 : " <Option name='NBITS' type='int' description='BITS for sub-byte files (1-7), sub-uint16 (9-15), sub-uint32 (17-31)'/>"
7923 : " <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
7924 : " <Value>BAND</Value>"
7925 : " <Value>PIXEL</Value>"
7926 : " </Option>"
7927 : " <Option name='TILED' type='boolean' description='Switch to tiled format'/>"
7928 : " <Option name='TFW' type='boolean' description='Write out world file'/>"
7929 : " <Option name='RPB' type='boolean' description='Write out .RPB (RPC) file'/>"
7930 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
7931 : " <Option name='BLOCKYSIZE' type='int' description='Tile/Strip Height'/>"
7932 : " <Option name='PHOTOMETRIC' type='string-select'>"
7933 : " <Value>MINISBLACK</Value>"
7934 : " <Value>MINISWHITE</Value>"
7935 : " <Value>PALETTE</Value>"
7936 : " <Value>RGB</Value>"
7937 : " <Value>CMYK</Value>"
7938 : " <Value>YCBCR</Value>"
7939 : " <Value>CIELAB</Value>"
7940 : " <Value>ICCLAB</Value>"
7941 : " <Value>ITULAB</Value>"
7942 : " </Option>"
7943 : " <Option name='SPARSE_OK' type='boolean' description='Can newly created files have missing blocks?' default='FALSE'/>"
7944 : " <Option name='ALPHA' type='boolean' description='Mark first extrasample as being alpha'/>"
7945 : " <Option name='PROFILE' type='string-select' default='GDALGeoTIFF'>"
7946 : " <Value>GDALGeoTIFF</Value>"
7947 : " <Value>GeoTIFF</Value>"
7948 : " <Value>BASELINE</Value>"
7949 : " </Option>"
7950 : " <Option name='PIXELTYPE' type='string-select'>"
7951 : " <Value>DEFAULT</Value>"
7952 : " <Value>SIGNEDBYTE</Value>"
7953 : " </Option>"
7954 : #ifdef BIGTIFF_SUPPORT
7955 : " <Option name='BIGTIFF' type='string-select' description='Force creation of BigTIFF file'>"
7956 : " <Value>YES</Value>"
7957 : " <Value>NO</Value>"
7958 : " <Value>IF_NEEDED</Value>"
7959 : " <Value>IF_SAFER</Value>"
7960 : " </Option>"
7961 : #endif
7962 : " <Option name='ENDIANNESS' type='string-select' default='NATIVE' description='Force endianness of created file. For DEBUG purpose mostly'>"
7963 : " <Value>NATIVE</Value>"
7964 : " <Value>INVERTED</Value>"
7965 : " <Value>LITTLE</Value>"
7966 : " <Value>BIG</Value>"
7967 : " </Option>"
7968 392 : "</CreationOptionList>" );
7969 :
7970 : /* -------------------------------------------------------------------- */
7971 : /* Set the driver details. */
7972 : /* -------------------------------------------------------------------- */
7973 392 : poDriver->SetDescription( "GTiff" );
7974 392 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoTIFF" );
7975 392 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_gtiff.html" );
7976 392 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/tiff" );
7977 392 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "tif" );
7978 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
7979 : "Byte UInt16 Int16 UInt32 Int32 Float32 "
7980 392 : "Float64 CInt16 CInt32 CFloat32 CFloat64" );
7981 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
7982 392 : szCreateOptions );
7983 :
7984 392 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
7985 :
7986 392 : poDriver->pfnOpen = GTiffDataset::Open;
7987 392 : poDriver->pfnCreate = GTiffDataset::Create;
7988 392 : poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
7989 392 : poDriver->pfnUnloadDriver = GDALDeregister_GTiff;
7990 392 : poDriver->pfnIdentify = GTiffDataset::Identify;
7991 :
7992 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
7993 : }
7994 409 : }
|