1 : /******************************************************************************
2 : * $Id: geotiff.cpp 18490 2010-01-09 05:44:49Z warmerdam $
3 : *
4 : * Project: GeoTIFF Driver
5 : * Purpose: GDAL GeoTIFF support.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #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 18490 2010-01-09 05:44:49Z warmerdam $");
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 : CPL_C_END
54 :
55 : #define TIFFTAG_GDAL_METADATA 42112
56 : #define TIFFTAG_GDAL_NODATA 42113
57 : #define TIFFTAG_RPCCOEFFICIENT 50844
58 :
59 : #if TIFFLIB_VERSION >= 20081217 && defined(BIGTIFF_SUPPORT)
60 : # define HAVE_UNSETFIELD
61 : #endif
62 :
63 : TIFF* VSI_TIFFOpen(const char* name, const char* mode);
64 :
65 : enum
66 : {
67 : ENDIANNESS_NATIVE,
68 : ENDIANNESS_LITTLE,
69 : ENDIANNESS_BIG
70 : };
71 :
72 : /************************************************************************/
73 : /* ==================================================================== */
74 : /* GTiffDataset */
75 : /* ==================================================================== */
76 : /************************************************************************/
77 :
78 : class GTiffRasterBand;
79 : class GTiffRGBABand;
80 : class GTiffBitmapBand;
81 :
82 : class GTiffDataset : public GDALPamDataset
83 : {
84 : friend class GTiffRasterBand;
85 : friend class GTiffSplitBand;
86 : friend class GTiffRGBABand;
87 : friend class GTiffBitmapBand;
88 : friend class GTiffSplitBitmapBand;
89 : friend class GTiffOddBitsBand;
90 :
91 : TIFF *hTIFF;
92 : GTiffDataset **ppoActiveDSRef;
93 : GTiffDataset *poActiveDS; /* only used in actual base */
94 :
95 : toff_t nDirOffset;
96 : int bBase;
97 : int bCloseTIFFHandle; /* usefull for closing TIFF handle opened by GTIFF_DIR: */
98 :
99 : uint16 nPlanarConfig;
100 : uint16 nSamplesPerPixel;
101 : uint16 nBitsPerSample;
102 : uint32 nRowsPerStrip;
103 : uint16 nPhotometric;
104 : uint16 nSampleFormat;
105 : uint16 nCompression;
106 :
107 : int nBlocksPerBand;
108 :
109 : uint32 nBlockXSize;
110 : uint32 nBlockYSize;
111 :
112 : int nLoadedBlock; /* or tile */
113 : int bLoadedBlockDirty;
114 : GByte *pabyBlockBuf;
115 :
116 : CPLErr LoadBlockBuf( int nBlockId, int bReadFromDisk = TRUE );
117 : CPLErr FlushBlockBuf();
118 :
119 : char *pszProjection;
120 : int bLookedForProjection;
121 :
122 : void LookForProjection();
123 :
124 : double adfGeoTransform[6];
125 : int bGeoTransformValid;
126 :
127 : int bTreatAsRGBA;
128 : int bCrystalized;
129 :
130 : void Crystalize();
131 :
132 : GDALColorTable *poColorTable;
133 :
134 : void WriteGeoTIFFInfo();
135 : int SetDirectory( toff_t nDirOffset = 0 );
136 :
137 : int nOverviewCount;
138 : GTiffDataset **papoOverviewDS;
139 :
140 : int nGCPCount;
141 : GDAL_GCP *pasGCPList;
142 :
143 : int IsBlockAvailable( int nBlockId );
144 :
145 : int bGeoTIFFInfoChanged;
146 : int bNoDataSet;
147 : double dfNoDataValue;
148 :
149 : int bMetadataChanged;
150 :
151 : int bNeedsRewrite;
152 :
153 : void ApplyPamInfo();
154 : void PushMetadataToPam();
155 :
156 : GDALMultiDomainMetadata oGTiffMDMD;
157 :
158 : CPLString osProfile;
159 : char **papszCreationOptions;
160 :
161 : int bLoadingOtherBands;
162 :
163 : static void WriteRPCTag( TIFF *, char ** );
164 : void ReadRPCTag();
165 :
166 : void* pabyTempWriteBuffer;
167 : int nTempWriteBufferSize;
168 : int WriteEncodedTile(uint32 tile, void* data, int bPreserveDataBuffer);
169 : int WriteEncodedStrip(uint32 strip, void* data, int bPreserveDataBuffer);
170 :
171 : GTiffDataset* poMaskDS;
172 : GTiffDataset* poBaseDS;
173 :
174 : CPLString osFilename;
175 :
176 : int bFillEmptyTiles;
177 : void FillEmptyTiles(void);
178 :
179 : void FlushDirectory();
180 : CPLErr CleanOverviews();
181 :
182 : /* Used for the all-in-on-strip case */
183 : int nLastLineRead;
184 : int nLastBandRead;
185 : int bTreatAsSplit;
186 : int bTreatAsSplitBitmap;
187 :
188 : public:
189 : GTiffDataset();
190 : ~GTiffDataset();
191 :
192 : virtual const char *GetProjectionRef(void);
193 : virtual CPLErr SetProjection( const char * );
194 : virtual CPLErr GetGeoTransform( double * );
195 : virtual CPLErr SetGeoTransform( double * );
196 :
197 : virtual int GetGCPCount();
198 : virtual const char *GetGCPProjection();
199 : virtual const GDAL_GCP *GetGCPs();
200 : CPLErr SetGCPs( int, const GDAL_GCP *, const char * );
201 :
202 : virtual char **GetFileList(void);
203 :
204 : virtual CPLErr IBuildOverviews( const char *, int, int *, int, int *,
205 : GDALProgressFunc, void * );
206 :
207 : CPLErr OpenOffset( TIFF *, GTiffDataset **ppoActiveDSRef,
208 : toff_t nDirOffset, int, GDALAccess,
209 : int bAllowRGBAInterface = TRUE);
210 :
211 : static GDALDataset *OpenDir( GDALOpenInfo * );
212 : static GDALDataset *Open( GDALOpenInfo * );
213 : static int Identify( GDALOpenInfo * );
214 : static GDALDataset *Create( const char * pszFilename,
215 : int nXSize, int nYSize, int nBands,
216 : GDALDataType eType, char ** papszParmList );
217 : static GDALDataset *CreateCopy( const char * pszFilename,
218 : GDALDataset *poSrcDS,
219 : int bStrict, char ** papszOptions,
220 : GDALProgressFunc pfnProgress,
221 : void * pProgressData );
222 : virtual void FlushCache( void );
223 :
224 : virtual CPLErr SetMetadata( char **, const char * = "" );
225 : virtual char **GetMetadata( const char * pszDomain = "" );
226 : virtual CPLErr SetMetadataItem( const char*, const char*,
227 : const char* = "" );
228 : virtual const char *GetMetadataItem( const char * pszName,
229 : const char * pszDomain = "" );
230 : virtual void *GetInternalHandle( const char * );
231 :
232 : virtual CPLErr CreateMaskBand( int nFlags );
233 :
234 : // only needed by createcopy and close code.
235 : static int WriteMetadata( GDALDataset *, TIFF *, int, const char *,
236 : const char *, char **, int bExcludeRPBandIMGFileWriting = FALSE );
237 : static void WriteNoDataValue( TIFF *, double );
238 :
239 : static TIFF * CreateLL( const char * pszFilename,
240 : int nXSize, int nYSize, int nBands,
241 : GDALDataType eType, char **papszParmList );
242 :
243 : CPLErr WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data, int bPreserveDataBuffer);
244 : };
245 :
246 : /************************************************************************/
247 : /* ==================================================================== */
248 : /* GTiffRasterBand */
249 : /* ==================================================================== */
250 : /************************************************************************/
251 :
252 : class GTiffRasterBand : public GDALPamRasterBand
253 796090 : {
254 : friend class GTiffDataset;
255 :
256 : GDALColorInterp eBandInterp;
257 :
258 : int bHaveOffsetScale;
259 : double dfOffset;
260 : double dfScale;
261 :
262 : protected:
263 : GTiffDataset *poGDS;
264 : GDALMultiDomainMetadata oGTiffMDMD;
265 :
266 : int bNoDataSet;
267 : double dfNoDataValue;
268 :
269 : void NullBlock( void *pData );
270 :
271 : public:
272 : GTiffRasterBand( GTiffDataset *, int );
273 :
274 : // should override RasterIO eventually.
275 :
276 : virtual CPLErr IReadBlock( int, int, void * );
277 : virtual CPLErr IWriteBlock( int, int, void * );
278 :
279 : virtual GDALColorInterp GetColorInterpretation();
280 : virtual GDALColorTable *GetColorTable();
281 : virtual CPLErr SetColorTable( GDALColorTable * );
282 : virtual double GetNoDataValue( int * );
283 : virtual CPLErr SetNoDataValue( double );
284 :
285 : virtual double GetOffset( int *pbSuccess = NULL );
286 : virtual CPLErr SetOffset( double dfNewValue );
287 : virtual double GetScale( int *pbSuccess = NULL );
288 : virtual CPLErr SetScale( double dfNewValue );
289 : virtual CPLErr SetColorInterpretation( GDALColorInterp );
290 :
291 : virtual CPLErr SetMetadata( char **, const char * = "" );
292 : virtual char **GetMetadata( const char * pszDomain = "" );
293 : virtual CPLErr SetMetadataItem( const char*, const char*,
294 : const char* = "" );
295 : virtual const char *GetMetadataItem( const char * pszName,
296 : const char * pszDomain = "" );
297 : virtual int GetOverviewCount();
298 : virtual GDALRasterBand *GetOverview( int );
299 :
300 : virtual GDALRasterBand *GetMaskBand();
301 : virtual int GetMaskFlags();
302 : virtual CPLErr CreateMaskBand( int nFlags );
303 : };
304 :
305 : /************************************************************************/
306 : /* GTiffRasterBand() */
307 : /************************************************************************/
308 :
309 398206 : GTiffRasterBand::GTiffRasterBand( GTiffDataset *poDS, int nBand )
310 :
311 : {
312 398206 : poGDS = poDS;
313 :
314 398206 : this->poDS = poDS;
315 398206 : this->nBand = nBand;
316 :
317 398206 : bHaveOffsetScale = FALSE;
318 398206 : dfOffset = 0.0;
319 398206 : dfScale = 1.0;
320 :
321 : /* -------------------------------------------------------------------- */
322 : /* Get the GDAL data type. */
323 : /* -------------------------------------------------------------------- */
324 398206 : uint16 nSampleFormat = poDS->nSampleFormat;
325 :
326 398206 : eDataType = GDT_Unknown;
327 :
328 398206 : if( poDS->nBitsPerSample <= 8 )
329 : {
330 395567 : eDataType = GDT_Byte;
331 395567 : if( nSampleFormat == SAMPLEFORMAT_INT )
332 0 : SetMetadataItem( "PIXELTYPE", "SIGNEDBYTE", "IMAGE_STRUCTURE" );
333 :
334 : }
335 2639 : else if( poDS->nBitsPerSample <= 16 )
336 : {
337 592 : if( nSampleFormat == SAMPLEFORMAT_INT )
338 246 : eDataType = GDT_Int16;
339 : else
340 346 : eDataType = GDT_UInt16;
341 : }
342 2047 : else if( poDS->nBitsPerSample == 32 )
343 : {
344 1177 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
345 186 : eDataType = GDT_CInt16;
346 991 : else if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
347 544 : eDataType = GDT_Float32;
348 447 : else if( nSampleFormat == SAMPLEFORMAT_INT )
349 221 : eDataType = GDT_Int32;
350 : else
351 226 : eDataType = GDT_UInt32;
352 : }
353 870 : else if( poDS->nBitsPerSample == 64 )
354 : {
355 601 : if( nSampleFormat == SAMPLEFORMAT_IEEEFP )
356 219 : eDataType = GDT_Float64;
357 382 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
358 197 : eDataType = GDT_CFloat32;
359 185 : else if( nSampleFormat == SAMPLEFORMAT_COMPLEXINT )
360 185 : eDataType = GDT_CInt32;
361 : }
362 269 : else if( poDS->nBitsPerSample == 128 )
363 : {
364 201 : if( nSampleFormat == SAMPLEFORMAT_COMPLEXIEEEFP )
365 201 : eDataType = GDT_CFloat64;
366 : }
367 :
368 : /* -------------------------------------------------------------------- */
369 : /* Try to work out band color interpretation. */
370 : /* -------------------------------------------------------------------- */
371 398280 : if( poDS->poColorTable != NULL && nBand == 1 )
372 74 : eBandInterp = GCI_PaletteIndex;
373 398132 : else if( poDS->nPhotometric == PHOTOMETRIC_RGB
374 : || (poDS->nPhotometric == PHOTOMETRIC_YCBCR
375 : && poDS->nCompression == COMPRESSION_JPEG
376 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
377 : "YES") )) )
378 : {
379 1068 : if( nBand == 1 )
380 335 : eBandInterp = GCI_RedBand;
381 733 : else if( nBand == 2 )
382 335 : eBandInterp = GCI_GreenBand;
383 398 : else if( nBand == 3 )
384 335 : eBandInterp = GCI_BlueBand;
385 : else
386 : {
387 : uint16 *v;
388 63 : uint16 count = 0;
389 :
390 63 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v) )
391 : {
392 109 : if( nBand - 3 <= count && v[nBand-4] == EXTRASAMPLE_ASSOCALPHA )
393 46 : eBandInterp = GCI_AlphaBand;
394 : else
395 17 : eBandInterp = GCI_Undefined;
396 : }
397 0 : else if( nBand == 4 )
398 0 : eBandInterp = GCI_AlphaBand;
399 : else
400 0 : eBandInterp = GCI_Undefined;
401 : }
402 : }
403 397064 : else if( poDS->nPhotometric == PHOTOMETRIC_YCBCR )
404 : {
405 0 : if( nBand == 1 )
406 0 : eBandInterp = GCI_YCbCr_YBand;
407 0 : else if( nBand == 2 )
408 0 : eBandInterp = GCI_YCbCr_CbBand;
409 0 : else if( nBand == 3 )
410 0 : eBandInterp = GCI_YCbCr_CrBand;
411 : else
412 : {
413 : uint16 *v;
414 0 : uint16 count = 0;
415 :
416 0 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v) )
417 : {
418 0 : if( nBand - 3 <= count && v[nBand-4] == EXTRASAMPLE_ASSOCALPHA )
419 0 : eBandInterp = GCI_AlphaBand;
420 : else
421 0 : eBandInterp = GCI_Undefined;
422 : }
423 0 : else if( nBand == 4 )
424 0 : eBandInterp = GCI_AlphaBand;
425 : else
426 0 : eBandInterp = GCI_Undefined;
427 : }
428 : }
429 397064 : else if( poDS->nPhotometric == PHOTOMETRIC_SEPARATED )
430 : {
431 40 : if( nBand == 1 )
432 10 : eBandInterp = GCI_CyanBand;
433 30 : else if( nBand == 2 )
434 10 : eBandInterp = GCI_MagentaBand;
435 20 : else if( nBand == 3 )
436 10 : eBandInterp = GCI_YellowBand;
437 : else
438 10 : eBandInterp = GCI_BlackBand;
439 : }
440 400426 : else if( poDS->nPhotometric == PHOTOMETRIC_MINISBLACK && nBand == 1 )
441 3402 : eBandInterp = GCI_GrayIndex;
442 : else
443 : {
444 : uint16 *v;
445 393622 : uint16 count = 0;
446 :
447 393622 : if( TIFFGetField( poDS->hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v ) )
448 : {
449 : int nBaseSamples;
450 393529 : nBaseSamples = poDS->nSamplesPerPixel - count;
451 :
452 787065 : if( nBand > nBaseSamples
453 393529 : && v[nBand-nBaseSamples-1] == EXTRASAMPLE_ASSOCALPHA )
454 7 : eBandInterp = GCI_AlphaBand;
455 : else
456 393522 : eBandInterp = GCI_Undefined;
457 : }
458 : else
459 93 : eBandInterp = GCI_Undefined;
460 : }
461 :
462 : /* -------------------------------------------------------------------- */
463 : /* Establish block size for strip or tiles. */
464 : /* -------------------------------------------------------------------- */
465 398206 : nBlockXSize = poDS->nBlockXSize;
466 398206 : nBlockYSize = poDS->nBlockYSize;
467 :
468 398206 : bNoDataSet = FALSE;
469 398206 : dfNoDataValue = -9999.0;
470 398206 : }
471 :
472 : /************************************************************************/
473 : /* IReadBlock() */
474 : /************************************************************************/
475 :
476 71441 : CPLErr GTiffRasterBand::IReadBlock( int nBlockXOff, int nBlockYOff,
477 : void * pImage )
478 :
479 : {
480 : int nBlockBufSize, nBlockId, nBlockIdBand0;
481 71441 : CPLErr eErr = CE_None;
482 :
483 71441 : if (!poGDS->SetDirectory())
484 0 : return CE_Failure;
485 :
486 71441 : if( TIFFIsTiled(poGDS->hTIFF) )
487 1089 : nBlockBufSize = TIFFTileSize( poGDS->hTIFF );
488 : else
489 : {
490 : CPLAssert( nBlockXOff == 0 );
491 70352 : nBlockBufSize = TIFFStripSize( poGDS->hTIFF );
492 : }
493 :
494 71441 : nBlockIdBand0 = nBlockXOff + nBlockYOff * nBlocksPerRow;
495 71441 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
496 414 : nBlockId = nBlockIdBand0 + (nBand-1) * poGDS->nBlocksPerBand;
497 : else
498 71027 : nBlockId = nBlockIdBand0;
499 :
500 : /* -------------------------------------------------------------------- */
501 : /* The bottom most partial tiles and strips are sometimes only */
502 : /* partially encoded. This code reduces the requested data so */
503 : /* an error won't be reported in this case. (#1179) */
504 : /* -------------------------------------------------------------------- */
505 71441 : int nBlockReqSize = nBlockBufSize;
506 :
507 71441 : if( (nBlockYOff+1) * nBlockYSize > nRasterYSize )
508 : {
509 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
510 698 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
511 : }
512 :
513 : /* -------------------------------------------------------------------- */
514 : /* Handle the case of a strip or tile that doesn't exist yet. */
515 : /* Just set to zeros and return. */
516 : /* -------------------------------------------------------------------- */
517 71441 : if( !poGDS->IsBlockAvailable(nBlockId) )
518 : {
519 624 : NullBlock( pImage );
520 624 : return CE_None;
521 : }
522 :
523 : /* -------------------------------------------------------------------- */
524 : /* Handle simple case (separate, onesampleperpixel) */
525 : /* -------------------------------------------------------------------- */
526 70817 : if( poGDS->nBands == 1
527 : || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
528 : {
529 2806 : if( nBlockReqSize < nBlockBufSize )
530 191 : memset( pImage, 0, nBlockBufSize );
531 :
532 2806 : if( TIFFIsTiled( poGDS->hTIFF ) )
533 : {
534 503 : if( TIFFReadEncodedTile( poGDS->hTIFF, nBlockId, pImage,
535 : nBlockReqSize ) == -1 )
536 : {
537 0 : memset( pImage, 0, nBlockBufSize );
538 : CPLError( CE_Failure, CPLE_AppDefined,
539 0 : "TIFFReadEncodedTile() failed.\n" );
540 :
541 0 : eErr = CE_Failure;
542 : }
543 : }
544 : else
545 : {
546 2303 : if( TIFFReadEncodedStrip( poGDS->hTIFF, nBlockId, pImage,
547 : nBlockReqSize ) == -1 )
548 : {
549 0 : memset( pImage, 0, nBlockBufSize );
550 : CPLError( CE_Failure, CPLE_AppDefined,
551 0 : "TIFFReadEncodedStrip() failed.\n" );
552 :
553 0 : eErr = CE_Failure;
554 : }
555 : }
556 :
557 2806 : return eErr;
558 : }
559 :
560 : /* -------------------------------------------------------------------- */
561 : /* Load desired block */
562 : /* -------------------------------------------------------------------- */
563 68011 : eErr = poGDS->LoadBlockBuf( nBlockId );
564 68011 : if( eErr != CE_None )
565 : {
566 : memset( pImage, 0,
567 : nBlockXSize * nBlockYSize
568 0 : * (GDALGetDataTypeSize(eDataType) / 8) );
569 0 : return eErr;
570 : }
571 :
572 : /* -------------------------------------------------------------------- */
573 : /* Special case for YCbCr subsampled data. */
574 : /* -------------------------------------------------------------------- */
575 : #ifdef notdef
576 : if( (eBandInterp == GCI_YCbCr_YBand
577 : || eBandInterp == GCI_YCbCr_CbBand
578 : || eBandInterp == GCI_YCbCr_CrBand)
579 : && poGDS->nBitsPerSample == 8 )
580 : {
581 : uint16 hs, vs;
582 : int iX, iY;
583 :
584 : TIFFGetFieldDefaulted( poGDS->hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
585 : &hs, &vs);
586 :
587 : for( iY = 0; iY < nBlockYSize; iY++ )
588 : {
589 : for( iX = 0; iX < nBlockXSize; iX++ )
590 : {
591 : int iBlock = (iY / vs) * (nBlockXSize/hs) + (iX / hs);
592 : GByte *pabySrcBlock = poGDS->pabyBlockBuf +
593 : (vs * hs + 2) * iBlock;
594 :
595 : if( eBandInterp == GCI_YCbCr_YBand )
596 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
597 : pabySrcBlock[(iX % hs) + (iY % vs) * hs];
598 : else if( eBandInterp == GCI_YCbCr_CbBand )
599 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
600 : pabySrcBlock[vs * hs + 0];
601 : else if( eBandInterp == GCI_YCbCr_CrBand )
602 : ((GByte *)pImage)[iY*nBlockXSize + iX] =
603 : pabySrcBlock[vs * hs + 1];
604 : }
605 : }
606 :
607 : return CE_None;
608 : }
609 : #endif
610 :
611 : /* -------------------------------------------------------------------- */
612 : /* Handle simple case of eight bit data, and pixel interleaving. */
613 : /* -------------------------------------------------------------------- */
614 68011 : if( poGDS->nBitsPerSample == 8 )
615 : {
616 : int i, nBlockPixels;
617 : GByte *pabyImage;
618 67872 : GByte *pabyImageDest = (GByte*)pImage;
619 67872 : int nBands = poGDS->nBands;
620 :
621 67872 : pabyImage = poGDS->pabyBlockBuf + nBand - 1;
622 :
623 67872 : nBlockPixels = nBlockXSize * nBlockYSize;
624 :
625 : /* ==================================================================== */
626 : /* Optimization for high number of words to transfer and some */
627 : /* typical band numbers : we unroll the loop. */
628 : /* ==================================================================== */
629 : #define COPY_TO_DST_BUFFER(nBands) \
630 : if (nBlockPixels > 100) \
631 : { \
632 : for ( i = nBlockPixels / 16; i != 0; i -- ) \
633 : { \
634 : pabyImageDest[0] = pabyImage[0*nBands]; \
635 : pabyImageDest[1] = pabyImage[1*nBands]; \
636 : pabyImageDest[2] = pabyImage[2*nBands]; \
637 : pabyImageDest[3] = pabyImage[3*nBands]; \
638 : pabyImageDest[4] = pabyImage[4*nBands]; \
639 : pabyImageDest[5] = pabyImage[5*nBands]; \
640 : pabyImageDest[6] = pabyImage[6*nBands]; \
641 : pabyImageDest[7] = pabyImage[7*nBands]; \
642 : pabyImageDest[8] = pabyImage[8*nBands]; \
643 : pabyImageDest[9] = pabyImage[9*nBands]; \
644 : pabyImageDest[10] = pabyImage[10*nBands]; \
645 : pabyImageDest[11] = pabyImage[11*nBands]; \
646 : pabyImageDest[12] = pabyImage[12*nBands]; \
647 : pabyImageDest[13] = pabyImage[13*nBands]; \
648 : pabyImageDest[14] = pabyImage[14*nBands]; \
649 : pabyImageDest[15] = pabyImage[15*nBands]; \
650 : pabyImageDest += 16; \
651 : pabyImage += 16*nBands; \
652 : } \
653 : nBlockPixels = nBlockPixels % 16; \
654 : } \
655 : for( i = 0; i < nBlockPixels; i++ ) \
656 : { \
657 : pabyImageDest[i] = *pabyImage; \
658 : pabyImage += nBands; \
659 : }
660 :
661 67872 : switch (nBands)
662 : {
663 1848 : case 3: COPY_TO_DST_BUFFER(3); break;
664 428 : case 4: COPY_TO_DST_BUFFER(4); break;
665 : default:
666 : {
667 507407 : for( i = 0; i < nBlockPixels; i++ )
668 : {
669 441811 : pabyImageDest[i] = *pabyImage;
670 441811 : pabyImage += nBands;
671 : }
672 : }
673 : }
674 : }
675 :
676 : else
677 : {
678 : int i, nBlockPixels, nWordBytes;
679 : GByte *pabyImage;
680 :
681 139 : nWordBytes = poGDS->nBitsPerSample / 8;
682 139 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
683 :
684 139 : nBlockPixels = nBlockXSize * nBlockYSize;
685 566627 : for( i = 0; i < nBlockPixels; i++ )
686 : {
687 2866200 : for( int j = 0; j < nWordBytes; j++ )
688 : {
689 2299712 : ((GByte *) pImage)[i*nWordBytes + j] = pabyImage[j];
690 : }
691 566488 : pabyImage += poGDS->nBands * nWordBytes;
692 : }
693 : }
694 :
695 : /* -------------------------------------------------------------------- */
696 : /* In the fairly common case of pixel interleaved 8bit data */
697 : /* that is multi-band, lets push the rest of the data into the */
698 : /* block cache too, to avoid (hopefully) having to redecode it. */
699 : /* */
700 : /* Our following logic actually depends on the fact that the */
701 : /* this block is already loaded, so subsequent calls will end */
702 : /* up back in this method and pull from the loaded block. */
703 : /* */
704 : /* Be careful not entering this portion of code from */
705 : /* the other bands, otherwise we'll get very deep nested calls */
706 : /* and O(nBands^2) performance ! */
707 : /* */
708 : /* If there are many bands and the block cache size is not big */
709 : /* enough to accomodate the size of all the blocks, don't enter */
710 : /* -------------------------------------------------------------------- */
711 68011 : if( poGDS->nBands != 1 && eErr == CE_None && !poGDS->bLoadingOtherBands &&
712 : nBlockXSize * nBlockYSize * (GDALGetDataTypeSize(eDataType) / 8) < GDALGetCacheMax() / poGDS->nBands)
713 : {
714 : int iOtherBand;
715 :
716 804 : poGDS->bLoadingOtherBands = TRUE;
717 :
718 68825 : for( iOtherBand = 1; iOtherBand <= poGDS->nBands; iOtherBand++ )
719 : {
720 68021 : if( iOtherBand == nBand )
721 804 : continue;
722 :
723 : GDALRasterBlock *poBlock;
724 :
725 : poBlock = poGDS->GetRasterBand(iOtherBand)->
726 67217 : GetLockedBlockRef(nBlockXOff,nBlockYOff);
727 67217 : if (poBlock == NULL)
728 : {
729 0 : eErr = CE_Failure;
730 0 : break;
731 : }
732 67217 : poBlock->DropLock();
733 : }
734 :
735 804 : poGDS->bLoadingOtherBands = FALSE;
736 : }
737 :
738 68011 : return eErr;
739 : }
740 :
741 : /************************************************************************/
742 : /* IWriteBlock() */
743 : /************************************************************************/
744 :
745 4622 : CPLErr GTiffRasterBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
746 : void * pImage )
747 :
748 : {
749 : int nBlockId;
750 4622 : CPLErr eErr = CE_None;
751 :
752 4622 : if (!poGDS->SetDirectory())
753 0 : return CE_Failure;
754 :
755 : CPLAssert( poGDS != NULL
756 : && nBlockXOff >= 0
757 : && nBlockYOff >= 0
758 : && pImage != NULL );
759 :
760 : /* -------------------------------------------------------------------- */
761 : /* Handle case of "separate" images */
762 : /* -------------------------------------------------------------------- */
763 4622 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
764 : || poGDS->nBands == 1 )
765 : {
766 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow
767 3930 : + (nBand-1) * poGDS->nBlocksPerBand;
768 :
769 3930 : eErr = poGDS->WriteEncodedTileOrStrip(nBlockId, pImage, TRUE);
770 :
771 3930 : return eErr;
772 : }
773 :
774 : /* -------------------------------------------------------------------- */
775 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
776 : /* -------------------------------------------------------------------- */
777 :
778 692 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
779 :
780 692 : eErr = poGDS->LoadBlockBuf( nBlockId );
781 692 : if( eErr != CE_None )
782 0 : return eErr;
783 :
784 : /* -------------------------------------------------------------------- */
785 : /* On write of pixel interleaved data, we might as well flush */
786 : /* out any other bands that are dirty in our cache. This is */
787 : /* especially helpful when writing compressed blocks. */
788 : /* -------------------------------------------------------------------- */
789 : int iBand;
790 692 : int nWordBytes = poGDS->nBitsPerSample / 8;
791 :
792 2827 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
793 : {
794 2135 : const GByte *pabyThisImage = NULL;
795 2135 : GDALRasterBlock *poBlock = NULL;
796 :
797 2135 : if( iBand+1 == nBand )
798 692 : pabyThisImage = (GByte *) pImage;
799 : else
800 : {
801 : poBlock = ((GTiffRasterBand *)poGDS->GetRasterBand( iBand+1 ))
802 1443 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
803 :
804 1443 : if( poBlock == NULL )
805 116 : continue;
806 :
807 1327 : if( !poBlock->GetDirty() )
808 : {
809 88 : poBlock->DropLock();
810 88 : continue;
811 : }
812 :
813 1239 : pabyThisImage = (GByte *) poBlock->GetDataRef();
814 : }
815 :
816 1931 : int i, nBlockPixels = nBlockXSize * nBlockYSize;
817 1931 : GByte *pabyOut = poGDS->pabyBlockBuf + iBand*nWordBytes;
818 :
819 6692214 : for( i = 0; i < nBlockPixels; i++ )
820 : {
821 6690283 : memcpy( pabyOut, pabyThisImage, nWordBytes );
822 :
823 6690283 : pabyOut += nWordBytes * poGDS->nBands;
824 6690283 : pabyThisImage += nWordBytes;
825 : }
826 :
827 1931 : if( poBlock != NULL )
828 : {
829 1239 : poBlock->MarkClean();
830 1239 : poBlock->DropLock();
831 : }
832 : }
833 :
834 692 : poGDS->bLoadedBlockDirty = TRUE;
835 :
836 692 : return CE_None;
837 : }
838 :
839 : /************************************************************************/
840 : /* GetOffset() */
841 : /************************************************************************/
842 :
843 132891 : double GTiffRasterBand::GetOffset( int *pbSuccess )
844 :
845 : {
846 132891 : if( pbSuccess )
847 132783 : *pbSuccess = bHaveOffsetScale;
848 132891 : return dfOffset;
849 : }
850 :
851 : /************************************************************************/
852 : /* SetOffset() */
853 : /************************************************************************/
854 :
855 0 : CPLErr GTiffRasterBand::SetOffset( double dfNewValue )
856 :
857 : {
858 0 : if( !bHaveOffsetScale || dfNewValue != dfOffset )
859 0 : poGDS->bMetadataChanged = TRUE;
860 :
861 0 : bHaveOffsetScale = TRUE;
862 0 : dfOffset = dfNewValue;
863 0 : return CE_None;
864 : }
865 :
866 : /************************************************************************/
867 : /* GetScale() */
868 : /************************************************************************/
869 :
870 132891 : double GTiffRasterBand::GetScale( int *pbSuccess )
871 :
872 : {
873 132891 : if( pbSuccess )
874 711 : *pbSuccess = bHaveOffsetScale;
875 132891 : return dfScale;
876 : }
877 :
878 : /************************************************************************/
879 : /* SetScale() */
880 : /************************************************************************/
881 :
882 0 : CPLErr GTiffRasterBand::SetScale( double dfNewValue )
883 :
884 : {
885 0 : if( !bHaveOffsetScale || dfNewValue != dfScale )
886 0 : poGDS->bMetadataChanged = TRUE;
887 :
888 0 : bHaveOffsetScale = TRUE;
889 0 : dfScale = dfNewValue;
890 0 : return CE_None;
891 : }
892 :
893 : /************************************************************************/
894 : /* GetMetadata() */
895 : /************************************************************************/
896 :
897 1427 : char **GTiffRasterBand::GetMetadata( const char * pszDomain )
898 :
899 : {
900 1427 : return oGTiffMDMD.GetMetadata( pszDomain );
901 : }
902 :
903 : /************************************************************************/
904 : /* SetMetadata() */
905 : /************************************************************************/
906 :
907 200 : CPLErr GTiffRasterBand::SetMetadata( char ** papszMD, const char *pszDomain )
908 :
909 : {
910 200 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
911 : {
912 200 : if( papszMD != NULL )
913 33 : poGDS->bMetadataChanged = TRUE;
914 : }
915 :
916 200 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
917 : }
918 :
919 : /************************************************************************/
920 : /* GetMetadataItem() */
921 : /************************************************************************/
922 :
923 1448 : const char *GTiffRasterBand::GetMetadataItem( const char * pszName,
924 : const char * pszDomain )
925 :
926 : {
927 1448 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
928 : }
929 :
930 : /************************************************************************/
931 : /* SetMetadataItem() */
932 : /************************************************************************/
933 :
934 460 : CPLErr GTiffRasterBand::SetMetadataItem( const char *pszName,
935 : const char *pszValue,
936 : const char *pszDomain )
937 :
938 : {
939 460 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
940 460 : poGDS->bMetadataChanged = TRUE;
941 :
942 460 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
943 : }
944 :
945 : /************************************************************************/
946 : /* GetColorInterpretation() */
947 : /************************************************************************/
948 :
949 2322 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
950 :
951 : {
952 2322 : return eBandInterp;
953 : }
954 :
955 : /************************************************************************/
956 : /* SetColorInterpretation() */
957 : /************************************************************************/
958 :
959 20 : CPLErr GTiffRasterBand::SetColorInterpretation( GDALColorInterp eInterp )
960 :
961 : {
962 20 : if( eInterp == eBandInterp )
963 12 : return CE_None;
964 :
965 8 : if( poGDS->bCrystalized )
966 0 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
967 :
968 : /* greyscale + alpha */
969 8 : else if( eInterp == GCI_AlphaBand
970 : && nBand == 2
971 : && poGDS->nSamplesPerPixel == 2
972 : && poGDS->nPhotometric == PHOTOMETRIC_MINISBLACK )
973 : {
974 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
975 :
976 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
977 1 : eBandInterp = eInterp;
978 1 : return CE_None;
979 : }
980 :
981 : /* RGB + alpha */
982 7 : else if( eInterp == GCI_AlphaBand
983 : && nBand == 4
984 : && poGDS->nSamplesPerPixel == 4
985 : && poGDS->nPhotometric == PHOTOMETRIC_RGB )
986 : {
987 1 : uint16 v[1] = { EXTRASAMPLE_ASSOCALPHA };
988 :
989 1 : TIFFSetField(poGDS->hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
990 1 : eBandInterp = eInterp;
991 1 : return CE_None;
992 : }
993 :
994 : else
995 6 : return GDALPamRasterBand::SetColorInterpretation( eInterp );
996 : }
997 :
998 : /************************************************************************/
999 : /* GetColorTable() */
1000 : /************************************************************************/
1001 :
1002 1550 : GDALColorTable *GTiffRasterBand::GetColorTable()
1003 :
1004 : {
1005 1550 : if( nBand == 1 )
1006 1240 : return poGDS->poColorTable;
1007 : else
1008 310 : return NULL;
1009 : }
1010 :
1011 : /************************************************************************/
1012 : /* SetColorTable() */
1013 : /************************************************************************/
1014 :
1015 8 : CPLErr GTiffRasterBand::SetColorTable( GDALColorTable * poCT )
1016 :
1017 : {
1018 : /* -------------------------------------------------------------------- */
1019 : /* Check if this is even a candidate for applying a PCT. */
1020 : /* -------------------------------------------------------------------- */
1021 8 : if( poGDS->nSamplesPerPixel != 1 )
1022 : {
1023 : CPLError( CE_Failure, CPLE_NotSupported,
1024 0 : "SetColorTable() not supported for multi-sample TIFF files." );
1025 0 : return CE_Failure;
1026 : }
1027 :
1028 8 : if( eDataType != GDT_Byte && eDataType != GDT_UInt16 )
1029 : {
1030 : CPLError( CE_Failure, CPLE_NotSupported,
1031 0 : "SetColorTable() only supported for Byte or UInt16 bands in TIFF format." );
1032 0 : return CE_Failure;
1033 : }
1034 :
1035 : /* -------------------------------------------------------------------- */
1036 : /* We are careful about calling SetDirectory() to avoid */
1037 : /* prematurely crystalizing the directory. (#2820) */
1038 : /* -------------------------------------------------------------------- */
1039 8 : if( poGDS->bCrystalized )
1040 : {
1041 4 : if (!poGDS->SetDirectory())
1042 0 : return CE_Failure;
1043 : }
1044 :
1045 : /* -------------------------------------------------------------------- */
1046 : /* Is this really a request to clear the color table? */
1047 : /* -------------------------------------------------------------------- */
1048 8 : if( poCT == NULL || poCT->GetColorEntryCount() == 0 )
1049 : {
1050 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC,
1051 1 : PHOTOMETRIC_MINISBLACK );
1052 :
1053 : #ifdef HAVE_UNSETFIELD
1054 1 : TIFFUnsetField( poGDS->hTIFF, TIFFTAG_COLORMAP );
1055 : #else
1056 : CPLDebug( "GTiff",
1057 : "TIFFUnsetField() not supported, colormap may not be cleared." );
1058 : #endif
1059 :
1060 1 : if( poGDS->poColorTable )
1061 : {
1062 1 : delete poGDS->poColorTable;
1063 1 : poGDS->poColorTable = NULL;
1064 : }
1065 :
1066 1 : return CE_None;
1067 : }
1068 :
1069 : /* -------------------------------------------------------------------- */
1070 : /* Write out the colortable, and update the configuration. */
1071 : /* -------------------------------------------------------------------- */
1072 : int nColors;
1073 :
1074 7 : if( eDataType == GDT_Byte )
1075 6 : nColors = 256;
1076 : else
1077 1 : nColors = 65536;
1078 :
1079 : unsigned short *panTRed, *panTGreen, *panTBlue;
1080 :
1081 7 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1082 7 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1083 7 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
1084 :
1085 67079 : for( int iColor = 0; iColor < nColors; iColor++ )
1086 : {
1087 67072 : if( iColor < poCT->GetColorEntryCount() )
1088 : {
1089 : GDALColorEntry sRGB;
1090 :
1091 32 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
1092 :
1093 32 : panTRed[iColor] = (unsigned short) (257 * sRGB.c1);
1094 32 : panTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
1095 32 : panTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
1096 : }
1097 : else
1098 : {
1099 67040 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
1100 : }
1101 : }
1102 :
1103 7 : TIFFSetField( poGDS->hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
1104 : TIFFSetField( poGDS->hTIFF, TIFFTAG_COLORMAP,
1105 7 : panTRed, panTGreen, panTBlue );
1106 :
1107 7 : CPLFree( panTRed );
1108 7 : CPLFree( panTGreen );
1109 7 : CPLFree( panTBlue );
1110 :
1111 7 : if( poGDS->poColorTable )
1112 3 : delete poGDS->poColorTable;
1113 :
1114 : /* libtiff 3.X needs setting this in all cases (creation or update) */
1115 : /* whereas libtiff 4.X would just need it if there */
1116 : /* was no color table before */
1117 : #if 0
1118 : else
1119 : #endif
1120 7 : poGDS->bNeedsRewrite = TRUE;
1121 :
1122 7 : poGDS->poColorTable = poCT->Clone();
1123 :
1124 7 : return CE_None;
1125 : }
1126 :
1127 : /************************************************************************/
1128 : /* GetNoDataValue() */
1129 : /************************************************************************/
1130 :
1131 3215 : double GTiffRasterBand::GetNoDataValue( int * pbSuccess )
1132 :
1133 : {
1134 3215 : if( bNoDataSet )
1135 : {
1136 49 : if( pbSuccess )
1137 40 : *pbSuccess = TRUE;
1138 :
1139 49 : return dfNoDataValue;
1140 : }
1141 :
1142 3166 : if( poGDS->bNoDataSet )
1143 : {
1144 193 : if( pbSuccess )
1145 187 : *pbSuccess = TRUE;
1146 :
1147 193 : return poGDS->dfNoDataValue;
1148 : }
1149 :
1150 2973 : return GDALPamRasterBand::GetNoDataValue( pbSuccess );
1151 : }
1152 :
1153 : /************************************************************************/
1154 : /* SetNoDataValue() */
1155 : /************************************************************************/
1156 :
1157 52 : CPLErr GTiffRasterBand::SetNoDataValue( double dfNoData )
1158 :
1159 : {
1160 52 : if( poGDS->bNoDataSet && poGDS->dfNoDataValue == dfNoData )
1161 14 : return CE_None;
1162 :
1163 38 : if (!poGDS->SetDirectory()) // needed to call TIFFSetField().
1164 0 : return CE_Failure;
1165 :
1166 38 : poGDS->bNoDataSet = TRUE;
1167 38 : poGDS->dfNoDataValue = dfNoData;
1168 :
1169 38 : poGDS->WriteNoDataValue( poGDS->hTIFF, dfNoData );
1170 38 : poGDS->bNeedsRewrite = TRUE;
1171 :
1172 38 : bNoDataSet = TRUE;
1173 38 : dfNoDataValue = dfNoData;
1174 38 : return CE_None;
1175 : }
1176 :
1177 : /************************************************************************/
1178 : /* NullBlock() */
1179 : /* */
1180 : /* Set the block data to the null value if it is set, or zero */
1181 : /* if there is no null data value. */
1182 : /************************************************************************/
1183 :
1184 637 : void GTiffRasterBand::NullBlock( void *pData )
1185 :
1186 : {
1187 637 : int nWords = nBlockXSize * nBlockYSize;
1188 637 : int nChunkSize = MAX(1,GDALGetDataTypeSize(eDataType)/8);
1189 :
1190 : int bNoDataSet;
1191 637 : double dfNoData = GetNoDataValue( &bNoDataSet );
1192 637 : if( !bNoDataSet )
1193 : {
1194 595 : memset( pData, 0, nWords*nChunkSize );
1195 : }
1196 : else
1197 : {
1198 : /* Will convert nodata value to the right type and copy efficiently */
1199 : GDALCopyWords( &dfNoData, GDT_Float64, 0,
1200 42 : pData, eDataType, nChunkSize, nWords);
1201 : }
1202 637 : }
1203 :
1204 : /************************************************************************/
1205 : /* GetOverviewCount() */
1206 : /************************************************************************/
1207 :
1208 299762 : int GTiffRasterBand::GetOverviewCount()
1209 :
1210 : {
1211 299762 : if( poGDS->nOverviewCount > 0 )
1212 608 : return poGDS->nOverviewCount;
1213 : else
1214 299154 : return GDALRasterBand::GetOverviewCount();
1215 : }
1216 :
1217 : /************************************************************************/
1218 : /* GetOverview() */
1219 : /************************************************************************/
1220 :
1221 593 : GDALRasterBand *GTiffRasterBand::GetOverview( int i )
1222 :
1223 : {
1224 593 : if( poGDS->nOverviewCount > 0 )
1225 : {
1226 447 : if( i < 0 || i >= poGDS->nOverviewCount )
1227 0 : return NULL;
1228 : else
1229 447 : return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
1230 : }
1231 : else
1232 146 : return GDALRasterBand::GetOverview( i );
1233 : }
1234 :
1235 : /************************************************************************/
1236 : /* GetMaskFlags() */
1237 : /************************************************************************/
1238 :
1239 1274 : int GTiffRasterBand::GetMaskFlags()
1240 : {
1241 1274 : if( poGDS->poMaskDS != NULL )
1242 : {
1243 : int iBand;
1244 24 : int nMaskFlag = 0;
1245 24 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1246 : {
1247 18 : iBand = 1;
1248 18 : nMaskFlag = GMF_PER_DATASET;
1249 : }
1250 : else
1251 : {
1252 6 : iBand = nBand;
1253 : }
1254 44 : if( poGDS->poMaskDS->GetRasterBand(iBand)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
1255 20 : && atoi(poGDS->poMaskDS->GetRasterBand(iBand)->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) == 1)
1256 : {
1257 20 : return nMaskFlag;
1258 : }
1259 : else
1260 : {
1261 4 : return nMaskFlag | GMF_ALPHA;
1262 : }
1263 : }
1264 : else
1265 1250 : return GDALPamRasterBand::GetMaskFlags();
1266 : }
1267 :
1268 : /************************************************************************/
1269 : /* GetMaskBand() */
1270 : /************************************************************************/
1271 :
1272 445 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
1273 : {
1274 445 : if( poGDS->poMaskDS != NULL )
1275 : {
1276 43 : if( poGDS->poMaskDS->GetRasterCount() == 1)
1277 37 : return poGDS->poMaskDS->GetRasterBand(1);
1278 : else
1279 6 : return poGDS->poMaskDS->GetRasterBand(nBand);
1280 : }
1281 : else
1282 402 : return GDALPamRasterBand::GetMaskBand();
1283 : }
1284 :
1285 : /************************************************************************/
1286 : /* ==================================================================== */
1287 : /* GTiffSplitBand */
1288 : /* ==================================================================== */
1289 : /************************************************************************/
1290 :
1291 : class GTiffSplitBand : public GTiffRasterBand
1292 : {
1293 : friend class GTiffDataset;
1294 :
1295 : public:
1296 :
1297 : GTiffSplitBand( GTiffDataset *, int );
1298 : virtual ~GTiffSplitBand();
1299 :
1300 : virtual CPLErr IReadBlock( int, int, void * );
1301 : virtual CPLErr IWriteBlock( int, int, void * );
1302 : };
1303 :
1304 : /************************************************************************/
1305 : /* GTiffSplitBand() */
1306 : /************************************************************************/
1307 :
1308 24 : GTiffSplitBand::GTiffSplitBand( GTiffDataset *poDS, int nBand )
1309 24 : : GTiffRasterBand( poDS, nBand )
1310 :
1311 : {
1312 24 : nBlockXSize = poDS->GetRasterXSize();
1313 24 : nBlockYSize = 1;
1314 24 : }
1315 :
1316 : /************************************************************************/
1317 : /* ~GTiffSplitBand() */
1318 : /************************************************************************/
1319 :
1320 48 : GTiffSplitBand::~GTiffSplitBand()
1321 : {
1322 48 : }
1323 :
1324 : /************************************************************************/
1325 : /* IReadBlock() */
1326 : /************************************************************************/
1327 :
1328 66144 : CPLErr GTiffSplitBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1329 : void * pImage )
1330 :
1331 : {
1332 : (void) nBlockXOff;
1333 :
1334 : /* Optimization when reading the same line in a contig multi-band TIFF */
1335 66144 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 &&
1336 : poGDS->nLastLineRead == nBlockYOff )
1337 : {
1338 9 : goto extract_band_data;
1339 : }
1340 :
1341 66135 : if (!poGDS->SetDirectory())
1342 0 : return CE_Failure;
1343 :
1344 66135 : if (poGDS->nPlanarConfig == PLANARCONFIG_CONTIG &&
1345 : poGDS->nBands > 1)
1346 : {
1347 36135 : if (poGDS->pabyBlockBuf == NULL)
1348 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
1349 : }
1350 : else
1351 : {
1352 : CPLAssert(TIFFScanlineSize(poGDS->hTIFF) == nBlockXSize);
1353 : }
1354 :
1355 : /* -------------------------------------------------------------------- */
1356 : /* Read through to target scanline. */
1357 : /* -------------------------------------------------------------------- */
1358 66135 : if( poGDS->nLastLineRead >= nBlockYOff )
1359 31 : poGDS->nLastLineRead = -1;
1360 :
1361 66135 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE && poGDS->nBands > 1 )
1362 : {
1363 : /* If we change of band, we must start reading the */
1364 : /* new strip from its beginning */
1365 30000 : if ( poGDS->nLastBandRead != nBand )
1366 20 : poGDS->nLastLineRead = -1;
1367 30000 : poGDS->nLastBandRead = nBand;
1368 : }
1369 :
1370 247718 : while( poGDS->nLastLineRead < nBlockYOff )
1371 : {
1372 115448 : if( TIFFReadScanline( poGDS->hTIFF,
1373 : poGDS->pabyBlockBuf ? poGDS->pabyBlockBuf : pImage,
1374 : ++poGDS->nLastLineRead,
1375 : (poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE) ? nBand-1 : 0 ) == -1 )
1376 : {
1377 : CPLError( CE_Failure, CPLE_AppDefined,
1378 0 : "TIFFReadScanline() failed." );
1379 0 : return CE_Failure;
1380 : }
1381 : }
1382 :
1383 : extract_band_data:
1384 : /* -------------------------------------------------------------------- */
1385 : /* Extract band data from contig buffer. */
1386 : /* -------------------------------------------------------------------- */
1387 66144 : if ( poGDS->pabyBlockBuf != NULL )
1388 : {
1389 36144 : int iPixel, iSrcOffset= nBand - 1, iDstOffset=0;
1390 :
1391 164448 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset+=poGDS->nBands, iDstOffset++ )
1392 : {
1393 128304 : ((GByte *) pImage)[iDstOffset] = poGDS->pabyBlockBuf[iSrcOffset];
1394 : }
1395 : }
1396 :
1397 66144 : return CE_None;
1398 : }
1399 :
1400 : /************************************************************************/
1401 : /* IWriteBlock() */
1402 : /************************************************************************/
1403 :
1404 0 : CPLErr GTiffSplitBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1405 : void * pImage )
1406 :
1407 : {
1408 : (void) nBlockXOff;
1409 : (void) nBlockYOff;
1410 : (void) pImage;
1411 :
1412 : CPLError( CE_Failure, CPLE_AppDefined,
1413 0 : "Split bands are read-only." );
1414 0 : return CE_Failure;
1415 : }
1416 :
1417 : /************************************************************************/
1418 : /* ==================================================================== */
1419 : /* GTiffRGBABand */
1420 : /* ==================================================================== */
1421 : /************************************************************************/
1422 :
1423 : class GTiffRGBABand : public GTiffRasterBand
1424 32 : {
1425 : friend class GTiffDataset;
1426 :
1427 : public:
1428 :
1429 : GTiffRGBABand( GTiffDataset *, int );
1430 :
1431 : virtual CPLErr IReadBlock( int, int, void * );
1432 : virtual CPLErr IWriteBlock( int, int, void * );
1433 :
1434 : virtual GDALColorInterp GetColorInterpretation();
1435 : };
1436 :
1437 :
1438 : /************************************************************************/
1439 : /* GTiffRGBABand() */
1440 : /************************************************************************/
1441 :
1442 16 : GTiffRGBABand::GTiffRGBABand( GTiffDataset *poDS, int nBand )
1443 16 : : GTiffRasterBand( poDS, nBand )
1444 :
1445 : {
1446 16 : eDataType = GDT_Byte;
1447 16 : }
1448 :
1449 : /************************************************************************/
1450 : /* IWriteBlock() */
1451 : /************************************************************************/
1452 :
1453 0 : CPLErr GTiffRGBABand::IWriteBlock( int, int, void * )
1454 :
1455 : {
1456 : CPLError( CE_Failure, CPLE_AppDefined,
1457 0 : "RGBA interpreted raster bands are read-only." );
1458 0 : return CE_Failure;
1459 : }
1460 :
1461 : /************************************************************************/
1462 : /* IReadBlock() */
1463 : /************************************************************************/
1464 :
1465 6 : CPLErr GTiffRGBABand::IReadBlock( int nBlockXOff, int nBlockYOff,
1466 : void * pImage )
1467 :
1468 : {
1469 : int nBlockBufSize, nBlockId;
1470 6 : CPLErr eErr = CE_None;
1471 :
1472 6 : if (!poGDS->SetDirectory())
1473 0 : return CE_Failure;
1474 :
1475 6 : nBlockBufSize = 4 * nBlockXSize * nBlockYSize;
1476 6 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1477 :
1478 : /* -------------------------------------------------------------------- */
1479 : /* Allocate a temporary buffer for this strip. */
1480 : /* -------------------------------------------------------------------- */
1481 6 : if( poGDS->pabyBlockBuf == NULL )
1482 : {
1483 2 : poGDS->pabyBlockBuf = (GByte *) VSIMalloc3( 4, nBlockXSize, nBlockYSize );
1484 2 : if( poGDS->pabyBlockBuf == NULL )
1485 0 : return( CE_Failure );
1486 : }
1487 :
1488 : /* -------------------------------------------------------------------- */
1489 : /* Read the strip */
1490 : /* -------------------------------------------------------------------- */
1491 6 : if( poGDS->nLoadedBlock != nBlockId )
1492 : {
1493 3 : if( TIFFIsTiled( poGDS->hTIFF ) )
1494 : {
1495 0 : if( TIFFReadRGBATile(poGDS->hTIFF,
1496 : nBlockXOff * nBlockXSize,
1497 : nBlockYOff * nBlockYSize,
1498 : (uint32 *) poGDS->pabyBlockBuf) == -1 )
1499 : {
1500 : /* Once TIFFError() is properly hooked, this can go away */
1501 : CPLError( CE_Failure, CPLE_AppDefined,
1502 0 : "TIFFReadRGBATile() failed." );
1503 :
1504 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
1505 :
1506 0 : eErr = CE_Failure;
1507 : }
1508 : }
1509 : else
1510 : {
1511 3 : if( TIFFReadRGBAStrip(poGDS->hTIFF,
1512 : nBlockId * nBlockYSize,
1513 : (uint32 *) poGDS->pabyBlockBuf) == -1 )
1514 : {
1515 : /* Once TIFFError() is properly hooked, this can go away */
1516 : CPLError( CE_Failure, CPLE_AppDefined,
1517 0 : "TIFFReadRGBAStrip() failed." );
1518 :
1519 0 : memset( poGDS->pabyBlockBuf, 0, nBlockBufSize );
1520 :
1521 0 : eErr = CE_Failure;
1522 : }
1523 : }
1524 : }
1525 :
1526 6 : poGDS->nLoadedBlock = nBlockId;
1527 :
1528 : /* -------------------------------------------------------------------- */
1529 : /* Handle simple case of eight bit data, and pixel interleaving. */
1530 : /* -------------------------------------------------------------------- */
1531 : int iDestLine, nBO;
1532 : int nThisBlockYSize;
1533 :
1534 6 : if( (nBlockYOff+1) * nBlockYSize > GetYSize()
1535 : && !TIFFIsTiled( poGDS->hTIFF ) )
1536 1 : nThisBlockYSize = GetYSize() - nBlockYOff * nBlockYSize;
1537 : else
1538 5 : nThisBlockYSize = nBlockYSize;
1539 :
1540 : #ifdef CPL_LSB
1541 6 : nBO = nBand - 1;
1542 : #else
1543 : nBO = 4 - nBand;
1544 : #endif
1545 :
1546 60 : for( iDestLine = 0; iDestLine < nThisBlockYSize; iDestLine++ )
1547 : {
1548 : int nSrcOffset;
1549 :
1550 54 : nSrcOffset = (nThisBlockYSize - iDestLine - 1) * nBlockXSize * 4;
1551 :
1552 : GDALCopyWords( poGDS->pabyBlockBuf + nBO + nSrcOffset, GDT_Byte, 4,
1553 : ((GByte *) pImage)+iDestLine*nBlockXSize, GDT_Byte, 1,
1554 54 : nBlockXSize );
1555 : }
1556 :
1557 6 : return eErr;
1558 : }
1559 :
1560 : /************************************************************************/
1561 : /* GetColorInterpretation() */
1562 : /************************************************************************/
1563 :
1564 5 : GDALColorInterp GTiffRGBABand::GetColorInterpretation()
1565 :
1566 : {
1567 5 : if( nBand == 1 )
1568 2 : return GCI_RedBand;
1569 3 : else if( nBand == 2 )
1570 1 : return GCI_GreenBand;
1571 2 : else if( nBand == 3 )
1572 1 : return GCI_BlueBand;
1573 : else
1574 1 : return GCI_AlphaBand;
1575 : }
1576 :
1577 : /************************************************************************/
1578 : /* ==================================================================== */
1579 : /* GTiffOddBitsBand */
1580 : /* ==================================================================== */
1581 : /************************************************************************/
1582 :
1583 : class GTiffOddBitsBand : public GTiffRasterBand
1584 : {
1585 : friend class GTiffDataset;
1586 : public:
1587 :
1588 : GTiffOddBitsBand( GTiffDataset *, int );
1589 : virtual ~GTiffOddBitsBand();
1590 :
1591 : virtual CPLErr IReadBlock( int, int, void * );
1592 : virtual CPLErr IWriteBlock( int, int, void * );
1593 : };
1594 :
1595 :
1596 : /************************************************************************/
1597 : /* GTiffOddBitsBand() */
1598 : /************************************************************************/
1599 :
1600 276 : GTiffOddBitsBand::GTiffOddBitsBand( GTiffDataset *poGDS, int nBand )
1601 276 : : GTiffRasterBand( poGDS, nBand )
1602 :
1603 : {
1604 276 : eDataType = GDT_Byte;
1605 276 : if( poGDS->nSampleFormat == SAMPLEFORMAT_IEEEFP )
1606 2 : eDataType = GDT_Float32;
1607 357 : else if( poGDS->nBitsPerSample > 8 && poGDS->nBitsPerSample < 16 )
1608 83 : eDataType = GDT_UInt16;
1609 191 : else if( poGDS->nBitsPerSample > 16 )
1610 67 : eDataType = GDT_UInt32;
1611 276 : }
1612 :
1613 : /************************************************************************/
1614 : /* ~GTiffOddBitsBand() */
1615 : /************************************************************************/
1616 :
1617 476 : GTiffOddBitsBand::~GTiffOddBitsBand()
1618 :
1619 : {
1620 476 : }
1621 :
1622 : /************************************************************************/
1623 : /* IWriteBlock() */
1624 : /************************************************************************/
1625 :
1626 63 : CPLErr GTiffOddBitsBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
1627 : void *pImage )
1628 :
1629 : {
1630 : int nBlockId;
1631 63 : CPLErr eErr = CE_None;
1632 :
1633 63 : if (!poGDS->SetDirectory())
1634 0 : return CE_Failure;
1635 :
1636 : CPLAssert( poGDS != NULL
1637 : && nBlockXOff >= 0
1638 : && nBlockYOff >= 0
1639 : && pImage != NULL );
1640 :
1641 63 : if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
1642 : {
1643 : CPLError(CE_Failure, CPLE_NotSupported,
1644 0 : "Writing float data with nBitsPerSample < 32 is unsupported");
1645 0 : return CE_Failure;
1646 : }
1647 :
1648 : /* -------------------------------------------------------------------- */
1649 : /* Load the block buffer. */
1650 : /* -------------------------------------------------------------------- */
1651 63 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1652 :
1653 63 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
1654 14 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
1655 :
1656 : /* Only read content from disk in the CONTIG case */
1657 : eErr = poGDS->LoadBlockBuf( nBlockId,
1658 63 : poGDS->nPlanarConfig == PLANARCONFIG_CONTIG && poGDS->nBands > 1 );
1659 63 : if( eErr != CE_None )
1660 0 : return eErr;
1661 :
1662 : /* -------------------------------------------------------------------- */
1663 : /* Handle case of "separate" images or single band images where */
1664 : /* no interleaving with other data is required. */
1665 : /* -------------------------------------------------------------------- */
1666 63 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE
1667 : || poGDS->nBands == 1 )
1668 : {
1669 47 : int iBit, iPixel, iBitOffset = 0;
1670 : int iX, iY, nBitsPerLine;
1671 :
1672 : // bits per line rounds up to next byte boundary.
1673 47 : nBitsPerLine = nBlockXSize * poGDS->nBitsPerSample;
1674 47 : if( (nBitsPerLine & 7) != 0 )
1675 28 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
1676 :
1677 : /* Initialize to zero as we set the buffer with binary or operations */
1678 47 : if (poGDS->nBitsPerSample != 24)
1679 42 : memset(poGDS->pabyBlockBuf, 0, (nBitsPerLine / 8) * nBlockYSize);
1680 :
1681 47 : iPixel = 0;
1682 9080 : for( iY = 0; iY < nBlockYSize; iY++ )
1683 : {
1684 9033 : iBitOffset = iY * nBitsPerLine;
1685 :
1686 : /* Small optimization in 1 bit case */
1687 9033 : if (poGDS->nBitsPerSample == 1)
1688 : {
1689 7371866 : for( iX = 0; iX < nBlockXSize; iX++ )
1690 : {
1691 7363175 : if (((GByte *) pImage)[iPixel++])
1692 7101782 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1693 7363175 : iBitOffset++;
1694 : }
1695 :
1696 8691 : continue;
1697 : }
1698 :
1699 6344 : for( iX = 0; iX < nBlockXSize; iX++ )
1700 : {
1701 6002 : int nInWord = 0;
1702 6002 : if( eDataType == GDT_Byte )
1703 400 : nInWord = ((GByte *) pImage)[iPixel++];
1704 5602 : else if( eDataType == GDT_UInt16 )
1705 2801 : nInWord = ((GUInt16 *) pImage)[iPixel++];
1706 2801 : else if( eDataType == GDT_UInt32 )
1707 2801 : nInWord = ((GUInt32 *) pImage)[iPixel++];
1708 : else
1709 : CPLAssert(0);
1710 :
1711 :
1712 6002 : if (poGDS->nBitsPerSample == 24)
1713 : {
1714 : /* -------------------------------------------------------------------- */
1715 : /* Special case for 24bit data which is pre-byteswapped since */
1716 : /* the size falls on a byte boundary ... ugg (#2361). */
1717 : /* -------------------------------------------------------------------- */
1718 : #ifdef CPL_MSB
1719 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1720 : (GByte) nInWord;
1721 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1722 : (GByte) (nInWord >> 8);
1723 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1724 : (GByte) (nInWord >> 16);
1725 : #else
1726 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1727 1400 : (GByte) (nInWord >> 16);
1728 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1729 1400 : (GByte) (nInWord >> 8);
1730 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1731 1400 : (GByte) nInWord;
1732 : #endif
1733 1400 : iBitOffset += 24;
1734 : }
1735 : else
1736 : {
1737 59828 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
1738 : {
1739 55226 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
1740 16744 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1741 55226 : iBitOffset++;
1742 : }
1743 : }
1744 : }
1745 : }
1746 :
1747 47 : poGDS->bLoadedBlockDirty = TRUE;
1748 :
1749 47 : return eErr;
1750 : }
1751 :
1752 : /* -------------------------------------------------------------------- */
1753 : /* Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images. */
1754 : /* -------------------------------------------------------------------- */
1755 :
1756 : /* -------------------------------------------------------------------- */
1757 : /* On write of pixel interleaved data, we might as well flush */
1758 : /* out any other bands that are dirty in our cache. This is */
1759 : /* especially helpful when writing compressed blocks. */
1760 : /* -------------------------------------------------------------------- */
1761 : int iBand;
1762 :
1763 54 : for( iBand = 0; iBand < poGDS->nBands; iBand++ )
1764 : {
1765 38 : const GByte *pabyThisImage = NULL;
1766 38 : GDALRasterBlock *poBlock = NULL;
1767 38 : int iBit, iPixel, iBitOffset = 0;
1768 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
1769 :
1770 38 : if( iBand+1 == nBand )
1771 16 : pabyThisImage = (GByte *) pImage;
1772 : else
1773 : {
1774 : poBlock = ((GTiffOddBitsBand *)poGDS->GetRasterBand( iBand+1 ))
1775 22 : ->TryGetLockedBlockRef( nBlockXOff, nBlockYOff );
1776 :
1777 22 : if( poBlock == NULL )
1778 10 : continue;
1779 :
1780 12 : if( !poBlock->GetDirty() )
1781 : {
1782 0 : poBlock->DropLock();
1783 0 : continue;
1784 : }
1785 :
1786 12 : pabyThisImage = (GByte *) poBlock->GetDataRef();
1787 : }
1788 :
1789 28 : iPixelBitSkip = poGDS->nBitsPerSample * poGDS->nBands;
1790 28 : iBandBitOffset = iBand * poGDS->nBitsPerSample;
1791 :
1792 : // bits per line rounds up to next byte boundary.
1793 28 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
1794 28 : if( (nBitsPerLine & 7) != 0 )
1795 15 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
1796 :
1797 28 : iPixel = 0;
1798 671 : for( iY = 0; iY < nBlockYSize; iY++ )
1799 : {
1800 643 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
1801 :
1802 22616 : for( iX = 0; iX < nBlockXSize; iX++ )
1803 : {
1804 21973 : int nInWord = 0;
1805 21973 : if( eDataType == GDT_Byte )
1806 4085 : nInWord = ((GByte *) pabyThisImage)[iPixel++];
1807 17888 : else if( eDataType == GDT_UInt16 )
1808 15088 : nInWord = ((GUInt16 *) pabyThisImage)[iPixel++];
1809 2800 : else if( eDataType == GDT_UInt32 )
1810 2800 : nInWord = ((GUInt32 *) pabyThisImage)[iPixel++];
1811 : else
1812 : CPLAssert(0);
1813 :
1814 :
1815 21973 : if (poGDS->nBitsPerSample == 24)
1816 : {
1817 : /* -------------------------------------------------------------------- */
1818 : /* Special case for 24bit data which is pre-byteswapped since */
1819 : /* the size falls on a byte boundary ... ugg (#2361). */
1820 : /* -------------------------------------------------------------------- */
1821 : #ifdef CPL_MSB
1822 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1823 : (GByte) nInWord;
1824 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1825 : (GByte) (nInWord >> 8);
1826 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1827 : (GByte) (nInWord >> 16);
1828 : #else
1829 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 0] =
1830 1400 : (GByte) (nInWord >> 16);
1831 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 1] =
1832 1400 : (GByte) (nInWord >> 8);
1833 1400 : poGDS->pabyBlockBuf[(iBitOffset>>3) + 2] =
1834 1400 : (GByte) nInWord;
1835 : #endif
1836 1400 : iBitOffset += 24;
1837 : }
1838 : else
1839 : {
1840 248624 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
1841 : {
1842 228051 : if (nInWord & (1 << (poGDS->nBitsPerSample - 1 - iBit)))
1843 101895 : poGDS->pabyBlockBuf[iBitOffset>>3] |= (0x80 >>(iBitOffset & 7));
1844 : else
1845 : {
1846 : /* We must explictly unset the bit as we may update an existing block */
1847 126156 : poGDS->pabyBlockBuf[iBitOffset>>3] &= ~(0x80 >>(iBitOffset & 7));
1848 : }
1849 :
1850 228051 : iBitOffset++;
1851 : }
1852 : }
1853 :
1854 21973 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
1855 : }
1856 : }
1857 :
1858 28 : if( poBlock != NULL )
1859 : {
1860 12 : poBlock->MarkClean();
1861 12 : poBlock->DropLock();
1862 : }
1863 : }
1864 :
1865 16 : poGDS->bLoadedBlockDirty = TRUE;
1866 :
1867 16 : return CE_None;
1868 : }
1869 :
1870 : /************************************************************************/
1871 : /* IReadBlock() */
1872 : /************************************************************************/
1873 :
1874 111 : CPLErr GTiffOddBitsBand::IReadBlock( int nBlockXOff, int nBlockYOff,
1875 : void * pImage )
1876 :
1877 : {
1878 : int nBlockId;
1879 111 : CPLErr eErr = CE_None;
1880 :
1881 111 : if (!poGDS->SetDirectory())
1882 0 : return CE_Failure;
1883 :
1884 111 : nBlockId = nBlockXOff + nBlockYOff * nBlocksPerRow;
1885 :
1886 111 : if( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE )
1887 14 : nBlockId += (nBand-1) * poGDS->nBlocksPerBand;
1888 :
1889 : /* -------------------------------------------------------------------- */
1890 : /* Handle the case of a strip in a writable file that doesn't */
1891 : /* exist yet, but that we want to read. Just set to zeros and */
1892 : /* return. */
1893 : /* -------------------------------------------------------------------- */
1894 111 : if( !poGDS->IsBlockAvailable(nBlockId) )
1895 : {
1896 13 : NullBlock( pImage );
1897 13 : return CE_None;
1898 : }
1899 :
1900 : /* -------------------------------------------------------------------- */
1901 : /* Load the block buffer. */
1902 : /* -------------------------------------------------------------------- */
1903 98 : eErr = poGDS->LoadBlockBuf( nBlockId );
1904 98 : if( eErr != CE_None )
1905 0 : return eErr;
1906 :
1907 128 : if ( poGDS->nBitsPerSample == 1 && (poGDS->nBands == 1 || poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) )
1908 : {
1909 : /* -------------------------------------------------------------------- */
1910 : /* Translate 1bit data to eight bit. */
1911 : /* -------------------------------------------------------------------- */
1912 30 : int iDstOffset=0, iLine;
1913 30 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
1914 :
1915 1845 : for( iLine = 0; iLine < nBlockYSize; iLine++ )
1916 : {
1917 : int iSrcOffset, iPixel;
1918 :
1919 1815 : iSrcOffset = ((nBlockXSize+7) >> 3) * 8 * iLine;
1920 :
1921 202006 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
1922 : {
1923 200191 : if( pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
1924 49875 : ((GByte *) pImage)[iDstOffset++] = 1;
1925 : else
1926 150316 : ((GByte *) pImage)[iDstOffset++] = 0;
1927 : }
1928 : }
1929 : }
1930 : /* -------------------------------------------------------------------- */
1931 : /* Handle the case of 16- and 24-bit floating point data as per */
1932 : /* TIFF Technical Note 3. */
1933 : /* -------------------------------------------------------------------- */
1934 70 : else if( eDataType == GDT_Float32 && poGDS->nBitsPerSample < 32 )
1935 : {
1936 : int i, nBlockPixels, nWordBytes, iSkipBytes;
1937 : GByte *pabyImage;
1938 :
1939 2 : nWordBytes = poGDS->nBitsPerSample / 8;
1940 2 : pabyImage = poGDS->pabyBlockBuf + (nBand - 1) * nWordBytes;
1941 : iSkipBytes = ( poGDS->nPlanarConfig == PLANARCONFIG_SEPARATE ) ?
1942 2 : nWordBytes : poGDS->nBands * nWordBytes;
1943 :
1944 2 : nBlockPixels = nBlockXSize * nBlockYSize;
1945 2 : if ( poGDS->nBitsPerSample == 16 )
1946 : {
1947 401 : for( i = 0; i < nBlockPixels; i++ )
1948 : {
1949 400 : ((GUInt32 *) pImage)[i] =
1950 400 : HalfToFloat( *((GUInt16 *)pabyImage) );
1951 400 : pabyImage += iSkipBytes;
1952 : }
1953 : }
1954 1 : else if ( poGDS->nBitsPerSample == 24 )
1955 : {
1956 401 : for( i = 0; i < nBlockPixels; i++ )
1957 : {
1958 : #ifdef CPL_MSB
1959 : ((GUInt32 *) pImage)[i] =
1960 : TripleToFloat( ((GUInt32)*(pabyImage + 0) << 16)
1961 : | ((GUInt32)*(pabyImage + 1) << 8)
1962 : | (GUInt32)*(pabyImage + 2) );
1963 : #else
1964 400 : ((GUInt32 *) pImage)[i] =
1965 : TripleToFloat( ((GUInt32)*(pabyImage + 2) << 16)
1966 : | ((GUInt32)*(pabyImage + 1) << 8)
1967 400 : | (GUInt32)*pabyImage );
1968 : #endif
1969 400 : pabyImage += iSkipBytes;
1970 : }
1971 : }
1972 : }
1973 :
1974 : /* -------------------------------------------------------------------- */
1975 : /* Special case for moving 12bit data somewhat more efficiently. */
1976 : /* -------------------------------------------------------------------- */
1977 66 : else if( poGDS->nBitsPerSample == 12 )
1978 : {
1979 16 : int iPixel, iBitOffset = 0;
1980 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
1981 :
1982 16 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
1983 : {
1984 13 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
1985 13 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
1986 : }
1987 : else
1988 : {
1989 3 : iPixelBitSkip = poGDS->nBitsPerSample;
1990 3 : iBandBitOffset = 0;
1991 : }
1992 :
1993 : // bits per line rounds up to next byte boundary.
1994 16 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
1995 16 : if( (nBitsPerLine & 7) != 0 )
1996 0 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
1997 :
1998 16 : iPixel = 0;
1999 516 : for( iY = 0; iY < nBlockYSize; iY++ )
2000 : {
2001 500 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2002 :
2003 24180 : for( iX = 0; iX < nBlockXSize; iX++ )
2004 : {
2005 23680 : int iByte = iBitOffset>>3;
2006 :
2007 23680 : if( (iBitOffset & 0x7) == 0 )
2008 : {
2009 : /* starting on byte boundary */
2010 :
2011 23880 : ((GUInt16 *) pImage)[iPixel++] =
2012 11940 : (poGDS->pabyBlockBuf[iByte] << 4)
2013 11940 : | (poGDS->pabyBlockBuf[iByte+1] >> 4);
2014 : }
2015 : else
2016 : {
2017 : /* starting off byte boundary */
2018 :
2019 23480 : ((GUInt16 *) pImage)[iPixel++] =
2020 11740 : ((poGDS->pabyBlockBuf[iByte] & 0xf) << 8)
2021 11740 : | (poGDS->pabyBlockBuf[iByte+1]);
2022 : }
2023 23680 : iBitOffset += iPixelBitSkip;
2024 : }
2025 : }
2026 : }
2027 :
2028 : /* -------------------------------------------------------------------- */
2029 : /* Special case for 24bit data which is pre-byteswapped since */
2030 : /* the size falls on a byte boundary ... ugg (#2361). */
2031 : /* -------------------------------------------------------------------- */
2032 50 : else if( poGDS->nBitsPerSample == 24 )
2033 : {
2034 : int iPixel;
2035 : int iPixelByteSkip, iBandByteOffset, iX, iY, nBytesPerLine;
2036 :
2037 11 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2038 : {
2039 8 : iPixelByteSkip = (poGDS->nBands * poGDS->nBitsPerSample) / 8;
2040 8 : iBandByteOffset = ((nBand-1) * poGDS->nBitsPerSample) / 8;
2041 : }
2042 : else
2043 : {
2044 3 : iPixelByteSkip = poGDS->nBitsPerSample / 8;
2045 3 : iBandByteOffset = 0;
2046 : }
2047 :
2048 11 : nBytesPerLine = nBlockXSize * iPixelByteSkip;
2049 :
2050 11 : iPixel = 0;
2051 191 : for( iY = 0; iY < nBlockYSize; iY++ )
2052 : {
2053 : GByte *pabyImage =
2054 180 : poGDS->pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
2055 :
2056 3380 : for( iX = 0; iX < nBlockXSize; iX++ )
2057 : {
2058 : #ifdef CPL_MSB
2059 : ((GUInt32 *) pImage)[iPixel++] =
2060 : ((GUInt32)*(pabyImage + 2) << 16)
2061 : | ((GUInt32)*(pabyImage + 1) << 8)
2062 : | (GUInt32)*(pabyImage + 0);
2063 : #else
2064 6400 : ((GUInt32 *) pImage)[iPixel++] =
2065 : ((GUInt32)*(pabyImage + 0) << 16)
2066 : | ((GUInt32)*(pabyImage + 1) << 8)
2067 3200 : | (GUInt32)*(pabyImage + 2);
2068 : #endif
2069 3200 : pabyImage += iPixelByteSkip;
2070 : }
2071 : }
2072 : }
2073 :
2074 : /* -------------------------------------------------------------------- */
2075 : /* Handle 1-32 bit integer data. */
2076 : /* -------------------------------------------------------------------- */
2077 : else
2078 : {
2079 39 : int iBit, iPixel, iBitOffset = 0;
2080 : int iPixelBitSkip, iBandBitOffset, iX, iY, nBitsPerLine;
2081 :
2082 39 : if( poGDS->nPlanarConfig == PLANARCONFIG_CONTIG )
2083 : {
2084 33 : iPixelBitSkip = poGDS->nBands * poGDS->nBitsPerSample;
2085 33 : iBandBitOffset = (nBand-1) * poGDS->nBitsPerSample;
2086 : }
2087 : else
2088 : {
2089 6 : iPixelBitSkip = poGDS->nBitsPerSample;
2090 6 : iBandBitOffset = 0;
2091 : }
2092 :
2093 : // bits per line rounds up to next byte boundary.
2094 39 : nBitsPerLine = nBlockXSize * iPixelBitSkip;
2095 39 : if( (nBitsPerLine & 7) != 0 )
2096 38 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
2097 :
2098 39 : register GByte *pabyBlockBuf = poGDS->pabyBlockBuf;
2099 39 : iPixel = 0;
2100 :
2101 1285 : for( iY = 0; iY < nBlockYSize; iY++ )
2102 : {
2103 1246 : iBitOffset = iBandBitOffset + iY * nBitsPerLine;
2104 :
2105 81540 : for( iX = 0; iX < nBlockXSize; iX++ )
2106 : {
2107 80294 : int nOutWord = 0;
2108 :
2109 256322 : for( iBit = 0; iBit < poGDS->nBitsPerSample; iBit++ )
2110 : {
2111 176028 : if( pabyBlockBuf[iBitOffset>>3]
2112 : & (0x80 >>(iBitOffset & 7)) )
2113 77543 : nOutWord |= (1 << (poGDS->nBitsPerSample - 1 - iBit));
2114 176028 : iBitOffset++;
2115 : }
2116 :
2117 80294 : iBitOffset= iBitOffset + iPixelBitSkip - poGDS->nBitsPerSample;
2118 :
2119 80294 : if( eDataType == GDT_Byte )
2120 74292 : ((GByte *) pImage)[iPixel++] = (GByte) nOutWord;
2121 6002 : else if( eDataType == GDT_UInt16 )
2122 3201 : ((GUInt16 *) pImage)[iPixel++] = (GUInt16) nOutWord;
2123 2801 : else if( eDataType == GDT_UInt32 )
2124 2801 : ((GUInt32 *) pImage)[iPixel++] = nOutWord;
2125 : else
2126 : CPLAssert(0);
2127 : }
2128 : }
2129 : }
2130 :
2131 98 : return CE_None;
2132 : }
2133 :
2134 :
2135 : /************************************************************************/
2136 : /* ==================================================================== */
2137 : /* GTiffBitmapBand */
2138 : /* ==================================================================== */
2139 : /************************************************************************/
2140 :
2141 : class GTiffBitmapBand : public GTiffOddBitsBand
2142 : {
2143 : friend class GTiffDataset;
2144 :
2145 : GDALColorTable *poColorTable;
2146 :
2147 : public:
2148 :
2149 : GTiffBitmapBand( GTiffDataset *, int );
2150 : virtual ~GTiffBitmapBand();
2151 :
2152 : virtual GDALColorInterp GetColorInterpretation();
2153 : virtual GDALColorTable *GetColorTable();
2154 : };
2155 :
2156 :
2157 : /************************************************************************/
2158 : /* GTiffBitmapBand() */
2159 : /************************************************************************/
2160 :
2161 76 : GTiffBitmapBand::GTiffBitmapBand( GTiffDataset *poDS, int nBand )
2162 76 : : GTiffOddBitsBand( poDS, nBand )
2163 :
2164 : {
2165 76 : eDataType = GDT_Byte;
2166 :
2167 76 : if( poDS->poColorTable != NULL )
2168 17 : poColorTable = poDS->poColorTable->Clone();
2169 : else
2170 : {
2171 : GDALColorEntry oWhite, oBlack;
2172 :
2173 59 : oWhite.c1 = 255;
2174 59 : oWhite.c2 = 255;
2175 59 : oWhite.c3 = 255;
2176 59 : oWhite.c4 = 255;
2177 :
2178 59 : oBlack.c1 = 0;
2179 59 : oBlack.c2 = 0;
2180 59 : oBlack.c3 = 0;
2181 59 : oBlack.c4 = 255;
2182 :
2183 59 : poColorTable = new GDALColorTable();
2184 :
2185 59 : if( poDS->nPhotometric == PHOTOMETRIC_MINISWHITE )
2186 : {
2187 0 : poColorTable->SetColorEntry( 0, &oWhite );
2188 0 : poColorTable->SetColorEntry( 1, &oBlack );
2189 : }
2190 : else
2191 : {
2192 59 : poColorTable->SetColorEntry( 0, &oBlack );
2193 59 : poColorTable->SetColorEntry( 1, &oWhite );
2194 : }
2195 : }
2196 76 : }
2197 :
2198 : /************************************************************************/
2199 : /* ~GTiffBitmapBand() */
2200 : /************************************************************************/
2201 :
2202 148 : GTiffBitmapBand::~GTiffBitmapBand()
2203 :
2204 : {
2205 76 : delete poColorTable;
2206 148 : }
2207 :
2208 : /************************************************************************/
2209 : /* GetColorInterpretation() */
2210 : /************************************************************************/
2211 :
2212 8 : GDALColorInterp GTiffBitmapBand::GetColorInterpretation()
2213 :
2214 : {
2215 8 : return GCI_PaletteIndex;
2216 : }
2217 :
2218 : /************************************************************************/
2219 : /* GetColorTable() */
2220 : /************************************************************************/
2221 :
2222 10 : GDALColorTable *GTiffBitmapBand::GetColorTable()
2223 :
2224 : {
2225 10 : return poColorTable;
2226 : }
2227 :
2228 : /************************************************************************/
2229 : /* ==================================================================== */
2230 : /* GTiffSplitBitmapBand */
2231 : /* ==================================================================== */
2232 : /************************************************************************/
2233 :
2234 : class GTiffSplitBitmapBand : public GTiffBitmapBand
2235 : {
2236 : friend class GTiffDataset;
2237 :
2238 : public:
2239 :
2240 : GTiffSplitBitmapBand( GTiffDataset *, int );
2241 : virtual ~GTiffSplitBitmapBand();
2242 :
2243 : virtual CPLErr IReadBlock( int, int, void * );
2244 : virtual CPLErr IWriteBlock( int, int, void * );
2245 : };
2246 :
2247 :
2248 : /************************************************************************/
2249 : /* GTiffSplitBitmapBand() */
2250 : /************************************************************************/
2251 :
2252 4 : GTiffSplitBitmapBand::GTiffSplitBitmapBand( GTiffDataset *poDS, int nBand )
2253 4 : : GTiffBitmapBand( poDS, nBand )
2254 :
2255 : {
2256 4 : nBlockXSize = poDS->GetRasterXSize();
2257 4 : nBlockYSize = 1;
2258 4 : }
2259 :
2260 : /************************************************************************/
2261 : /* ~GTiffSplitBitmapBand() */
2262 : /************************************************************************/
2263 :
2264 8 : GTiffSplitBitmapBand::~GTiffSplitBitmapBand()
2265 :
2266 : {
2267 8 : }
2268 :
2269 :
2270 : /************************************************************************/
2271 : /* IReadBlock() */
2272 : /************************************************************************/
2273 :
2274 21600 : CPLErr GTiffSplitBitmapBand::IReadBlock( int nBlockXOff, int nBlockYOff,
2275 : void * pImage )
2276 :
2277 : {
2278 : (void) nBlockXOff;
2279 :
2280 21600 : if (!poGDS->SetDirectory())
2281 0 : return CE_Failure;
2282 :
2283 21600 : if (poGDS->pabyBlockBuf == NULL)
2284 3 : poGDS->pabyBlockBuf = (GByte *) CPLMalloc(TIFFScanlineSize(poGDS->hTIFF));
2285 :
2286 : /* -------------------------------------------------------------------- */
2287 : /* Read through to target scanline. */
2288 : /* -------------------------------------------------------------------- */
2289 21600 : if( poGDS->nLastLineRead >= nBlockYOff )
2290 0 : poGDS->nLastLineRead = -1;
2291 :
2292 64800 : while( poGDS->nLastLineRead < nBlockYOff )
2293 : {
2294 21600 : if( TIFFReadScanline( poGDS->hTIFF, poGDS->pabyBlockBuf, ++poGDS->nLastLineRead, 0 ) == -1 )
2295 : {
2296 : CPLError( CE_Failure, CPLE_AppDefined,
2297 0 : "TIFFReadScanline() failed." );
2298 0 : return CE_Failure;
2299 : }
2300 : }
2301 :
2302 : /* -------------------------------------------------------------------- */
2303 : /* Translate 1bit data to eight bit. */
2304 : /* -------------------------------------------------------------------- */
2305 21600 : int iPixel, iSrcOffset=0, iDstOffset=0;
2306 :
2307 21621600 : for( iPixel = 0; iPixel < nBlockXSize; iPixel++, iSrcOffset++ )
2308 : {
2309 21600000 : if( poGDS->pabyBlockBuf[iSrcOffset >>3] & (0x80 >> (iSrcOffset & 0x7)) )
2310 21243630 : ((GByte *) pImage)[iDstOffset++] = 1;
2311 : else
2312 356370 : ((GByte *) pImage)[iDstOffset++] = 0;
2313 : }
2314 :
2315 21600 : return CE_None;
2316 : }
2317 :
2318 : /************************************************************************/
2319 : /* IWriteBlock() */
2320 : /************************************************************************/
2321 :
2322 0 : CPLErr GTiffSplitBitmapBand::IWriteBlock( int nBlockXOff, int nBlockYOff,
2323 : void * pImage )
2324 :
2325 : {
2326 : (void) nBlockXOff;
2327 : (void) nBlockYOff;
2328 : (void) pImage;
2329 :
2330 : CPLError( CE_Failure, CPLE_AppDefined,
2331 0 : "Split bitmap bands are read-only." );
2332 0 : return CE_Failure;
2333 : }
2334 :
2335 : /************************************************************************/
2336 : /* ==================================================================== */
2337 : /* GTiffDataset */
2338 : /* ==================================================================== */
2339 : /************************************************************************/
2340 :
2341 :
2342 : /************************************************************************/
2343 : /* GTiffDataset() */
2344 : /************************************************************************/
2345 :
2346 3880 : GTiffDataset::GTiffDataset()
2347 :
2348 : {
2349 3880 : nLoadedBlock = -1;
2350 3880 : bLoadedBlockDirty = FALSE;
2351 3880 : pabyBlockBuf = NULL;
2352 3880 : hTIFF = NULL;
2353 3880 : bNeedsRewrite = FALSE;
2354 3880 : bMetadataChanged = FALSE;
2355 3880 : bGeoTIFFInfoChanged = FALSE;
2356 3880 : bCrystalized = TRUE;
2357 3880 : poColorTable = NULL;
2358 3880 : bNoDataSet = FALSE;
2359 3880 : dfNoDataValue = -9999.0;
2360 3880 : pszProjection = CPLStrdup("");
2361 3880 : bLookedForProjection = FALSE;
2362 3880 : bBase = TRUE;
2363 3880 : bCloseTIFFHandle = FALSE;
2364 3880 : bTreatAsRGBA = FALSE;
2365 3880 : nOverviewCount = 0;
2366 3880 : papoOverviewDS = NULL;
2367 3880 : nDirOffset = 0;
2368 3880 : poActiveDS = NULL;
2369 3880 : ppoActiveDSRef = NULL;
2370 :
2371 3880 : bGeoTransformValid = FALSE;
2372 3880 : adfGeoTransform[0] = 0.0;
2373 3880 : adfGeoTransform[1] = 1.0;
2374 3880 : adfGeoTransform[2] = 0.0;
2375 3880 : adfGeoTransform[3] = 0.0;
2376 3880 : adfGeoTransform[4] = 0.0;
2377 3880 : adfGeoTransform[5] = 1.0;
2378 :
2379 3880 : nGCPCount = 0;
2380 3880 : pasGCPList = NULL;
2381 :
2382 3880 : osProfile = "GDALGeoTIFF";
2383 :
2384 3880 : papszCreationOptions = NULL;
2385 :
2386 3880 : nTempWriteBufferSize = 0;
2387 3880 : pabyTempWriteBuffer = NULL;
2388 :
2389 3880 : poMaskDS = NULL;
2390 3880 : poBaseDS = NULL;
2391 :
2392 3880 : bFillEmptyTiles = FALSE;
2393 3880 : bLoadingOtherBands = FALSE;
2394 3880 : nLastLineRead = -1;
2395 3880 : nLastBandRead = -1;
2396 3880 : bTreatAsSplit = FALSE;
2397 3880 : bTreatAsSplitBitmap = FALSE;
2398 3880 : }
2399 :
2400 : /************************************************************************/
2401 : /* ~GTiffDataset() */
2402 : /************************************************************************/
2403 :
2404 7758 : GTiffDataset::~GTiffDataset()
2405 :
2406 : {
2407 3879 : Crystalize();
2408 :
2409 : /* -------------------------------------------------------------------- */
2410 : /* Ensure any blocks write cached by GDAL gets pushed through libtiff.*/
2411 : /* -------------------------------------------------------------------- */
2412 3879 : GDALPamDataset::FlushCache();
2413 :
2414 : /* -------------------------------------------------------------------- */
2415 : /* Fill in missing blocks with empty data. */
2416 : /* -------------------------------------------------------------------- */
2417 3879 : if( bFillEmptyTiles )
2418 : {
2419 678 : FillEmptyTiles();
2420 678 : bFillEmptyTiles = FALSE;
2421 : }
2422 :
2423 : /* -------------------------------------------------------------------- */
2424 : /* Force a complete flush, including either rewriting(moving) */
2425 : /* of writing in place the current directory. */
2426 : /* -------------------------------------------------------------------- */
2427 3879 : FlushCache();
2428 :
2429 : /* -------------------------------------------------------------------- */
2430 : /* If there is still changed metadata, then presumably we want */
2431 : /* to push it into PAM. */
2432 : /* -------------------------------------------------------------------- */
2433 3879 : if( bMetadataChanged )
2434 : {
2435 14 : PushMetadataToPam();
2436 14 : bMetadataChanged = FALSE;
2437 14 : GDALPamDataset::FlushCache();
2438 : }
2439 :
2440 : /* -------------------------------------------------------------------- */
2441 : /* Cleanup overviews. */
2442 : /* -------------------------------------------------------------------- */
2443 3879 : if( bBase )
2444 : {
2445 3770 : for( int i = 0; i < nOverviewCount; i++ )
2446 : {
2447 229 : delete papoOverviewDS[i];
2448 : }
2449 : }
2450 :
2451 : /* If we are a mask dataset, we can have overviews, but we don't */
2452 : /* own them. We can only free the array, not the overviews themselves */
2453 3879 : CPLFree( papoOverviewDS );
2454 :
2455 : /* poMaskDS is owned by the main image and the overviews */
2456 : /* so because of the latter case, we can delete it even if */
2457 : /* we are not the base image */
2458 3879 : if (poMaskDS)
2459 57 : delete poMaskDS;
2460 :
2461 3879 : if( poColorTable != NULL )
2462 77 : delete poColorTable;
2463 :
2464 3879 : if( bBase || bCloseTIFFHandle )
2465 : {
2466 3545 : XTIFFClose( hTIFF );
2467 : }
2468 :
2469 3879 : if( nGCPCount > 0 )
2470 : {
2471 39 : GDALDeinitGCPs( nGCPCount, pasGCPList );
2472 39 : CPLFree( pasGCPList );
2473 : }
2474 :
2475 3879 : CPLFree( pszProjection );
2476 :
2477 3879 : CSLDestroy( papszCreationOptions );
2478 :
2479 3879 : CPLFree(pabyTempWriteBuffer);
2480 :
2481 3879 : if( *ppoActiveDSRef == this )
2482 3657 : *ppoActiveDSRef = NULL;
2483 7758 : }
2484 :
2485 : /************************************************************************/
2486 : /* FillEmptyTiles() */
2487 : /************************************************************************/
2488 :
2489 678 : void GTiffDataset::FillEmptyTiles()
2490 :
2491 : {
2492 678 : toff_t *panByteCounts = NULL;
2493 : int nBlockCount, iBlock;
2494 :
2495 678 : if (!SetDirectory())
2496 0 : return;
2497 :
2498 : /* -------------------------------------------------------------------- */
2499 : /* How many blocks are there in this file? */
2500 : /* -------------------------------------------------------------------- */
2501 678 : if( nPlanarConfig == PLANARCONFIG_SEPARATE )
2502 4 : nBlockCount = nBlocksPerBand * nBands;
2503 : else
2504 674 : nBlockCount = nBlocksPerBand;
2505 :
2506 : /* -------------------------------------------------------------------- */
2507 : /* Fetch block maps. */
2508 : /* -------------------------------------------------------------------- */
2509 678 : if( TIFFIsTiled( hTIFF ) )
2510 8 : TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts );
2511 : else
2512 670 : TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts );
2513 :
2514 : /* -------------------------------------------------------------------- */
2515 : /* Prepare a blank data buffer to write for uninitialized blocks. */
2516 : /* -------------------------------------------------------------------- */
2517 : int nBlockBytes;
2518 :
2519 678 : if( TIFFIsTiled( hTIFF ) )
2520 8 : nBlockBytes = TIFFTileSize(hTIFF);
2521 : else
2522 670 : nBlockBytes = TIFFStripSize(hTIFF);
2523 :
2524 678 : GByte *pabyData = (GByte *) VSICalloc(nBlockBytes,1);
2525 678 : if (pabyData == NULL)
2526 : {
2527 : CPLError(CE_Failure, CPLE_OutOfMemory,
2528 0 : "Cannot allocate %d bytes", nBlockBytes);
2529 0 : return;
2530 : }
2531 :
2532 : /* -------------------------------------------------------------------- */
2533 : /* Check all blocks, writing out data for uninitialized blocks. */
2534 : /* -------------------------------------------------------------------- */
2535 72193 : for( iBlock = 0; iBlock < nBlockCount; iBlock++ )
2536 : {
2537 71515 : if( panByteCounts[iBlock] == 0 )
2538 69792 : WriteEncodedTileOrStrip( iBlock, pabyData, FALSE );
2539 : }
2540 :
2541 678 : CPLFree( pabyData );
2542 : }
2543 :
2544 : /************************************************************************/
2545 : /* WriteEncodedTile() */
2546 : /************************************************************************/
2547 :
2548 552 : int GTiffDataset::WriteEncodedTile(uint32 tile, void* data,
2549 : int bPreserveDataBuffer)
2550 : {
2551 : /* TIFFWriteEncodedTile can alter the passed buffer if byte-swapping is necessary */
2552 : /* so we use a temporary buffer before calling it */
2553 552 : int cc = TIFFTileSize( hTIFF );
2554 552 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
2555 : {
2556 38 : if (cc != nTempWriteBufferSize)
2557 : {
2558 19 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
2559 19 : nTempWriteBufferSize = cc;
2560 : }
2561 38 : memcpy(pabyTempWriteBuffer, data, cc);
2562 38 : return TIFFWriteEncodedTile(hTIFF, tile, pabyTempWriteBuffer, cc);
2563 : }
2564 : else
2565 514 : return TIFFWriteEncodedTile(hTIFF, tile, data, cc);
2566 : }
2567 :
2568 : /************************************************************************/
2569 : /* WriteEncodedStrip() */
2570 : /************************************************************************/
2571 :
2572 73925 : int GTiffDataset::WriteEncodedStrip(uint32 strip, void* data,
2573 : int bPreserveDataBuffer)
2574 : {
2575 73925 : int cc = TIFFStripSize( hTIFF );
2576 :
2577 : /* -------------------------------------------------------------------- */
2578 : /* If this is the last strip in the image, and is partial, then */
2579 : /* we need to trim the number of scanlines written to the */
2580 : /* amount of valid data we have. (#2748) */
2581 : /* -------------------------------------------------------------------- */
2582 73925 : int nStripWithinBand = strip % nBlocksPerBand;
2583 :
2584 73925 : if( (int) ((nStripWithinBand+1) * nRowsPerStrip) > GetRasterYSize() )
2585 : {
2586 : cc = (cc / nRowsPerStrip)
2587 61 : * (GetRasterYSize() - nStripWithinBand * nRowsPerStrip);
2588 : CPLDebug( "GTiff", "Adjusted bytes to write from %d to %d.",
2589 61 : (int) TIFFStripSize(hTIFF), cc );
2590 : }
2591 :
2592 : /* -------------------------------------------------------------------- */
2593 : /* TIFFWriteEncodedStrip can alter the passed buffer if */
2594 : /* byte-swapping is necessary so we use a temporary buffer */
2595 : /* before calling it. */
2596 : /* -------------------------------------------------------------------- */
2597 73925 : if (bPreserveDataBuffer && TIFFIsByteSwapped(hTIFF))
2598 : {
2599 23 : if (cc != nTempWriteBufferSize)
2600 : {
2601 19 : pabyTempWriteBuffer = CPLRealloc(pabyTempWriteBuffer, cc);
2602 19 : nTempWriteBufferSize = cc;
2603 : }
2604 23 : memcpy(pabyTempWriteBuffer, data, cc);
2605 23 : return TIFFWriteEncodedStrip(hTIFF, strip, pabyTempWriteBuffer, cc);
2606 : }
2607 : else
2608 73902 : return TIFFWriteEncodedStrip(hTIFF, strip, data, cc);
2609 : }
2610 :
2611 : /************************************************************************/
2612 : /* WriteEncodedTileOrStrip() */
2613 : /************************************************************************/
2614 :
2615 74477 : CPLErr GTiffDataset::WriteEncodedTileOrStrip(uint32 tile_or_strip, void* data,
2616 : int bPreserveDataBuffer)
2617 : {
2618 74477 : CPLErr eErr = CE_None;
2619 :
2620 74477 : if( TIFFIsTiled( hTIFF ) )
2621 : {
2622 552 : if( WriteEncodedTile(tile_or_strip, data, bPreserveDataBuffer) == -1 )
2623 : {
2624 0 : eErr = CE_Failure;
2625 : }
2626 : }
2627 : else
2628 : {
2629 73925 : if( WriteEncodedStrip(tile_or_strip, data, bPreserveDataBuffer) == -1 )
2630 : {
2631 0 : eErr = CE_Failure;
2632 : }
2633 : }
2634 :
2635 74477 : return eErr;
2636 : }
2637 :
2638 : /************************************************************************/
2639 : /* FlushBlockBuf() */
2640 : /************************************************************************/
2641 :
2642 173715 : CPLErr GTiffDataset::FlushBlockBuf()
2643 :
2644 : {
2645 173715 : CPLErr eErr = CE_None;
2646 :
2647 173715 : if( nLoadedBlock < 0 || !bLoadedBlockDirty )
2648 172960 : return CE_None;
2649 :
2650 755 : bLoadedBlockDirty = FALSE;
2651 :
2652 755 : if (!SetDirectory())
2653 0 : return CE_Failure;
2654 :
2655 755 : eErr = WriteEncodedTileOrStrip(nLoadedBlock, pabyBlockBuf, TRUE);
2656 755 : if (eErr != CE_None)
2657 : {
2658 : CPLError( CE_Failure, CPLE_AppDefined,
2659 0 : "WriteEncodedTile/Strip() failed." );
2660 : }
2661 :
2662 755 : return eErr;
2663 : }
2664 :
2665 : /************************************************************************/
2666 : /* LoadBlockBuf() */
2667 : /* */
2668 : /* Load working block buffer with request block (tile/strip). */
2669 : /************************************************************************/
2670 :
2671 68864 : CPLErr GTiffDataset::LoadBlockBuf( int nBlockId, int bReadFromDisk )
2672 :
2673 : {
2674 : int nBlockBufSize;
2675 68864 : CPLErr eErr = CE_None;
2676 :
2677 68864 : if( nLoadedBlock == nBlockId )
2678 67308 : return CE_None;
2679 :
2680 : /* -------------------------------------------------------------------- */
2681 : /* If we have a dirty loaded block, flush it out first. */
2682 : /* -------------------------------------------------------------------- */
2683 1556 : if( nLoadedBlock != -1 && bLoadedBlockDirty )
2684 : {
2685 0 : eErr = FlushBlockBuf();
2686 0 : if( eErr != CE_None )
2687 0 : return eErr;
2688 : }
2689 :
2690 : /* -------------------------------------------------------------------- */
2691 : /* Get block size. */
2692 : /* -------------------------------------------------------------------- */
2693 1556 : if( TIFFIsTiled(hTIFF) )
2694 94 : nBlockBufSize = TIFFTileSize( hTIFF );
2695 : else
2696 1462 : nBlockBufSize = TIFFStripSize( hTIFF );
2697 :
2698 1556 : if ( !nBlockBufSize )
2699 : {
2700 : CPLError( CE_Failure, CPLE_AppDefined,
2701 0 : "Bogus block size; unable to allocate a buffer.");
2702 0 : return CE_Failure;
2703 : }
2704 :
2705 : /* -------------------------------------------------------------------- */
2706 : /* Allocate a temporary buffer for this strip. */
2707 : /* -------------------------------------------------------------------- */
2708 1556 : if( pabyBlockBuf == NULL )
2709 : {
2710 332 : pabyBlockBuf = (GByte *) VSICalloc( 1, nBlockBufSize );
2711 332 : if( pabyBlockBuf == NULL )
2712 : {
2713 : CPLError( CE_Failure, CPLE_OutOfMemory,
2714 : "Unable to allocate %d bytes for a temporary strip "
2715 : "buffer in GTIFF driver.",
2716 0 : nBlockBufSize );
2717 :
2718 0 : return( CE_Failure );
2719 : }
2720 : }
2721 :
2722 : /* -------------------------------------------------------------------- */
2723 : /* When called from ::IWriteBlock in separate cases (or in single band */
2724 : /* geotiffs), the ::IWriteBlock will override the content of the buffer*/
2725 : /* with pImage, so we don't need to read data from disk */
2726 : /* -------------------------------------------------------------------- */
2727 1556 : if( !bReadFromDisk )
2728 : {
2729 41 : nLoadedBlock = nBlockId;
2730 41 : return CE_None;
2731 : }
2732 :
2733 : /* -------------------------------------------------------------------- */
2734 : /* The bottom most partial tiles and strips are sometimes only */
2735 : /* partially encoded. This code reduces the requested data so */
2736 : /* an error won't be reported in this case. (#1179) */
2737 : /* -------------------------------------------------------------------- */
2738 1515 : int nBlockReqSize = nBlockBufSize;
2739 1515 : int nBlocksPerRow = (nRasterXSize + nBlockXSize - 1) / nBlockXSize;
2740 1515 : int nBlockYOff = (nBlockId % nBlocksPerBand) / nBlocksPerRow;
2741 :
2742 1515 : if( (int)((nBlockYOff+1) * nBlockYSize) > nRasterYSize )
2743 : {
2744 : nBlockReqSize = (nBlockBufSize / nBlockYSize)
2745 118 : * (nBlockYSize - (((nBlockYOff+1) * nBlockYSize) % nRasterYSize));
2746 118 : memset( pabyBlockBuf, 0, nBlockBufSize );
2747 : }
2748 :
2749 : /* -------------------------------------------------------------------- */
2750 : /* If we don't have this block already loaded, and we know it */
2751 : /* doesn't yet exist on disk, just zero the memory buffer and */
2752 : /* pretend we loaded it. */
2753 : /* -------------------------------------------------------------------- */
2754 1515 : if( !IsBlockAvailable( nBlockId ) )
2755 : {
2756 655 : memset( pabyBlockBuf, 0, nBlockBufSize );
2757 655 : nLoadedBlock = nBlockId;
2758 655 : return CE_None;
2759 : }
2760 :
2761 : /* -------------------------------------------------------------------- */
2762 : /* Load the block, if it isn't our current block. */
2763 : /* -------------------------------------------------------------------- */
2764 860 : if( TIFFIsTiled( hTIFF ) )
2765 : {
2766 49 : if( TIFFReadEncodedTile(hTIFF, nBlockId, pabyBlockBuf,
2767 : nBlockReqSize) == -1 )
2768 : {
2769 : /* Once TIFFError() is properly hooked, this can go away */
2770 : CPLError( CE_Failure, CPLE_AppDefined,
2771 0 : "TIFFReadEncodedTile() failed." );
2772 :
2773 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
2774 :
2775 0 : eErr = CE_Failure;
2776 : }
2777 : }
2778 : else
2779 : {
2780 811 : if( TIFFReadEncodedStrip(hTIFF, nBlockId, pabyBlockBuf,
2781 : nBlockReqSize) == -1 )
2782 : {
2783 : /* Once TIFFError() is properly hooked, this can go away */
2784 : CPLError( CE_Failure, CPLE_AppDefined,
2785 0 : "TIFFReadEncodedStrip() failed." );
2786 :
2787 0 : memset( pabyBlockBuf, 0, nBlockBufSize );
2788 :
2789 0 : eErr = CE_Failure;
2790 : }
2791 : }
2792 :
2793 860 : nLoadedBlock = nBlockId;
2794 860 : bLoadedBlockDirty = FALSE;
2795 :
2796 860 : return eErr;
2797 : }
2798 :
2799 :
2800 : /************************************************************************/
2801 : /* Crystalize() */
2802 : /* */
2803 : /* Make sure that the directory information is written out for */
2804 : /* a new file, require before writing any imagery data. */
2805 : /************************************************************************/
2806 :
2807 177513 : void GTiffDataset::Crystalize()
2808 :
2809 : {
2810 177513 : if( !bCrystalized )
2811 : {
2812 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
2813 692 : papszCreationOptions );
2814 692 : WriteGeoTIFFInfo();
2815 :
2816 692 : bMetadataChanged = FALSE;
2817 692 : bGeoTIFFInfoChanged = FALSE;
2818 692 : bNeedsRewrite = FALSE;
2819 :
2820 692 : bCrystalized = TRUE;
2821 :
2822 692 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffDataset::Crystalize");
2823 :
2824 : // Keep zip and tiff quality, and jpegcolormode which get reset when we call
2825 : // TIFFWriteDirectory
2826 692 : int jquality = -1, zquality = -1, nColorMode = -1;
2827 692 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
2828 692 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
2829 692 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
2830 :
2831 692 : TIFFWriteDirectory( hTIFF );
2832 692 : TIFFSetDirectory( hTIFF, 0 );
2833 :
2834 :
2835 : // Now, reset zip and tiff quality and jpegcolormode.
2836 692 : if(jquality > 0)
2837 2 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
2838 692 : if(zquality > 0)
2839 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
2840 692 : if (nColorMode >= 0)
2841 2 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, nColorMode);
2842 :
2843 692 : nDirOffset = TIFFCurrentDirOffset( hTIFF );
2844 : }
2845 177513 : }
2846 :
2847 :
2848 : /************************************************************************/
2849 : /* IsBlockAvailable() */
2850 : /* */
2851 : /* Return TRUE if the indicated strip/tile is available. We */
2852 : /* establish this by testing if the stripbytecount is zero. If */
2853 : /* zero then the block has never been committed to disk. */
2854 : /************************************************************************/
2855 :
2856 73067 : int GTiffDataset::IsBlockAvailable( int nBlockId )
2857 :
2858 : {
2859 73067 : toff_t *panByteCounts = NULL;
2860 :
2861 73067 : if( ( TIFFIsTiled( hTIFF )
2862 : && TIFFGetField( hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts ) )
2863 : || ( !TIFFIsTiled( hTIFF )
2864 : && TIFFGetField( hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts ) ) )
2865 : {
2866 73067 : if( panByteCounts == NULL )
2867 0 : return FALSE;
2868 : else
2869 73067 : return panByteCounts[nBlockId] != 0;
2870 : }
2871 : else
2872 0 : return FALSE;
2873 : }
2874 :
2875 : /************************************************************************/
2876 : /* FlushCache() */
2877 : /* */
2878 : /* We override this so we can also flush out local tiff strip */
2879 : /* cache if need be. */
2880 : /************************************************************************/
2881 :
2882 3997 : void GTiffDataset::FlushCache()
2883 :
2884 : {
2885 3997 : GDALPamDataset::FlushCache();
2886 :
2887 3997 : if( bLoadedBlockDirty && nLoadedBlock != -1 )
2888 81 : FlushBlockBuf();
2889 :
2890 3997 : CPLFree( pabyBlockBuf );
2891 3997 : pabyBlockBuf = NULL;
2892 3997 : nLoadedBlock = -1;
2893 3997 : bLoadedBlockDirty = FALSE;
2894 :
2895 3997 : if (!SetDirectory())
2896 0 : return;
2897 3997 : FlushDirectory();
2898 : }
2899 :
2900 : /************************************************************************/
2901 : /* FlushDirectory() */
2902 : /************************************************************************/
2903 :
2904 7554 : void GTiffDataset::FlushDirectory()
2905 :
2906 : {
2907 7554 : if( GetAccess() == GA_Update )
2908 : {
2909 2106 : if( bMetadataChanged )
2910 : {
2911 4 : if (!SetDirectory())
2912 0 : return;
2913 : bNeedsRewrite =
2914 : WriteMetadata( this, hTIFF, TRUE, osProfile, osFilename,
2915 4 : papszCreationOptions );
2916 4 : bMetadataChanged = FALSE;
2917 : }
2918 :
2919 2106 : if( bGeoTIFFInfoChanged )
2920 : {
2921 10 : if (!SetDirectory())
2922 0 : return;
2923 10 : WriteGeoTIFFInfo();
2924 : }
2925 :
2926 2106 : if( bNeedsRewrite )
2927 : {
2928 : #if defined(TIFFLIB_VERSION)
2929 : /* We need at least TIFF 3.7.0 for TIFFGetSizeProc and TIFFClientdata */
2930 : #if TIFFLIB_VERSION > 20041016
2931 53 : if (!SetDirectory())
2932 0 : return;
2933 :
2934 53 : TIFFSizeProc pfnSizeProc = TIFFGetSizeProc( hTIFF );
2935 :
2936 53 : nDirOffset = pfnSizeProc( TIFFClientdata( hTIFF ) );
2937 53 : if( (nDirOffset % 2) == 1 )
2938 5 : nDirOffset++;
2939 :
2940 53 : TIFFRewriteDirectory( hTIFF );
2941 :
2942 53 : TIFFSetSubDirectory( hTIFF, nDirOffset );
2943 : #elif TIFFLIB_VERSION > 20010925 && TIFFLIB_VERSION != 20011807
2944 : if (!SetDirectory())
2945 : return;
2946 :
2947 : TIFFRewriteDirectory( hTIFF );
2948 : #endif
2949 : #endif
2950 53 : bNeedsRewrite = FALSE;
2951 : }
2952 : }
2953 :
2954 : // there are some circumstances in which we can reach this point
2955 : // without having made this our directory (SetDirectory()) in which
2956 : // case we should not risk a flush.
2957 7554 : if( TIFFCurrentDirOffset(hTIFF) == nDirOffset )
2958 7546 : TIFFFlush( hTIFF );
2959 : }
2960 :
2961 : /************************************************************************/
2962 : /* TIFF_OvLevelAdjust() */
2963 : /* */
2964 : /* Some overview levels cannot be achieved closely enough to be */
2965 : /* recognised as the desired overview level. This function */
2966 : /* will adjust an overview level to one that is achievable on */
2967 : /* the given raster size. */
2968 : /* */
2969 : /* For instance a 1200x1200 image on which a 256 level overview */
2970 : /* is request will end up generating a 5x5 overview. However, */
2971 : /* this will appear to the system be a level 240 overview. */
2972 : /* This function will adjust 256 to 240 based on knowledge of */
2973 : /* the image size. */
2974 : /* */
2975 : /* This is a copy of the GDALOvLevelAdjust() function in */
2976 : /* gdaldefaultoverviews.cpp. */
2977 : /************************************************************************/
2978 :
2979 61 : static int TIFF_OvLevelAdjust( int nOvLevel, int nXSize )
2980 :
2981 : {
2982 61 : int nOXSize = (nXSize + nOvLevel - 1) / nOvLevel;
2983 :
2984 61 : return (int) (0.5 + nXSize / (double) nOXSize);
2985 : }
2986 :
2987 : /************************************************************************/
2988 : /* CleanOverviews() */
2989 : /************************************************************************/
2990 :
2991 2 : CPLErr GTiffDataset::CleanOverviews()
2992 :
2993 : {
2994 : CPLAssert( bBase );
2995 :
2996 2 : FlushDirectory();
2997 2 : *ppoActiveDSRef = NULL;
2998 :
2999 : /* -------------------------------------------------------------------- */
3000 : /* Cleanup overviews objects, and get offsets to all overview */
3001 : /* directories. */
3002 : /* -------------------------------------------------------------------- */
3003 2 : std::vector<toff_t> anOvDirOffsets;
3004 : int i;
3005 :
3006 4 : for( i = 0; i < nOverviewCount; i++ )
3007 : {
3008 2 : anOvDirOffsets.push_back( papoOverviewDS[i]->nDirOffset );
3009 2 : delete papoOverviewDS[i];
3010 : }
3011 :
3012 : /* -------------------------------------------------------------------- */
3013 : /* Loop through all the directories, translating the offsets */
3014 : /* into indexes we can use with TIFFUnlinkDirectory(). */
3015 : /* -------------------------------------------------------------------- */
3016 2 : std::vector<uint16> anOvDirIndexes;
3017 2 : int iThisOffset = 1;
3018 :
3019 2 : TIFFSetDirectory( hTIFF, 0 );
3020 :
3021 2 : for( ; TRUE; )
3022 : {
3023 8 : for( i = 0; i < nOverviewCount; i++ )
3024 : {
3025 4 : if( anOvDirOffsets[i] == TIFFCurrentDirOffset( hTIFF ) )
3026 : {
3027 : CPLDebug( "GTiff", "%d -> %d",
3028 2 : (int) anOvDirOffsets[i], iThisOffset );
3029 2 : anOvDirIndexes.push_back( iThisOffset );
3030 : }
3031 : }
3032 :
3033 4 : if( TIFFLastDirectory( hTIFF ) )
3034 : break;
3035 :
3036 2 : TIFFReadDirectory( hTIFF );
3037 2 : iThisOffset++;
3038 : }
3039 :
3040 : /* -------------------------------------------------------------------- */
3041 : /* Actually unlink the target directories. Note that we do */
3042 : /* this from last to first so as to avoid renumbering any of */
3043 : /* the earlier directories we need to remove. */
3044 : /* -------------------------------------------------------------------- */
3045 6 : while( !anOvDirIndexes.empty() )
3046 : {
3047 2 : TIFFUnlinkDirectory( hTIFF, anOvDirIndexes.back() );
3048 2 : anOvDirIndexes.pop_back();
3049 : }
3050 :
3051 2 : CPLFree( papoOverviewDS );
3052 :
3053 2 : nOverviewCount = 0;
3054 2 : papoOverviewDS = NULL;
3055 :
3056 2 : if (!SetDirectory())
3057 0 : return CE_Failure;
3058 :
3059 2 : return CE_None;
3060 : }
3061 :
3062 : /************************************************************************/
3063 : /* IBuildOverviews() */
3064 : /************************************************************************/
3065 :
3066 85 : CPLErr GTiffDataset::IBuildOverviews(
3067 : const char * pszResampling,
3068 : int nOverviews, int * panOverviewList,
3069 : int nBands, int * panBandList,
3070 : GDALProgressFunc pfnProgress, void * pProgressData )
3071 :
3072 : {
3073 85 : CPLErr eErr = CE_None;
3074 : int i;
3075 : GTiffDataset *poODS;
3076 :
3077 : /* -------------------------------------------------------------------- */
3078 : /* If we don't have read access, then create the overviews */
3079 : /* externally. */
3080 : /* -------------------------------------------------------------------- */
3081 85 : if( GetAccess() != GA_Update )
3082 : {
3083 : CPLDebug( "GTiff",
3084 : "File open for read-only accessing, "
3085 25 : "creating overviews externally." );
3086 :
3087 : return GDALDataset::IBuildOverviews(
3088 : pszResampling, nOverviews, panOverviewList,
3089 25 : nBands, panBandList, pfnProgress, pProgressData );
3090 : }
3091 :
3092 : /* -------------------------------------------------------------------- */
3093 : /* If RRD overviews requested, then invoke generic handling. */
3094 : /* -------------------------------------------------------------------- */
3095 60 : if( CSLTestBoolean(CPLGetConfigOption( "USE_RRD", "NO" )) )
3096 : {
3097 : return GDALDataset::IBuildOverviews(
3098 : pszResampling, nOverviews, panOverviewList,
3099 2 : nBands, panBandList, pfnProgress, pProgressData );
3100 : }
3101 :
3102 : /* -------------------------------------------------------------------- */
3103 : /* Our TIFF overview support currently only works safely if all */
3104 : /* bands are handled at the same time. */
3105 : /* -------------------------------------------------------------------- */
3106 58 : if( nBands != GetRasterCount() )
3107 : {
3108 : CPLError( CE_Failure, CPLE_NotSupported,
3109 : "Generation of overviews in TIFF currently only"
3110 : " supported when operating on all bands.\n"
3111 0 : "Operation failed.\n" );
3112 0 : return CE_Failure;
3113 : }
3114 :
3115 : /* -------------------------------------------------------------------- */
3116 : /* Initialize progress counter. */
3117 : /* -------------------------------------------------------------------- */
3118 58 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
3119 : {
3120 0 : CPLError( CE_Failure, CPLE_UserInterrupt, "User terminated" );
3121 0 : return CE_Failure;
3122 : }
3123 :
3124 : /* -------------------------------------------------------------------- */
3125 : /* If zero overviews were requested, we need to clear all */
3126 : /* existing overviews. */
3127 : /* -------------------------------------------------------------------- */
3128 58 : if( nOverviews == 0 )
3129 : {
3130 3 : if( nOverviewCount == 0 )
3131 : return GDALDataset::IBuildOverviews(
3132 : pszResampling, nOverviews, panOverviewList,
3133 1 : nBands, panBandList, pfnProgress, pProgressData );
3134 : else
3135 2 : return CleanOverviews();
3136 : }
3137 :
3138 : /* -------------------------------------------------------------------- */
3139 : /* Move to the directory for this dataset. */
3140 : /* -------------------------------------------------------------------- */
3141 55 : if (!SetDirectory())
3142 0 : return CE_Failure;
3143 55 : FlushDirectory();
3144 :
3145 : /* -------------------------------------------------------------------- */
3146 : /* If we are averaging bit data to grayscale we need to create */
3147 : /* 8bit overviews. */
3148 : /* -------------------------------------------------------------------- */
3149 55 : int nOvBitsPerSample = nBitsPerSample;
3150 :
3151 55 : if( EQUALN(pszResampling,"AVERAGE_BIT2",12) )
3152 2 : nOvBitsPerSample = 8;
3153 :
3154 : /* -------------------------------------------------------------------- */
3155 : /* Do we have a palette? If so, create a TIFF compatible version. */
3156 : /* -------------------------------------------------------------------- */
3157 55 : std::vector<unsigned short> anTRed, anTGreen, anTBlue;
3158 55 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
3159 :
3160 55 : if( nPhotometric == PHOTOMETRIC_PALETTE && poColorTable != NULL )
3161 : {
3162 : int nColors;
3163 :
3164 9 : if( nOvBitsPerSample == 8 )
3165 9 : nColors = 256;
3166 0 : else if( nOvBitsPerSample < 8 )
3167 0 : nColors = 1 << nOvBitsPerSample;
3168 : else
3169 0 : nColors = 65536;
3170 :
3171 9 : anTRed.resize(nColors,0);
3172 9 : anTGreen.resize(nColors,0);
3173 9 : anTBlue.resize(nColors,0);
3174 :
3175 2313 : for( int iColor = 0; iColor < nColors; iColor++ )
3176 : {
3177 2304 : if( iColor < poColorTable->GetColorEntryCount() )
3178 : {
3179 : GDALColorEntry sRGB;
3180 :
3181 2304 : poColorTable->GetColorEntryAsRGB( iColor, &sRGB );
3182 :
3183 2304 : anTRed[iColor] = (unsigned short) (256 * sRGB.c1);
3184 2304 : anTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
3185 2304 : anTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
3186 : }
3187 : else
3188 : {
3189 0 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
3190 : }
3191 : }
3192 :
3193 9 : panRed = &(anTRed[0]);
3194 9 : panGreen = &(anTGreen[0]);
3195 9 : panBlue = &(anTBlue[0]);
3196 : }
3197 :
3198 : /* -------------------------------------------------------------------- */
3199 : /* Do we need some metadata for the overviews? */
3200 : /* -------------------------------------------------------------------- */
3201 55 : CPLString osMetadata;
3202 :
3203 55 : GTIFFBuildOverviewMetadata( pszResampling, this, osMetadata );
3204 :
3205 : /* -------------------------------------------------------------------- */
3206 : /* Fetch extra sample tag */
3207 : /* -------------------------------------------------------------------- */
3208 55 : uint16 *panExtraSampleValues = NULL;
3209 55 : uint16 nExtraSamples = 0;
3210 :
3211 55 : if( TIFFGetField( hTIFF, TIFFTAG_EXTRASAMPLES, &nExtraSamples, &panExtraSampleValues) )
3212 : {
3213 8 : uint16* panExtraSampleValuesNew = (uint16*) CPLMalloc(nExtraSamples * sizeof(uint16));
3214 8 : memcpy(panExtraSampleValuesNew, panExtraSampleValues, nExtraSamples * sizeof(uint16));
3215 8 : panExtraSampleValues = panExtraSampleValuesNew;
3216 : }
3217 : else
3218 : {
3219 47 : panExtraSampleValues = NULL;
3220 47 : nExtraSamples = 0;
3221 : }
3222 :
3223 : /* -------------------------------------------------------------------- */
3224 : /* Establish which of the overview levels we already have, and */
3225 : /* which are new. We assume that band 1 of the file is */
3226 : /* representative. */
3227 : /* -------------------------------------------------------------------- */
3228 130 : for( i = 0; i < nOverviews && eErr == CE_None; i++ )
3229 : {
3230 : int j;
3231 :
3232 106 : for( j = 0; j < nOverviewCount; j++ )
3233 : {
3234 : int nOvFactor;
3235 :
3236 31 : poODS = papoOverviewDS[j];
3237 :
3238 : nOvFactor = (int)
3239 31 : (0.5 + GetRasterXSize() / (double) poODS->GetRasterXSize());
3240 :
3241 31 : if( nOvFactor == panOverviewList[i]
3242 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3243 : GetRasterXSize() ) )
3244 8 : panOverviewList[i] *= -1;
3245 : }
3246 :
3247 75 : if( panOverviewList[i] > 0 )
3248 : {
3249 : toff_t nOverviewOffset;
3250 : int nOXSize, nOYSize;
3251 :
3252 67 : nOXSize = (GetRasterXSize() + panOverviewList[i] - 1)
3253 134 : / panOverviewList[i];
3254 67 : nOYSize = (GetRasterYSize() + panOverviewList[i] - 1)
3255 134 : / panOverviewList[i];
3256 :
3257 : nOverviewOffset =
3258 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE,
3259 : nOXSize, nOYSize,
3260 : nOvBitsPerSample, nPlanarConfig,
3261 : nSamplesPerPixel, 128, 128, TRUE,
3262 : nCompression, nPhotometric, nSampleFormat,
3263 : panRed, panGreen, panBlue,
3264 : nExtraSamples, panExtraSampleValues,
3265 67 : osMetadata );
3266 :
3267 67 : if( nOverviewOffset == 0 )
3268 : {
3269 0 : eErr = CE_Failure;
3270 0 : continue;
3271 : }
3272 :
3273 67 : poODS = new GTiffDataset();
3274 134 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nOverviewOffset, FALSE,
3275 : GA_Update ) != CE_None )
3276 : {
3277 0 : delete poODS;
3278 0 : eErr = CE_Failure;
3279 : }
3280 : else
3281 : {
3282 67 : nOverviewCount++;
3283 : papoOverviewDS = (GTiffDataset **)
3284 : CPLRealloc(papoOverviewDS,
3285 67 : nOverviewCount * (sizeof(void*)));
3286 67 : papoOverviewDS[nOverviewCount-1] = poODS;
3287 67 : poODS->poBaseDS = this;
3288 : }
3289 : }
3290 : else
3291 8 : panOverviewList[i] *= -1;
3292 : }
3293 :
3294 55 : CPLFree(panExtraSampleValues);
3295 55 : panExtraSampleValues = NULL;
3296 :
3297 : /* -------------------------------------------------------------------- */
3298 : /* Create overviews for the mask. */
3299 : /* -------------------------------------------------------------------- */
3300 :
3301 55 : if (poMaskDS != NULL &&
3302 : poMaskDS->GetRasterCount() == 1 &&
3303 : CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
3304 : {
3305 3 : for( i = 0; i < nOverviewCount; i++ )
3306 : {
3307 2 : if (papoOverviewDS[i]->poMaskDS == NULL)
3308 : {
3309 : toff_t nOverviewOffset;
3310 :
3311 : nOverviewOffset =
3312 : GTIFFWriteDirectory(hTIFF, FILETYPE_REDUCEDIMAGE | FILETYPE_MASK,
3313 4 : papoOverviewDS[i]->nRasterXSize, papoOverviewDS[i]->nRasterYSize,
3314 : 1, PLANARCONFIG_CONTIG,
3315 : 1, 128, 128, TRUE,
3316 : COMPRESSION_NONE, PHOTOMETRIC_MASK, SAMPLEFORMAT_UINT,
3317 : NULL, NULL, NULL, 0, NULL,
3318 6 : "" );
3319 :
3320 2 : if( nOverviewOffset == 0 )
3321 : {
3322 0 : eErr = CE_Failure;
3323 0 : continue;
3324 : }
3325 :
3326 2 : poODS = new GTiffDataset();
3327 4 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef,
3328 : nOverviewOffset, FALSE,
3329 : GA_Update ) != CE_None )
3330 : {
3331 0 : delete poODS;
3332 0 : eErr = CE_Failure;
3333 : }
3334 : else
3335 : {
3336 2 : poODS->poBaseDS = this;
3337 2 : papoOverviewDS[i]->poMaskDS = poODS;
3338 2 : poMaskDS->nOverviewCount++;
3339 : poMaskDS->papoOverviewDS = (GTiffDataset **)
3340 : CPLRealloc(poMaskDS->papoOverviewDS,
3341 2 : poMaskDS->nOverviewCount * (sizeof(void*)));
3342 2 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] = poODS;
3343 : }
3344 : }
3345 : }
3346 : }
3347 :
3348 : /* -------------------------------------------------------------------- */
3349 : /* Refresh overviews for the mask */
3350 : /* -------------------------------------------------------------------- */
3351 55 : if (poMaskDS != NULL &&
3352 : poMaskDS->GetRasterCount() == 1)
3353 : {
3354 : GDALRasterBand **papoOverviewBands;
3355 5 : int nMaskOverviews = 0;
3356 :
3357 5 : papoOverviewBands = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviewCount);
3358 15 : for( i = 0; i < nOverviewCount; i++ )
3359 : {
3360 10 : if (papoOverviewDS[i]->poMaskDS != NULL)
3361 : {
3362 16 : papoOverviewBands[nMaskOverviews ++] =
3363 8 : papoOverviewDS[i]->poMaskDS->GetRasterBand(1);
3364 : }
3365 : }
3366 : eErr = GDALRegenerateOverviews( (GDALRasterBandH)
3367 : poMaskDS->GetRasterBand(1),
3368 : nMaskOverviews,
3369 : (GDALRasterBandH *) papoOverviewBands,
3370 5 : pszResampling, GDALDummyProgress, NULL);
3371 5 : CPLFree(papoOverviewBands);
3372 : }
3373 :
3374 :
3375 : /* -------------------------------------------------------------------- */
3376 : /* Refresh old overviews that were listed. */
3377 : /* -------------------------------------------------------------------- */
3378 61 : if (nCompression != COMPRESSION_NONE &&
3379 : nPlanarConfig == PLANARCONFIG_CONTIG &&
3380 : GDALDataTypeIsComplex(GetRasterBand( panBandList[0] )->GetRasterDataType()) == FALSE &&
3381 6 : GetRasterBand( panBandList[0] )->GetColorTable() == NULL &&
3382 : (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
3383 : {
3384 : /* In the case of pixel interleaved compressed overviews, we want to generate */
3385 : /* the overviews for all the bands block by block, and not band after band, */
3386 : /* in order to write the block once and not loose space in the TIFF file */
3387 :
3388 : GDALRasterBand ***papapoOverviewBands;
3389 : GDALRasterBand **papoBandList;
3390 :
3391 6 : int nNewOverviews = 0;
3392 : int iBand;
3393 :
3394 6 : papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
3395 6 : papoBandList = (GDALRasterBand **) CPLCalloc(sizeof(void*),nBands);
3396 24 : for( iBand = 0; iBand < nBands; iBand++ )
3397 : {
3398 18 : GDALRasterBand* poBand = GetRasterBand( panBandList[iBand] );
3399 :
3400 18 : papoBandList[iBand] = poBand;
3401 18 : papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*), poBand->GetOverviewCount());
3402 :
3403 18 : int iCurOverview = 0;
3404 36 : for( i = 0; i < nOverviews; i++ )
3405 : {
3406 : int j;
3407 :
3408 18 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
3409 : {
3410 : int nOvFactor;
3411 18 : GDALRasterBand * poOverview = poBand->GetOverview( j );
3412 :
3413 : nOvFactor = (int)
3414 18 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
3415 :
3416 : int bHasNoData;
3417 18 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
3418 :
3419 18 : if (bHasNoData)
3420 12 : poOverview->SetNoDataValue(noDataValue);
3421 :
3422 18 : if( nOvFactor == panOverviewList[i]
3423 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3424 : poBand->GetXSize() ) )
3425 : {
3426 18 : papapoOverviewBands[iBand][iCurOverview] = poOverview;
3427 18 : iCurOverview++ ;
3428 18 : break;
3429 : }
3430 : }
3431 : }
3432 :
3433 18 : if (nNewOverviews == 0)
3434 6 : nNewOverviews = iCurOverview;
3435 12 : else if (nNewOverviews != iCurOverview)
3436 : {
3437 : CPLAssert(0);
3438 0 : return CE_Failure;
3439 : }
3440 : }
3441 :
3442 : GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
3443 : nNewOverviews, papapoOverviewBands,
3444 6 : pszResampling, pfnProgress, pProgressData );
3445 :
3446 24 : for( iBand = 0; iBand < nBands; iBand++ )
3447 : {
3448 18 : CPLFree(papapoOverviewBands[iBand]);
3449 : }
3450 6 : CPLFree(papapoOverviewBands);
3451 6 : CPLFree(papoBandList);
3452 : }
3453 : else
3454 : {
3455 : GDALRasterBand **papoOverviewBands;
3456 :
3457 : papoOverviewBands = (GDALRasterBand **)
3458 49 : CPLCalloc(sizeof(void*),nOverviews);
3459 :
3460 120 : for( int iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
3461 : {
3462 : GDALRasterBand *poBand;
3463 : int nNewOverviews;
3464 :
3465 71 : poBand = GetRasterBand( panBandList[iBand] );
3466 :
3467 71 : nNewOverviews = 0;
3468 180 : for( i = 0; i < nOverviews && poBand != NULL; i++ )
3469 : {
3470 : int j;
3471 :
3472 147 : for( j = 0; j < poBand->GetOverviewCount(); j++ )
3473 : {
3474 : int nOvFactor;
3475 147 : GDALRasterBand * poOverview = poBand->GetOverview( j );
3476 :
3477 : int bHasNoData;
3478 147 : double noDataValue = poBand->GetNoDataValue(&bHasNoData);
3479 :
3480 147 : if (bHasNoData)
3481 7 : poOverview->SetNoDataValue(noDataValue);
3482 :
3483 : nOvFactor = (int)
3484 147 : (0.5 + poBand->GetXSize() / (double) poOverview->GetXSize());
3485 :
3486 147 : if( nOvFactor == panOverviewList[i]
3487 : || nOvFactor == TIFF_OvLevelAdjust( panOverviewList[i],
3488 : poBand->GetXSize() ) )
3489 : {
3490 109 : papoOverviewBands[nNewOverviews++] = poOverview;
3491 109 : break;
3492 : }
3493 : }
3494 : }
3495 :
3496 : void *pScaledProgressData;
3497 :
3498 : pScaledProgressData =
3499 : GDALCreateScaledProgress( iBand / (double) nBands,
3500 : (iBand+1) / (double) nBands,
3501 71 : pfnProgress, pProgressData );
3502 :
3503 : eErr = GDALRegenerateOverviews( (GDALRasterBandH) poBand,
3504 : nNewOverviews,
3505 : (GDALRasterBandH *) papoOverviewBands,
3506 : pszResampling,
3507 : GDALScaledProgress,
3508 71 : pScaledProgressData);
3509 :
3510 71 : GDALDestroyScaledProgress( pScaledProgressData );
3511 : }
3512 :
3513 : /* -------------------------------------------------------------------- */
3514 : /* Cleanup */
3515 : /* -------------------------------------------------------------------- */
3516 49 : CPLFree( papoOverviewBands );
3517 : }
3518 :
3519 :
3520 55 : pfnProgress( 1.0, NULL, pProgressData );
3521 :
3522 55 : return eErr;
3523 : }
3524 :
3525 :
3526 : /************************************************************************/
3527 : /* WriteGeoTIFFInfo() */
3528 : /************************************************************************/
3529 :
3530 702 : void GTiffDataset::WriteGeoTIFFInfo()
3531 :
3532 : {
3533 : /* -------------------------------------------------------------------- */
3534 : /* If the geotransform is the default, don't bother writing it. */
3535 : /* -------------------------------------------------------------------- */
3536 2112 : if( adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
3537 360 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
3538 522 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 )
3539 : {
3540 528 : bNeedsRewrite = TRUE;
3541 :
3542 : /* -------------------------------------------------------------------- */
3543 : /* Clear old tags to ensure we don't end up with conflicting */
3544 : /* information. (#2625) */
3545 : /* -------------------------------------------------------------------- */
3546 : #ifdef HAVE_UNSETFIELD
3547 528 : TIFFUnsetField( hTIFF, TIFFTAG_GEOPIXELSCALE );
3548 528 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTIEPOINTS );
3549 528 : TIFFUnsetField( hTIFF, TIFFTAG_GEOTRANSMATRIX );
3550 : #endif
3551 :
3552 : /* -------------------------------------------------------------------- */
3553 : /* Write the transform. If we have a normal north-up image we */
3554 : /* use the tiepoint plus pixelscale otherwise we use a matrix. */
3555 : /* -------------------------------------------------------------------- */
3556 1579 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
3557 526 : && adfGeoTransform[5] < 0.0 )
3558 : {
3559 : double adfPixelScale[3], adfTiePoints[6];
3560 :
3561 525 : adfPixelScale[0] = adfGeoTransform[1];
3562 525 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
3563 525 : adfPixelScale[2] = 0.0;
3564 :
3565 525 : if( !EQUAL(osProfile,"BASELINE") )
3566 520 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
3567 :
3568 525 : adfTiePoints[0] = 0.0;
3569 525 : adfTiePoints[1] = 0.0;
3570 525 : adfTiePoints[2] = 0.0;
3571 525 : adfTiePoints[3] = adfGeoTransform[0];
3572 525 : adfTiePoints[4] = adfGeoTransform[3];
3573 525 : adfTiePoints[5] = 0.0;
3574 :
3575 525 : if( !EQUAL(osProfile,"BASELINE") )
3576 520 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
3577 : }
3578 : else
3579 : {
3580 : double adfMatrix[16];
3581 :
3582 3 : memset(adfMatrix,0,sizeof(double) * 16);
3583 :
3584 3 : adfMatrix[0] = adfGeoTransform[1];
3585 3 : adfMatrix[1] = adfGeoTransform[2];
3586 3 : adfMatrix[3] = adfGeoTransform[0];
3587 3 : adfMatrix[4] = adfGeoTransform[4];
3588 3 : adfMatrix[5] = adfGeoTransform[5];
3589 3 : adfMatrix[7] = adfGeoTransform[3];
3590 3 : adfMatrix[15] = 1.0;
3591 :
3592 3 : if( !EQUAL(osProfile,"BASELINE") )
3593 3 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
3594 : }
3595 :
3596 : // Do we need a world file?
3597 528 : if( CSLFetchBoolean( papszCreationOptions, "TFW", FALSE ) )
3598 2 : GDALWriteWorldFile( osFilename, "tfw", adfGeoTransform );
3599 526 : else if( CSLFetchBoolean( papszCreationOptions, "WORLDFILE", FALSE ) )
3600 2 : GDALWriteWorldFile( osFilename, "wld", adfGeoTransform );
3601 : }
3602 174 : else if( GetGCPCount() > 0 )
3603 : {
3604 : double *padfTiePoints;
3605 : int iGCP;
3606 1 : bNeedsRewrite = TRUE;
3607 :
3608 : padfTiePoints = (double *)
3609 1 : CPLMalloc( 6 * sizeof(double) * GetGCPCount() );
3610 :
3611 5 : for( iGCP = 0; iGCP < GetGCPCount(); iGCP++ )
3612 : {
3613 :
3614 4 : padfTiePoints[iGCP*6+0] = pasGCPList[iGCP].dfGCPPixel;
3615 4 : padfTiePoints[iGCP*6+1] = pasGCPList[iGCP].dfGCPLine;
3616 4 : padfTiePoints[iGCP*6+2] = 0;
3617 4 : padfTiePoints[iGCP*6+3] = pasGCPList[iGCP].dfGCPX;
3618 4 : padfTiePoints[iGCP*6+4] = pasGCPList[iGCP].dfGCPY;
3619 4 : padfTiePoints[iGCP*6+5] = pasGCPList[iGCP].dfGCPZ;
3620 : }
3621 :
3622 1 : if( !EQUAL(osProfile,"BASELINE") )
3623 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
3624 1 : 6 * GetGCPCount(), padfTiePoints );
3625 1 : CPLFree( padfTiePoints );
3626 : }
3627 :
3628 : /* -------------------------------------------------------------------- */
3629 : /* Write out projection definition. */
3630 : /* -------------------------------------------------------------------- */
3631 702 : if( pszProjection != NULL && !EQUAL( pszProjection, "" )
3632 : && !EQUAL(osProfile,"BASELINE") )
3633 : {
3634 : GTIF *psGTIF;
3635 :
3636 523 : bNeedsRewrite = TRUE;
3637 :
3638 : // If we have existing geokeys, try to wipe them
3639 : // by writing a dummy goekey directory. (#2546)
3640 523 : uint16 *panVI = NULL;
3641 : uint16 nKeyCount;
3642 :
3643 523 : if( TIFFGetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
3644 : &nKeyCount, &panVI ) )
3645 : {
3646 3 : GUInt16 anGKVersionInfo[4] = { 1, 1, 0, 0 };
3647 3 : double adfDummyDoubleParams[1] = { 0.0 };
3648 : TIFFSetField( hTIFF, TIFFTAG_GEOKEYDIRECTORY,
3649 3 : 4, anGKVersionInfo );
3650 : TIFFSetField( hTIFF, TIFFTAG_GEODOUBLEPARAMS,
3651 3 : 1, adfDummyDoubleParams );
3652 3 : TIFFSetField( hTIFF, TIFFTAG_GEOASCIIPARAMS, "" );
3653 : }
3654 :
3655 523 : psGTIF = GTIFNew( hTIFF );
3656 :
3657 : // set according to coordinate system.
3658 523 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
3659 :
3660 524 : if( GetMetadataItem( GDALMD_AREA_OR_POINT )
3661 1 : && EQUAL(GetMetadataItem(GDALMD_AREA_OR_POINT),
3662 : GDALMD_AOP_POINT) )
3663 : {
3664 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
3665 0 : RasterPixelIsPoint);
3666 : }
3667 :
3668 523 : GTIFWriteKeys( psGTIF );
3669 523 : GTIFFree( psGTIF );
3670 : }
3671 702 : }
3672 :
3673 : /************************************************************************/
3674 : /* AppendMetadataItem() */
3675 : /************************************************************************/
3676 :
3677 130 : static void AppendMetadataItem( CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
3678 : const char *pszKey, const char *pszValue,
3679 : int nBand, const char *pszRole,
3680 : const char *pszDomain )
3681 :
3682 : {
3683 : char szBandId[32];
3684 : CPLXMLNode *psItem;
3685 :
3686 : /* -------------------------------------------------------------------- */
3687 : /* Create the Item element, and subcomponents. */
3688 : /* -------------------------------------------------------------------- */
3689 130 : psItem = CPLCreateXMLNode( NULL, CXT_Element, "Item" );
3690 : CPLCreateXMLNode( CPLCreateXMLNode( psItem, CXT_Attribute, "name"),
3691 130 : CXT_Text, pszKey );
3692 :
3693 130 : if( nBand > 0 )
3694 : {
3695 30 : sprintf( szBandId, "%d", nBand - 1 );
3696 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"sample"),
3697 30 : CXT_Text, szBandId );
3698 : }
3699 :
3700 130 : if( pszRole != NULL )
3701 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"role"),
3702 0 : CXT_Text, pszRole );
3703 :
3704 130 : if( pszDomain != NULL && strlen(pszDomain) > 0 )
3705 : CPLCreateXMLNode( CPLCreateXMLNode( psItem,CXT_Attribute,"domain"),
3706 1 : CXT_Text, pszDomain );
3707 :
3708 130 : char *pszEscapedItemValue = CPLEscapeString(pszValue,-1,CPLES_XML);
3709 130 : CPLCreateXMLNode( psItem, CXT_Text, pszEscapedItemValue );
3710 130 : CPLFree( pszEscapedItemValue );
3711 :
3712 : /* -------------------------------------------------------------------- */
3713 : /* Create root, if missing. */
3714 : /* -------------------------------------------------------------------- */
3715 130 : if( *ppsRoot == NULL )
3716 47 : *ppsRoot = CPLCreateXMLNode( NULL, CXT_Element, "GDALMetadata" );
3717 :
3718 : /* -------------------------------------------------------------------- */
3719 : /* Append item to tail. We keep track of the tail to avoid */
3720 : /* O(nsquared) time as the list gets longer. */
3721 : /* -------------------------------------------------------------------- */
3722 130 : if( *ppsTail == NULL )
3723 47 : CPLAddXMLChild( *ppsRoot, psItem );
3724 : else
3725 83 : CPLAddXMLSibling( *ppsTail, psItem );
3726 :
3727 130 : *ppsTail = psItem;
3728 130 : }
3729 :
3730 : /************************************************************************/
3731 : /* WriteMDMDMetadata() */
3732 : /************************************************************************/
3733 :
3734 132701 : static void WriteMDMetadata( GDALMultiDomainMetadata *poMDMD, TIFF *hTIFF,
3735 : CPLXMLNode **ppsRoot, CPLXMLNode **ppsTail,
3736 : int nBand, const char *pszProfile )
3737 :
3738 : {
3739 : int iDomain;
3740 : char **papszDomainList;
3741 :
3742 : (void) pszProfile;
3743 :
3744 : /* ==================================================================== */
3745 : /* Process each domain. */
3746 : /* ==================================================================== */
3747 132701 : papszDomainList = poMDMD->GetDomainList();
3748 132852 : for( iDomain = 0; papszDomainList && papszDomainList[iDomain]; iDomain++ )
3749 : {
3750 151 : char **papszMD = poMDMD->GetMetadata( papszDomainList[iDomain] );
3751 : int iItem;
3752 151 : int bIsXML = FALSE;
3753 :
3754 151 : if( EQUAL(papszDomainList[iDomain], "IMAGE_STRUCTURE") )
3755 31 : continue; // ignored
3756 120 : if( EQUAL(papszDomainList[iDomain], "RPC") )
3757 0 : continue; // handled elsewhere
3758 120 : if( EQUALN(papszDomainList[iDomain], "xml:",4 ) )
3759 1 : bIsXML = TRUE;
3760 :
3761 : /* -------------------------------------------------------------------- */
3762 : /* Process each item in this domain. */
3763 : /* -------------------------------------------------------------------- */
3764 318 : for( iItem = 0; papszMD && papszMD[iItem]; iItem++ )
3765 : {
3766 : const char *pszItemValue;
3767 198 : char *pszItemName = NULL;
3768 :
3769 198 : if( bIsXML )
3770 : {
3771 1 : pszItemName = CPLStrdup("doc");
3772 1 : pszItemValue = papszMD[iItem];
3773 : }
3774 : else
3775 : {
3776 197 : pszItemValue = CPLParseNameValue( papszMD[iItem], &pszItemName);
3777 : }
3778 :
3779 : /* -------------------------------------------------------------------- */
3780 : /* Convert into XML item or handle as a special TIFF tag. */
3781 : /* -------------------------------------------------------------------- */
3782 227 : if( strlen(papszDomainList[iDomain]) == 0
3783 : && nBand == 0 && EQUALN(pszItemName,"TIFFTAG_",8) )
3784 : {
3785 29 : if( EQUAL(pszItemName,"TIFFTAG_DOCUMENTNAME") )
3786 4 : TIFFSetField( hTIFF, TIFFTAG_DOCUMENTNAME, pszItemValue );
3787 25 : else if( EQUAL(pszItemName,"TIFFTAG_IMAGEDESCRIPTION") )
3788 1 : TIFFSetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, pszItemValue );
3789 24 : else if( EQUAL(pszItemName,"TIFFTAG_SOFTWARE") )
3790 2 : TIFFSetField( hTIFF, TIFFTAG_SOFTWARE, pszItemValue );
3791 22 : else if( EQUAL(pszItemName,"TIFFTAG_DATETIME") )
3792 1 : TIFFSetField( hTIFF, TIFFTAG_DATETIME, pszItemValue );
3793 21 : else if( EQUAL(pszItemName,"TIFFTAG_ARTIST") )
3794 1 : TIFFSetField( hTIFF, TIFFTAG_ARTIST, pszItemValue );
3795 20 : else if( EQUAL(pszItemName,"TIFFTAG_HOSTCOMPUTER") )
3796 1 : TIFFSetField( hTIFF, TIFFTAG_HOSTCOMPUTER, pszItemValue );
3797 19 : else if( EQUAL(pszItemName,"TIFFTAG_COPYRIGHT") )
3798 1 : TIFFSetField( hTIFF, TIFFTAG_COPYRIGHT, pszItemValue );
3799 18 : else if( EQUAL(pszItemName,"TIFFTAG_XRESOLUTION") )
3800 6 : TIFFSetField( hTIFF, TIFFTAG_XRESOLUTION, atof(pszItemValue) );
3801 12 : else if( EQUAL(pszItemName,"TIFFTAG_YRESOLUTION") )
3802 6 : TIFFSetField( hTIFF, TIFFTAG_YRESOLUTION, atof(pszItemValue) );
3803 6 : else if( EQUAL(pszItemName,"TIFFTAG_RESOLUTIONUNIT") )
3804 6 : TIFFSetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, atoi(pszItemValue) );
3805 : }
3806 169 : else if( nBand == 0 && EQUAL(pszItemName,GDALMD_AREA_OR_POINT) )
3807 : /* do nothing, handled elsewhere */;
3808 : else
3809 : AppendMetadataItem( ppsRoot, ppsTail,
3810 : pszItemName, pszItemValue,
3811 130 : nBand, NULL, papszDomainList[iDomain] );
3812 :
3813 198 : CPLFree( pszItemName );
3814 : }
3815 : }
3816 132701 : }
3817 :
3818 : /************************************************************************/
3819 : /* WriteMetadata() */
3820 : /************************************************************************/
3821 :
3822 810 : int GTiffDataset::WriteMetadata( GDALDataset *poSrcDS, TIFF *hTIFF,
3823 : int bSrcIsGeoTIFF,
3824 : const char *pszProfile,
3825 : const char *pszTIFFFilename,
3826 : char **papszCreationOptions,
3827 : int bExcludeRPBandIMGFileWriting)
3828 :
3829 : {
3830 : /* -------------------------------------------------------------------- */
3831 : /* Convert all the remaining metadata into a simple XML */
3832 : /* format. */
3833 : /* -------------------------------------------------------------------- */
3834 810 : CPLXMLNode *psRoot = NULL, *psTail = NULL;
3835 :
3836 810 : if( bSrcIsGeoTIFF )
3837 : {
3838 : WriteMDMetadata( &(((GTiffDataset *)poSrcDS)->oGTiffMDMD),
3839 700 : hTIFF, &psRoot, &psTail, 0, pszProfile );
3840 : }
3841 : else
3842 : {
3843 110 : char **papszMD = poSrcDS->GetMetadata();
3844 :
3845 110 : if( CSLCount(papszMD) > 0 )
3846 : {
3847 62 : GDALMultiDomainMetadata oMDMD;
3848 62 : oMDMD.SetMetadata( papszMD );
3849 :
3850 62 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, 0, pszProfile );
3851 : }
3852 : }
3853 :
3854 : /* -------------------------------------------------------------------- */
3855 : /* Handle RPC data written to an RPB file. */
3856 : /* -------------------------------------------------------------------- */
3857 810 : char **papszRPCMD = poSrcDS->GetMetadata("RPC");
3858 810 : if( papszRPCMD != NULL && !bExcludeRPBandIMGFileWriting )
3859 : {
3860 2 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
3861 1 : WriteRPCTag( hTIFF, papszRPCMD );
3862 :
3863 2 : if( !EQUAL(pszProfile,"GDALGeoTIFF")
3864 : || CSLFetchBoolean( papszCreationOptions, "RPB", FALSE ) )
3865 : {
3866 1 : GDALWriteRPBFile( pszTIFFFilename, papszRPCMD );
3867 : }
3868 : }
3869 :
3870 : /* -------------------------------------------------------------------- */
3871 : /* Handle metadata data written to an IMD file. */
3872 : /* -------------------------------------------------------------------- */
3873 810 : char **papszIMDMD = poSrcDS->GetMetadata("IMD");
3874 810 : if( papszIMDMD != NULL && !bExcludeRPBandIMGFileWriting)
3875 : {
3876 2 : GDALWriteIMDFile( pszTIFFFilename, papszIMDMD );
3877 : }
3878 :
3879 : /* -------------------------------------------------------------------- */
3880 : /* We also need to address band specific metadata, and special */
3881 : /* "role" metadata. */
3882 : /* -------------------------------------------------------------------- */
3883 : int nBand;
3884 132916 : for( nBand = 1; nBand <= poSrcDS->GetRasterCount(); nBand++ )
3885 : {
3886 132106 : GDALRasterBand *poBand = poSrcDS->GetRasterBand( nBand );
3887 :
3888 132106 : if( bSrcIsGeoTIFF )
3889 : {
3890 : WriteMDMetadata( &(((GTiffRasterBand *)poBand)->oGTiffMDMD),
3891 131913 : hTIFF, &psRoot, &psTail, nBand, pszProfile );
3892 : }
3893 : else
3894 : {
3895 193 : char **papszMD = poBand->GetMetadata();
3896 :
3897 193 : if( CSLCount(papszMD) > 0 )
3898 : {
3899 26 : GDALMultiDomainMetadata oMDMD;
3900 26 : oMDMD.SetMetadata( papszMD );
3901 :
3902 : WriteMDMetadata( &oMDMD, hTIFF, &psRoot, &psTail, nBand,
3903 26 : pszProfile );
3904 : }
3905 : }
3906 :
3907 : int bSuccess;
3908 132106 : double dfOffset = poBand->GetOffset( &bSuccess );
3909 132106 : double dfScale = poBand->GetScale();
3910 :
3911 132106 : if( bSuccess && (dfOffset != 0.0 || dfScale != 1.0) )
3912 : {
3913 : char szValue[128];
3914 :
3915 0 : sprintf( szValue, "%.18g", dfOffset );
3916 : AppendMetadataItem( &psRoot, &psTail, "OFFSET", szValue, nBand,
3917 0 : "offset", "" );
3918 0 : sprintf( szValue, "%.18g", dfScale );
3919 : AppendMetadataItem( &psRoot, &psTail, "SCALE", szValue, nBand,
3920 0 : "scale", "" );
3921 : }
3922 : }
3923 :
3924 : /* -------------------------------------------------------------------- */
3925 : /* Write out the generic XML metadata if there is any. */
3926 : /* -------------------------------------------------------------------- */
3927 810 : if( psRoot != NULL )
3928 : {
3929 47 : int bRet = TRUE;
3930 :
3931 47 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
3932 : {
3933 37 : char *pszXML_MD = CPLSerializeXMLTree( psRoot );
3934 37 : if( strlen(pszXML_MD) > 32000 )
3935 : {
3936 1 : if( bSrcIsGeoTIFF )
3937 1 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
3938 : else
3939 0 : bRet = FALSE;
3940 : CPLError( CE_Warning, CPLE_AppDefined,
3941 1 : "Lost metadata writing to GeoTIFF ... too large to fit in tag." );
3942 : }
3943 : else
3944 : {
3945 36 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszXML_MD );
3946 : }
3947 37 : CPLFree( pszXML_MD );
3948 : }
3949 : else
3950 : {
3951 10 : if( bSrcIsGeoTIFF )
3952 6 : ((GTiffDataset *) poSrcDS)->PushMetadataToPam();
3953 : else
3954 4 : bRet = FALSE;
3955 : }
3956 :
3957 47 : CPLDestroyXMLNode( psRoot );
3958 :
3959 47 : return bRet;
3960 : }
3961 :
3962 763 : return TRUE;
3963 : }
3964 :
3965 : /************************************************************************/
3966 : /* PushMetadataToPam() */
3967 : /* */
3968 : /* When producing a strict profile TIFF or if our aggregate */
3969 : /* metadata is too big for a single tiff tag we may end up */
3970 : /* needing to write it via the PAM mechanisms. This method */
3971 : /* copies all the appropriate metadata into the PAM level */
3972 : /* metadata object but with special care to avoid copying */
3973 : /* metadata handled in other ways in TIFF format. */
3974 : /************************************************************************/
3975 :
3976 21 : void GTiffDataset::PushMetadataToPam()
3977 :
3978 : {
3979 : int nBand;
3980 75 : for( nBand = 0; nBand <= GetRasterCount(); nBand++ )
3981 : {
3982 : GDALMultiDomainMetadata *poSrcMDMD;
3983 54 : GTiffRasterBand *poBand = NULL;
3984 :
3985 54 : if( nBand == 0 )
3986 21 : poSrcMDMD = &(this->oGTiffMDMD);
3987 : else
3988 : {
3989 33 : poBand = (GTiffRasterBand *) GetRasterBand(nBand);
3990 33 : poSrcMDMD = &(poBand->oGTiffMDMD);
3991 : }
3992 :
3993 : /* -------------------------------------------------------------------- */
3994 : /* Loop over the available domains. */
3995 : /* -------------------------------------------------------------------- */
3996 : int iDomain, i;
3997 : char **papszDomainList;
3998 :
3999 54 : papszDomainList = poSrcMDMD->GetDomainList();
4000 251 : for( iDomain = 0;
4001 125 : papszDomainList && papszDomainList[iDomain];
4002 : iDomain++ )
4003 : {
4004 72 : char **papszMD = poSrcMDMD->GetMetadata( papszDomainList[iDomain] );
4005 :
4006 288 : if( EQUAL(papszDomainList[iDomain],"RPC")
4007 72 : || EQUAL(papszDomainList[iDomain],"IMD")
4008 72 : || EQUAL(papszDomainList[iDomain],"_temporary_")
4009 72 : || EQUAL(papszDomainList[iDomain],"IMAGE_STRUCTURE") )
4010 24 : continue;
4011 :
4012 48 : papszMD = CSLDuplicate(papszMD);
4013 :
4014 167 : for( i = CSLCount(papszMD)-1; i >= 0; i-- )
4015 : {
4016 232 : if( EQUALN(papszMD[i],"TIFFTAG_",8)
4017 113 : || EQUALN(papszMD[i],GDALMD_AREA_OR_POINT,
4018 : strlen(GDALMD_AREA_OR_POINT)) )
4019 20 : papszMD = CSLRemoveStrings( papszMD, i, 1, NULL );
4020 : }
4021 :
4022 48 : if( nBand == 0 )
4023 20 : GDALPamDataset::SetMetadata( papszMD, papszDomainList[iDomain]);
4024 : else
4025 28 : poBand->GDALPamRasterBand::SetMetadata( papszMD, papszDomainList[iDomain]);
4026 :
4027 48 : CSLDestroy( papszMD );
4028 : }
4029 :
4030 : /* -------------------------------------------------------------------- */
4031 : /* Handle some "special domain" stuff. */
4032 : /* -------------------------------------------------------------------- */
4033 54 : if( poBand != NULL )
4034 : {
4035 : int bSuccess;
4036 33 : double dfOffset = poBand->GetOffset( &bSuccess );
4037 33 : double dfScale = poBand->GetScale();
4038 :
4039 33 : if( bSuccess && (dfOffset != 0.0 || dfScale != 1.0) )
4040 : {
4041 0 : poBand->GDALPamRasterBand::SetScale( dfScale );
4042 0 : poBand->GDALPamRasterBand::SetOffset( dfOffset );
4043 : }
4044 : }
4045 : }
4046 21 : }
4047 :
4048 : /************************************************************************/
4049 : /* WriteRPCTag() */
4050 : /* */
4051 : /* Format a TAG according to: */
4052 : /* */
4053 : /* http://geotiff.maptools.org/rpc_prop.html */
4054 : /************************************************************************/
4055 :
4056 : /* static */
4057 1 : void GTiffDataset::WriteRPCTag( TIFF *hTIFF, char **papszRPCMD )
4058 :
4059 : {
4060 : double adfRPCTag[92];
4061 : GDALRPCInfo sRPC;
4062 :
4063 1 : if( !GDALExtractRPCInfo( papszRPCMD, &sRPC ) )
4064 0 : return;
4065 :
4066 1 : adfRPCTag[0] = -1.0; // Error Bias
4067 1 : adfRPCTag[1] = -1.0; // Error Random
4068 :
4069 1 : adfRPCTag[2] = sRPC.dfLINE_OFF;
4070 1 : adfRPCTag[3] = sRPC.dfSAMP_OFF;
4071 1 : adfRPCTag[4] = sRPC.dfLAT_OFF;
4072 1 : adfRPCTag[5] = sRPC.dfLONG_OFF;
4073 1 : adfRPCTag[6] = sRPC.dfHEIGHT_OFF;
4074 1 : adfRPCTag[7] = sRPC.dfLINE_SCALE;
4075 1 : adfRPCTag[8] = sRPC.dfSAMP_SCALE;
4076 1 : adfRPCTag[9] = sRPC.dfLAT_SCALE;
4077 1 : adfRPCTag[10] = sRPC.dfLONG_SCALE;
4078 1 : adfRPCTag[11] = sRPC.dfHEIGHT_SCALE;
4079 :
4080 1 : memcpy( adfRPCTag + 12, sRPC.adfLINE_NUM_COEFF, sizeof(double) * 20 );
4081 1 : memcpy( adfRPCTag + 32, sRPC.adfLINE_DEN_COEFF, sizeof(double) * 20 );
4082 1 : memcpy( adfRPCTag + 52, sRPC.adfSAMP_NUM_COEFF, sizeof(double) * 20 );
4083 1 : memcpy( adfRPCTag + 72, sRPC.adfSAMP_DEN_COEFF, sizeof(double) * 20 );
4084 :
4085 1 : TIFFSetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, 92, adfRPCTag );
4086 : }
4087 :
4088 : /************************************************************************/
4089 : /* ReadRPCTag() */
4090 : /* */
4091 : /* Format a TAG according to: */
4092 : /* */
4093 : /* http://geotiff.maptools.org/rpc_prop.html */
4094 : /************************************************************************/
4095 :
4096 2847 : void GTiffDataset::ReadRPCTag()
4097 :
4098 : {
4099 : double *padfRPCTag;
4100 2847 : char **papszMD = NULL;
4101 2847 : CPLString osField;
4102 2847 : CPLString osMultiField;
4103 : int i;
4104 : uint16 nCount;
4105 :
4106 2847 : if( !TIFFGetField( hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag )
4107 : || nCount != 92 )
4108 : return;
4109 :
4110 3 : osField.Printf( "%.15g", padfRPCTag[2] );
4111 3 : papszMD = CSLSetNameValue( papszMD, "LINE_OFF", osField );
4112 :
4113 3 : osField.Printf( "%.15g", padfRPCTag[3] );
4114 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_OFF", osField );
4115 :
4116 3 : osField.Printf( "%.15g", padfRPCTag[4] );
4117 3 : papszMD = CSLSetNameValue( papszMD, "LAT_OFF", osField );
4118 :
4119 3 : osField.Printf( "%.15g", padfRPCTag[5] );
4120 3 : papszMD = CSLSetNameValue( papszMD, "LONG_OFF", osField );
4121 :
4122 3 : osField.Printf( "%.15g", padfRPCTag[6] );
4123 3 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_OFF", osField );
4124 :
4125 3 : osField.Printf( "%.15g", padfRPCTag[7] );
4126 3 : papszMD = CSLSetNameValue( papszMD, "LINE_SCALE", osField );
4127 :
4128 3 : osField.Printf( "%.15g", padfRPCTag[8] );
4129 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_SCALE", osField );
4130 :
4131 3 : osField.Printf( "%.15g", padfRPCTag[9] );
4132 3 : papszMD = CSLSetNameValue( papszMD, "LAT_SCALE", osField );
4133 :
4134 3 : osField.Printf( "%.15g", padfRPCTag[10] );
4135 3 : papszMD = CSLSetNameValue( papszMD, "LONG_SCALE", osField );
4136 :
4137 3 : osField.Printf( "%.15g", padfRPCTag[11] );
4138 3 : papszMD = CSLSetNameValue( papszMD, "HEIGHT_SCALE", osField );
4139 :
4140 63 : for( i = 0; i < 20; i++ )
4141 : {
4142 60 : osField.Printf( "%.15g", padfRPCTag[12+i] );
4143 60 : if( i > 0 )
4144 57 : osMultiField += " ";
4145 : else
4146 3 : osMultiField = "";
4147 60 : osMultiField += osField;
4148 : }
4149 3 : papszMD = CSLSetNameValue( papszMD, "LINE_NUM_COEFF", osMultiField );
4150 :
4151 63 : for( i = 0; i < 20; i++ )
4152 : {
4153 60 : osField.Printf( "%.15g", padfRPCTag[32+i] );
4154 60 : if( i > 0 )
4155 57 : osMultiField += " ";
4156 : else
4157 3 : osMultiField = "";
4158 60 : osMultiField += osField;
4159 : }
4160 3 : papszMD = CSLSetNameValue( papszMD, "LINE_DEN_COEFF", osMultiField );
4161 :
4162 63 : for( i = 0; i < 20; i++ )
4163 : {
4164 60 : osField.Printf( "%.15g", padfRPCTag[52+i] );
4165 60 : if( i > 0 )
4166 57 : osMultiField += " ";
4167 : else
4168 3 : osMultiField = "";
4169 60 : osMultiField += osField;
4170 : }
4171 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_NUM_COEFF", osMultiField );
4172 :
4173 63 : for( i = 0; i < 20; i++ )
4174 : {
4175 60 : osField.Printf( "%.15g", padfRPCTag[72+i] );
4176 60 : if( i > 0 )
4177 57 : osMultiField += " ";
4178 : else
4179 3 : osMultiField = "";
4180 60 : osMultiField += osField;
4181 : }
4182 3 : papszMD = CSLSetNameValue( papszMD, "SAMP_DEN_COEFF", osMultiField );
4183 :
4184 3 : oGTiffMDMD.SetMetadata( papszMD, "RPC" );
4185 3 : CSLDestroy( papszMD );
4186 : }
4187 :
4188 : /************************************************************************/
4189 : /* WriteNoDataValue() */
4190 : /************************************************************************/
4191 :
4192 55 : void GTiffDataset::WriteNoDataValue( TIFF *hTIFF, double dfNoData )
4193 :
4194 : {
4195 : TIFFSetField( hTIFF, TIFFTAG_GDAL_NODATA,
4196 55 : CPLString().Printf( "%.18g", dfNoData ).c_str() );
4197 55 : }
4198 :
4199 : /************************************************************************/
4200 : /* SetDirectory() */
4201 : /************************************************************************/
4202 :
4203 173634 : int GTiffDataset::SetDirectory( toff_t nNewOffset )
4204 :
4205 : {
4206 173634 : Crystalize();
4207 :
4208 173634 : FlushBlockBuf();
4209 :
4210 173634 : if( nNewOffset == 0 )
4211 170446 : nNewOffset = nDirOffset;
4212 :
4213 173634 : if( TIFFCurrentDirOffset(hTIFF) == nNewOffset )
4214 : {
4215 : CPLAssert( *ppoActiveDSRef == this || *ppoActiveDSRef == NULL );
4216 172619 : *ppoActiveDSRef = this;
4217 172619 : return TRUE;
4218 : }
4219 :
4220 1015 : int jquality = -1, zquality = -1;
4221 :
4222 1015 : if( GetAccess() == GA_Update )
4223 : {
4224 719 : TIFFGetField(hTIFF, TIFFTAG_JPEGQUALITY, &jquality);
4225 719 : TIFFGetField(hTIFF, TIFFTAG_ZIPQUALITY, &zquality);
4226 :
4227 719 : if( *ppoActiveDSRef != NULL )
4228 650 : (*ppoActiveDSRef)->FlushDirectory();
4229 : }
4230 :
4231 1015 : if( nNewOffset == 0)
4232 0 : return TRUE;
4233 :
4234 1015 : (*ppoActiveDSRef) = this;
4235 :
4236 1015 : int nSetDirResult = TIFFSetSubDirectory( hTIFF, nNewOffset );
4237 1015 : if (!nSetDirResult)
4238 0 : return nSetDirResult;
4239 :
4240 : /* -------------------------------------------------------------------- */
4241 : /* YCbCr JPEG compressed images should be translated on the fly */
4242 : /* to RGB by libtiff/libjpeg unless specifically requested */
4243 : /* otherwise. */
4244 : /* -------------------------------------------------------------------- */
4245 1015 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
4246 0 : nCompression = COMPRESSION_NONE;
4247 :
4248 1015 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
4249 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
4250 :
4251 1015 : if( nCompression == COMPRESSION_JPEG
4252 : && nPhotometric == PHOTOMETRIC_YCBCR
4253 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
4254 : "YES") ) )
4255 : {
4256 : int nColorMode;
4257 :
4258 18 : TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode );
4259 18 : if( nColorMode != JPEGCOLORMODE_RGB )
4260 18 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4261 : }
4262 :
4263 : /* -------------------------------------------------------------------- */
4264 : /* Propogate any quality settings. */
4265 : /* -------------------------------------------------------------------- */
4266 1015 : if( GetAccess() == GA_Update )
4267 : {
4268 : // Now, reset zip and jpeg quality.
4269 719 : if(jquality > 0)
4270 : {
4271 : CPLDebug( "GTiff", "Propgate JPEG_QUALITY(%d) in SetDirectory()",
4272 4 : jquality );
4273 4 : TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, jquality);
4274 : }
4275 719 : if(zquality > 0)
4276 0 : TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, zquality);
4277 : }
4278 :
4279 1015 : return nSetDirResult;
4280 : }
4281 :
4282 : /************************************************************************/
4283 : /* Identify() */
4284 : /************************************************************************/
4285 :
4286 13338 : int GTiffDataset::Identify( GDALOpenInfo * poOpenInfo )
4287 :
4288 : {
4289 13338 : const char *pszFilename = poOpenInfo->pszFilename;
4290 13338 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4291 : {
4292 115 : pszFilename += strlen("GTIFF_RAW:");
4293 115 : GDALOpenInfo oOpenInfo( pszFilename, poOpenInfo->eAccess );
4294 115 : return Identify(&oOpenInfo);
4295 : }
4296 :
4297 : /* -------------------------------------------------------------------- */
4298 : /* We have a special hook for handling opening a specific */
4299 : /* directory of a TIFF file. */
4300 : /* -------------------------------------------------------------------- */
4301 13223 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4302 4 : return TRUE;
4303 :
4304 : /* -------------------------------------------------------------------- */
4305 : /* First we check to see if the file has the expected header */
4306 : /* bytes. */
4307 : /* -------------------------------------------------------------------- */
4308 13219 : if( poOpenInfo->nHeaderBytes < 2 )
4309 8613 : return FALSE;
4310 :
4311 6484 : if( (poOpenInfo->pabyHeader[0] != 'I' || poOpenInfo->pabyHeader[1] != 'I')
4312 1878 : && (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
4313 1747 : return FALSE;
4314 :
4315 : #ifndef BIGTIFF_SUPPORT
4316 : if( (poOpenInfo->pabyHeader[2] == 0x2B && poOpenInfo->pabyHeader[3] == 0) ||
4317 : (poOpenInfo->pabyHeader[2] == 0 && poOpenInfo->pabyHeader[3] == 0x2B) )
4318 : {
4319 : CPLError( CE_Failure, CPLE_OpenFailed,
4320 : "This is a BigTIFF file. BigTIFF is not supported by this\n"
4321 : "version of GDAL and libtiff." );
4322 : return FALSE;
4323 : }
4324 : #endif
4325 :
4326 3107 : if( (poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0)
4327 156 : && (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0)
4328 76 : && (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0)
4329 16 : && (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
4330 0 : return FALSE;
4331 :
4332 2859 : return TRUE;
4333 : }
4334 :
4335 : /************************************************************************/
4336 : /* Open() */
4337 : /************************************************************************/
4338 :
4339 5483 : GDALDataset *GTiffDataset::Open( GDALOpenInfo * poOpenInfo )
4340 :
4341 : {
4342 : TIFF *hTIFF;
4343 5483 : int bAllowRGBAInterface = TRUE;
4344 5483 : const char *pszFilename = poOpenInfo->pszFilename;
4345 :
4346 : /* -------------------------------------------------------------------- */
4347 : /* Check if it looks like a TIFF file. */
4348 : /* -------------------------------------------------------------------- */
4349 5483 : if (!Identify(poOpenInfo))
4350 2629 : return NULL;
4351 :
4352 2854 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4353 : {
4354 115 : bAllowRGBAInterface = FALSE;
4355 115 : pszFilename += strlen("GTIFF_RAW:");
4356 : }
4357 :
4358 : /* -------------------------------------------------------------------- */
4359 : /* We have a special hook for handling opening a specific */
4360 : /* directory of a TIFF file. */
4361 : /* -------------------------------------------------------------------- */
4362 2854 : if( EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4363 4 : return OpenDir( poOpenInfo );
4364 :
4365 2850 : GTiffOneTimeInit();
4366 :
4367 : /* -------------------------------------------------------------------- */
4368 : /* Try opening the dataset. */
4369 : /* -------------------------------------------------------------------- */
4370 2850 : if( poOpenInfo->eAccess == GA_ReadOnly )
4371 2619 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
4372 : else
4373 231 : hTIFF = VSI_TIFFOpen( pszFilename, "r+" );
4374 :
4375 2850 : if( hTIFF == NULL )
4376 0 : return( NULL );
4377 :
4378 : /* -------------------------------------------------------------------- */
4379 : /* Create a corresponding GDALDataset. */
4380 : /* -------------------------------------------------------------------- */
4381 : GTiffDataset *poDS;
4382 :
4383 2850 : poDS = new GTiffDataset();
4384 2850 : poDS->SetDescription( pszFilename );
4385 5700 : poDS->osFilename = pszFilename;
4386 2850 : poDS->poActiveDS = poDS;
4387 :
4388 2850 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
4389 : TIFFCurrentDirOffset(hTIFF), TRUE,
4390 : poOpenInfo->eAccess,
4391 : bAllowRGBAInterface ) != CE_None )
4392 : {
4393 0 : delete poDS;
4394 0 : return NULL;
4395 : }
4396 :
4397 : /* -------------------------------------------------------------------- */
4398 : /* Initialize any PAM information. */
4399 : /* -------------------------------------------------------------------- */
4400 2850 : poDS->TryLoadXML();
4401 2850 : poDS->ApplyPamInfo();
4402 :
4403 2850 : poDS->bMetadataChanged = FALSE;
4404 2850 : poDS->bGeoTIFFInfoChanged = FALSE;
4405 :
4406 : /* -------------------------------------------------------------------- */
4407 : /* Check for external overviews. */
4408 : /* -------------------------------------------------------------------- */
4409 2850 : poDS->oOvManager.Initialize( poDS, pszFilename );
4410 :
4411 2850 : return poDS;
4412 : }
4413 :
4414 : /************************************************************************/
4415 : /* LookForProjection() */
4416 : /************************************************************************/
4417 :
4418 3517 : void GTiffDataset::LookForProjection()
4419 :
4420 : {
4421 3517 : if( bLookedForProjection )
4422 2662 : return;
4423 :
4424 855 : bLookedForProjection = TRUE;
4425 855 : if (!SetDirectory())
4426 0 : return;
4427 :
4428 : /* -------------------------------------------------------------------- */
4429 : /* Capture the GeoTIFF projection, if available. */
4430 : /* -------------------------------------------------------------------- */
4431 : GTIF *hGTIF;
4432 : GTIFDefn sGTIFDefn;
4433 :
4434 855 : CPLFree( pszProjection );
4435 855 : pszProjection = NULL;
4436 :
4437 855 : hGTIF = GTIFNew(hTIFF);
4438 :
4439 855 : if ( !hGTIF )
4440 : {
4441 : CPLError( CE_Warning, CPLE_AppDefined,
4442 0 : "GeoTIFF tags apparently corrupt, they are being ignored." );
4443 : }
4444 : else
4445 : {
4446 855 : if( GTIFGetDefn( hGTIF, &sGTIFDefn ) )
4447 : {
4448 829 : pszProjection = GTIFGetOGISDefn( hGTIF, &sGTIFDefn );
4449 :
4450 : // Should we simplify away vertical CS stuff?
4451 829 : if( EQUALN(pszProjection,"COMPD_CS",8)
4452 : && !CSLTestBoolean( CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
4453 : "NO") ) )
4454 : {
4455 0 : OGRSpatialReference oSRS;
4456 :
4457 0 : CPLDebug( "GTiff", "Got COMPD_CS, but stripping it." );
4458 0 : char *pszWKT = pszProjection;
4459 0 : oSRS.importFromWkt( &pszWKT );
4460 0 : CPLFree( pszProjection );
4461 :
4462 0 : oSRS.StripVertical();
4463 0 : oSRS.exportToWkt( &pszProjection );
4464 : }
4465 : }
4466 :
4467 : // Is this a pixel-is-point dataset?
4468 : short nRasterType;
4469 :
4470 855 : if( GTIFKeyGet(hGTIF, GTRasterTypeGeoKey, &nRasterType,
4471 : 0, 1 ) == 1 )
4472 : {
4473 828 : int bMetadataChangedSaved = bMetadataChanged;
4474 828 : if( nRasterType == (short) RasterPixelIsPoint )
4475 3 : SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_POINT );
4476 : else
4477 825 : SetMetadataItem( GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA );
4478 828 : bMetadataChanged = bMetadataChangedSaved;
4479 : }
4480 :
4481 855 : GTIFFree( hGTIF );
4482 : }
4483 :
4484 855 : if( pszProjection == NULL )
4485 : {
4486 26 : pszProjection = CPLStrdup( "" );
4487 : }
4488 :
4489 855 : bGeoTIFFInfoChanged = FALSE;
4490 : }
4491 :
4492 : /************************************************************************/
4493 : /* ApplyPamInfo() */
4494 : /* */
4495 : /* PAM Information, if available, overrides the GeoTIFF */
4496 : /* geotransform and projection definition. Check for them */
4497 : /* now. */
4498 : /************************************************************************/
4499 :
4500 2850 : void GTiffDataset::ApplyPamInfo()
4501 :
4502 : {
4503 : double adfPamGeoTransform[6];
4504 :
4505 2850 : if( GDALPamDataset::GetGeoTransform( adfPamGeoTransform ) == CE_None
4506 0 : && (adfPamGeoTransform[0] != 0.0 || adfPamGeoTransform[1] != 1.0
4507 0 : || adfPamGeoTransform[2] != 0.0 || adfPamGeoTransform[3] != 0.0
4508 0 : || adfPamGeoTransform[4] != 0.0 || adfPamGeoTransform[5] != 1.0 ))
4509 : {
4510 0 : memcpy( adfGeoTransform, adfPamGeoTransform, sizeof(double)*6 );
4511 0 : bGeoTransformValid = TRUE;
4512 : }
4513 :
4514 2850 : const char *pszPamSRS = GDALPamDataset::GetProjectionRef();
4515 :
4516 2850 : if( pszPamSRS != NULL && strlen(pszPamSRS) > 0 )
4517 : {
4518 0 : CPLFree( pszProjection );
4519 0 : pszProjection = CPLStrdup( pszPamSRS );
4520 0 : bLookedForProjection= TRUE;
4521 : }
4522 :
4523 : /* -------------------------------------------------------------------- */
4524 : /* Copy any PAM metadata into our GeoTIFF context, but with the */
4525 : /* GeoTIFF context overriding the PAM info. */
4526 : /* -------------------------------------------------------------------- */
4527 2850 : char **papszPamDomains = oMDMD.GetDomainList();
4528 :
4529 2858 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
4530 : {
4531 8 : const char *pszDomain = papszPamDomains[iDomain];
4532 8 : char **papszGT_MD = oGTiffMDMD.GetMetadata( pszDomain );
4533 8 : char **papszPAM_MD = CSLDuplicate(oMDMD.GetMetadata( pszDomain ));
4534 :
4535 8 : papszPAM_MD = CSLMerge( papszPAM_MD, papszGT_MD );
4536 :
4537 8 : oGTiffMDMD.SetMetadata( papszPAM_MD, pszDomain );
4538 8 : CSLDestroy( papszPAM_MD );
4539 : }
4540 :
4541 268559 : for( int i = 1; i <= GetRasterCount(); i++)
4542 : {
4543 265709 : GTiffRasterBand* poBand = (GTiffRasterBand *)GetRasterBand(i);
4544 265709 : papszPamDomains = poBand->oMDMD.GetDomainList();
4545 :
4546 265735 : for( int iDomain = 0; papszPamDomains && papszPamDomains[iDomain] != NULL; iDomain++ )
4547 : {
4548 26 : const char *pszDomain = papszPamDomains[iDomain];
4549 26 : char **papszGT_MD = poBand->oGTiffMDMD.GetMetadata( pszDomain );
4550 26 : char **papszPAM_MD = CSLDuplicate(poBand->oMDMD.GetMetadata( pszDomain ));
4551 :
4552 26 : papszPAM_MD = CSLMerge( papszPAM_MD, papszGT_MD );
4553 :
4554 26 : poBand->oGTiffMDMD.SetMetadata( papszPAM_MD, pszDomain );
4555 26 : CSLDestroy( papszPAM_MD );
4556 : }
4557 : }
4558 2850 : }
4559 :
4560 : /************************************************************************/
4561 : /* OpenDir() */
4562 : /* */
4563 : /* Open a specific directory as encoded into a filename. */
4564 : /************************************************************************/
4565 :
4566 4 : GDALDataset *GTiffDataset::OpenDir( GDALOpenInfo * poOpenInfo )
4567 :
4568 : {
4569 4 : int bAllowRGBAInterface = TRUE;
4570 4 : const char* pszFilename = poOpenInfo->pszFilename;
4571 4 : if( EQUALN(pszFilename,"GTIFF_RAW:", strlen("GTIFF_RAW:")) )
4572 : {
4573 0 : bAllowRGBAInterface = FALSE;
4574 0 : pszFilename += strlen("GTIFF_RAW:");
4575 : }
4576 :
4577 4 : if( !EQUALN(pszFilename,"GTIFF_DIR:",strlen("GTIFF_DIR:")) )
4578 0 : return NULL;
4579 :
4580 : /* -------------------------------------------------------------------- */
4581 : /* Split out filename, and dir#/offset. */
4582 : /* -------------------------------------------------------------------- */
4583 4 : pszFilename += strlen("GTIFF_DIR:");
4584 4 : int bAbsolute = FALSE;
4585 : toff_t nOffset;
4586 :
4587 4 : if( EQUALN(pszFilename,"off:",4) )
4588 : {
4589 1 : bAbsolute = TRUE;
4590 1 : pszFilename += 4;
4591 : }
4592 :
4593 4 : nOffset = atol(pszFilename);
4594 4 : pszFilename += 1;
4595 :
4596 14 : while( *pszFilename != '\0' && pszFilename[-1] != ':' )
4597 6 : pszFilename++;
4598 :
4599 4 : if( *pszFilename == '\0' || nOffset == 0 )
4600 : {
4601 : CPLError( CE_Failure, CPLE_OpenFailed,
4602 : "Unable to extract offset or filename, should take the form\n"
4603 0 : "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename" );
4604 0 : return NULL;
4605 : }
4606 :
4607 : /* -------------------------------------------------------------------- */
4608 : /* Try opening the dataset. */
4609 : /* -------------------------------------------------------------------- */
4610 : TIFF *hTIFF;
4611 :
4612 4 : GTiffOneTimeInit();
4613 :
4614 4 : hTIFF = VSI_TIFFOpen( pszFilename, "r" );
4615 4 : if( hTIFF == NULL )
4616 0 : return( NULL );
4617 :
4618 : /* -------------------------------------------------------------------- */
4619 : /* If a directory was requested by index, advance to it now. */
4620 : /* -------------------------------------------------------------------- */
4621 4 : if( !bAbsolute )
4622 : {
4623 7 : while( nOffset > 1 )
4624 : {
4625 1 : if( TIFFReadDirectory( hTIFF ) == 0 )
4626 : {
4627 0 : XTIFFClose( hTIFF );
4628 : CPLError( CE_Failure, CPLE_OpenFailed,
4629 0 : "Requested directory %lu not found.", (long unsigned int)nOffset );
4630 0 : return NULL;
4631 : }
4632 1 : nOffset--;
4633 : }
4634 :
4635 3 : nOffset = TIFFCurrentDirOffset( hTIFF );
4636 : }
4637 :
4638 : /* -------------------------------------------------------------------- */
4639 : /* Create a corresponding GDALDataset. */
4640 : /* -------------------------------------------------------------------- */
4641 : GTiffDataset *poDS;
4642 :
4643 4 : poDS = new GTiffDataset();
4644 4 : poDS->SetDescription( poOpenInfo->pszFilename );
4645 8 : poDS->osFilename = poOpenInfo->pszFilename;
4646 4 : poDS->poActiveDS = poDS;
4647 :
4648 8 : if( !EQUAL(pszFilename,poOpenInfo->pszFilename)
4649 : && !EQUALN(poOpenInfo->pszFilename,"GTIFF_RAW:",10) )
4650 : {
4651 4 : poDS->SetPhysicalFilename( pszFilename );
4652 4 : poDS->SetSubdatasetName( poOpenInfo->pszFilename );
4653 4 : poDS->osFilename = pszFilename;
4654 : }
4655 :
4656 4 : if (poOpenInfo->eAccess == GA_Update)
4657 : {
4658 : CPLError( CE_Warning, CPLE_AppDefined,
4659 0 : "Opening a specific TIFF directory is not supported in update mode. Switching to read-only" );
4660 : }
4661 :
4662 4 : if( poDS->OpenOffset( hTIFF, &(poDS->poActiveDS),
4663 : nOffset, FALSE, GA_ReadOnly, bAllowRGBAInterface ) != CE_None )
4664 : {
4665 0 : delete poDS;
4666 0 : return NULL;
4667 : }
4668 : else
4669 : {
4670 4 : poDS->bCloseTIFFHandle = TRUE;
4671 4 : return poDS;
4672 : }
4673 : }
4674 :
4675 : /************************************************************************/
4676 : /* OpenOffset() */
4677 : /* */
4678 : /* Initialize the GTiffDataset based on a passed in file */
4679 : /* handle, and directory offset to utilize. This is called for */
4680 : /* full res, and overview pages. */
4681 : /************************************************************************/
4682 :
4683 3188 : CPLErr GTiffDataset::OpenOffset( TIFF *hTIFFIn,
4684 : GTiffDataset **ppoActiveDSRef,
4685 : toff_t nDirOffsetIn,
4686 : int bBaseIn, GDALAccess eAccess,
4687 : int bAllowRGBAInterface)
4688 :
4689 : {
4690 : uint32 nXSize, nYSize;
4691 3188 : int bTreatAsBitmap = FALSE;
4692 3188 : int bTreatAsOdd = FALSE;
4693 :
4694 3188 : this->eAccess = eAccess;
4695 :
4696 3188 : hTIFF = hTIFFIn;
4697 3188 : this->ppoActiveDSRef = ppoActiveDSRef;
4698 :
4699 3188 : nDirOffset = nDirOffsetIn;
4700 :
4701 3188 : if (!SetDirectory( nDirOffsetIn ))
4702 0 : return CE_Failure;
4703 :
4704 3188 : bBase = bBaseIn;
4705 :
4706 3188 : this->eAccess = eAccess;
4707 :
4708 : /* -------------------------------------------------------------------- */
4709 : /* Capture some information from the file that is of interest. */
4710 : /* -------------------------------------------------------------------- */
4711 3188 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
4712 3188 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
4713 3188 : nRasterXSize = nXSize;
4714 3188 : nRasterYSize = nYSize;
4715 :
4716 3188 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSamplesPerPixel ) )
4717 0 : nBands = 1;
4718 : else
4719 3188 : nBands = nSamplesPerPixel;
4720 :
4721 3188 : if( !TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(nBitsPerSample)) )
4722 0 : nBitsPerSample = 1;
4723 :
4724 3188 : if( !TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(nPlanarConfig) ) )
4725 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
4726 :
4727 3188 : if( !TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(nPhotometric) ) )
4728 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
4729 :
4730 3188 : if( !TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(nSampleFormat) ) )
4731 8 : nSampleFormat = SAMPLEFORMAT_UINT;
4732 :
4733 3188 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
4734 0 : nCompression = COMPRESSION_NONE;
4735 :
4736 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
4737 3188 : if (nCompression != COMPRESSION_NONE &&
4738 : !TIFFIsCODECConfigured(nCompression))
4739 : {
4740 : CPLError( CE_Failure, CPLE_AppDefined,
4741 0 : "Cannot open TIFF file due to missing codec." );
4742 0 : return CE_Failure;
4743 : }
4744 : #endif
4745 :
4746 : /* -------------------------------------------------------------------- */
4747 : /* YCbCr JPEG compressed images should be translated on the fly */
4748 : /* to RGB by libtiff/libjpeg unless specifically requested */
4749 : /* otherwise. */
4750 : /* -------------------------------------------------------------------- */
4751 3188 : if( nCompression == COMPRESSION_JPEG
4752 : && nPhotometric == PHOTOMETRIC_YCBCR
4753 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
4754 : "YES") ) )
4755 : {
4756 : int nColorMode;
4757 :
4758 44 : SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
4759 44 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
4760 : nColorMode != JPEGCOLORMODE_RGB )
4761 42 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
4762 : }
4763 :
4764 : /* -------------------------------------------------------------------- */
4765 : /* Get strip/tile layout. */
4766 : /* -------------------------------------------------------------------- */
4767 3188 : if( TIFFIsTiled(hTIFF) )
4768 : {
4769 433 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(nBlockXSize) );
4770 433 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(nBlockYSize) );
4771 : }
4772 : else
4773 : {
4774 2755 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
4775 : &(nRowsPerStrip) ) )
4776 : {
4777 : CPLError( CE_Warning, CPLE_AppDefined,
4778 0 : "RowsPerStrip not defined ... assuming all one strip." );
4779 0 : nRowsPerStrip = nYSize; /* dummy value */
4780 : }
4781 :
4782 2755 : nBlockXSize = nRasterXSize;
4783 2755 : nBlockYSize = MIN(nRowsPerStrip,nYSize);
4784 : }
4785 :
4786 : nBlocksPerBand =
4787 : ((nYSize + nBlockYSize - 1) / nBlockYSize)
4788 3188 : * ((nXSize + nBlockXSize - 1) / nBlockXSize);
4789 :
4790 : /* -------------------------------------------------------------------- */
4791 : /* Should we handle this using the GTiffBitmapBand? */
4792 : /* -------------------------------------------------------------------- */
4793 3188 : if( nBitsPerSample == 1 && nBands == 1 )
4794 : {
4795 76 : bTreatAsBitmap = TRUE;
4796 :
4797 : // Lets treat large "one row" bitmaps using the scanline api.
4798 76 : if( !TIFFIsTiled(hTIFF)
4799 : && nBlockYSize == nYSize
4800 : && nYSize > 2000
4801 : && bAllowRGBAInterface )
4802 4 : bTreatAsSplitBitmap = TRUE;
4803 : }
4804 :
4805 : /* -------------------------------------------------------------------- */
4806 : /* Should we treat this via the RGBA interface? */
4807 : /* -------------------------------------------------------------------- */
4808 3188 : if( bAllowRGBAInterface &&
4809 : !bTreatAsBitmap && !(nBitsPerSample > 8)
4810 : && (nPhotometric == PHOTOMETRIC_CIELAB ||
4811 : nPhotometric == PHOTOMETRIC_LOGL ||
4812 : nPhotometric == PHOTOMETRIC_LOGLUV ||
4813 : nPhotometric == PHOTOMETRIC_SEPARATED ||
4814 : ( nPhotometric == PHOTOMETRIC_YCBCR
4815 : && nCompression != COMPRESSION_JPEG )) )
4816 : {
4817 : char szMessage[1024];
4818 :
4819 4 : if( TIFFRGBAImageOK( hTIFF, szMessage ) == 1 )
4820 : {
4821 4 : const char* pszSourceColorSpace = NULL;
4822 4 : switch (nPhotometric)
4823 : {
4824 : case PHOTOMETRIC_CIELAB:
4825 1 : pszSourceColorSpace = "CIELAB";
4826 1 : break;
4827 : case PHOTOMETRIC_LOGL:
4828 0 : pszSourceColorSpace = "LOGL";
4829 0 : break;
4830 : case PHOTOMETRIC_LOGLUV:
4831 0 : pszSourceColorSpace = "LOGLUV";
4832 0 : break;
4833 : case PHOTOMETRIC_SEPARATED:
4834 3 : pszSourceColorSpace = "CMYK";
4835 3 : break;
4836 : case PHOTOMETRIC_YCBCR:
4837 0 : pszSourceColorSpace = "YCbCr";
4838 : break;
4839 : }
4840 4 : if (pszSourceColorSpace)
4841 4 : SetMetadataItem( "SOURCE_COLOR_SPACE", pszSourceColorSpace, "IMAGE_STRUCTURE" );
4842 4 : bTreatAsRGBA = TRUE;
4843 4 : nBands = 4;
4844 : }
4845 : else
4846 : {
4847 0 : CPLDebug( "GTiff", "TIFFRGBAImageOK says:\n%s", szMessage );
4848 : }
4849 : }
4850 :
4851 : /* -------------------------------------------------------------------- */
4852 : /* Should we treat this via the split interface? */
4853 : /* -------------------------------------------------------------------- */
4854 3188 : if( !TIFFIsTiled(hTIFF)
4855 : && nBitsPerSample == 8
4856 : && nBlockYSize == nYSize
4857 : && nYSize > 2000
4858 : && !bTreatAsRGBA
4859 : && CSLTestBoolean(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
4860 : {
4861 : /* libtiff 3.9.2 (20091104) and older, libtiff 4.0.0beta5 (also 20091104) */
4862 : /* and older will crash when trying to open a all-in-one-strip */
4863 : /* YCbCr JPEG compressed TIFF (see #3259). BUG_3259_FIXED is defined */
4864 : /* in internal libtiff tif_config.h until a 4.0.0beta6 is released */
4865 : #if (TIFFLIB_VERSION <= 20091104 && !defined(BIGTIFF_SUPPORT)) || \
4866 : (TIFFLIB_VERSION <= 20091104 && defined(BIGTIFF_SUPPORT) && !defined(BUG_3259_FIXED))
4867 : if (nPhotometric == PHOTOMETRIC_YCBCR &&
4868 : nCompression == COMPRESSION_JPEG)
4869 : {
4870 : CPLDebug("GTiff", "Avoid using split band to open all-in-one-strip "
4871 : "YCbCr JPEG compressed TIFF because of older libtiff");
4872 : }
4873 : else
4874 : #endif
4875 8 : bTreatAsSplit = TRUE;
4876 : }
4877 :
4878 : /* -------------------------------------------------------------------- */
4879 : /* Should we treat this via the odd bits interface? */
4880 : /* -------------------------------------------------------------------- */
4881 3188 : if ( nSampleFormat == SAMPLEFORMAT_IEEEFP )
4882 : {
4883 447 : if ( nBitsPerSample == 16 || nBitsPerSample == 24 )
4884 2 : bTreatAsOdd = TRUE;
4885 : }
4886 2741 : else if ( !bTreatAsRGBA && !bTreatAsBitmap
4887 : && nBitsPerSample != 8
4888 : && nBitsPerSample != 16
4889 : && nBitsPerSample != 32
4890 : && nBitsPerSample != 64
4891 : && nBitsPerSample != 128 )
4892 85 : bTreatAsOdd = TRUE;
4893 :
4894 3188 : int bMinIsWhite = nPhotometric == PHOTOMETRIC_MINISWHITE;
4895 :
4896 : /* -------------------------------------------------------------------- */
4897 : /* Capture the color table if there is one. */
4898 : /* -------------------------------------------------------------------- */
4899 : unsigned short *panRed, *panGreen, *panBlue;
4900 :
4901 3188 : if( bTreatAsRGBA
4902 : || TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
4903 : &panRed, &panGreen, &panBlue) == 0 )
4904 : {
4905 : // Build inverted palette if we have inverted photometric.
4906 : // Pixel values remains unchanged. Avoid doing this for *deep*
4907 : // data types (per #1882)
4908 3131 : if( nBitsPerSample <= 16 && nPhotometric == PHOTOMETRIC_MINISWHITE )
4909 : {
4910 : GDALColorEntry oEntry;
4911 : int iColor, nColorCount;
4912 :
4913 7 : poColorTable = new GDALColorTable();
4914 7 : nColorCount = 1 << nBitsPerSample;
4915 :
4916 21 : for ( iColor = 0; iColor < nColorCount; iColor++ )
4917 : {
4918 : oEntry.c1 = oEntry.c2 = oEntry.c3 = (short)
4919 14 : ((255 * (nColorCount - 1 - iColor)) / (nColorCount-1));
4920 14 : oEntry.c4 = 255;
4921 14 : poColorTable->SetColorEntry( iColor, &oEntry );
4922 : }
4923 :
4924 7 : nPhotometric = PHOTOMETRIC_PALETTE;
4925 : }
4926 : else
4927 3117 : poColorTable = NULL;
4928 : }
4929 : else
4930 : {
4931 64 : int nColorCount, nMaxColor = 0;
4932 : GDALColorEntry oEntry;
4933 :
4934 64 : poColorTable = new GDALColorTable();
4935 :
4936 64 : nColorCount = 1 << nBitsPerSample;
4937 :
4938 340308 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
4939 : {
4940 340244 : oEntry.c1 = panRed[iColor] / 256;
4941 340244 : oEntry.c2 = panGreen[iColor] / 256;
4942 340244 : oEntry.c3 = panBlue[iColor] / 256;
4943 340244 : oEntry.c4 = 255;
4944 :
4945 340244 : poColorTable->SetColorEntry( iColor, &oEntry );
4946 :
4947 340244 : nMaxColor = MAX(nMaxColor,panRed[iColor]);
4948 340244 : nMaxColor = MAX(nMaxColor,panGreen[iColor]);
4949 340244 : nMaxColor = MAX(nMaxColor,panBlue[iColor]);
4950 : }
4951 :
4952 : // Bug 1384 - Some TIFF files are generated with color map entry
4953 : // values in range 0-255 instead of 0-65535 - try to handle these
4954 : // gracefully.
4955 64 : if( nMaxColor > 0 && nMaxColor < 256 )
4956 : {
4957 0 : CPLDebug( "GTiff", "TIFF ColorTable seems to be improperly scaled, fixing up." );
4958 :
4959 0 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
4960 : {
4961 0 : oEntry.c1 = panRed[iColor];
4962 0 : oEntry.c2 = panGreen[iColor];
4963 0 : oEntry.c3 = panBlue[iColor];
4964 0 : oEntry.c4 = 255;
4965 :
4966 0 : poColorTable->SetColorEntry( iColor, &oEntry );
4967 : }
4968 : }
4969 : }
4970 :
4971 : /* -------------------------------------------------------------------- */
4972 : /* Create band information objects. */
4973 : /* -------------------------------------------------------------------- */
4974 269491 : for( int iBand = 0; iBand < nBands; iBand++ )
4975 : {
4976 266303 : if( bTreatAsRGBA )
4977 16 : SetBand( iBand+1, new GTiffRGBABand( this, iBand+1 ) );
4978 266287 : else if( bTreatAsSplitBitmap )
4979 4 : SetBand( iBand+1, new GTiffSplitBitmapBand( this, iBand+1 ) );
4980 266283 : else if( bTreatAsSplit )
4981 24 : SetBand( iBand+1, new GTiffSplitBand( this, iBand+1 ) );
4982 266259 : else if( bTreatAsBitmap )
4983 72 : SetBand( iBand+1, new GTiffBitmapBand( this, iBand+1 ) );
4984 266187 : else if( bTreatAsOdd )
4985 177 : SetBand( iBand+1, new GTiffOddBitsBand( this, iBand+1 ) );
4986 : else
4987 266010 : SetBand( iBand+1, new GTiffRasterBand( this, iBand+1 ) );
4988 : }
4989 :
4990 3188 : if( GetRasterBand(1)->GetRasterDataType() == GDT_Unknown )
4991 : {
4992 : CPLError( CE_Failure, CPLE_NotSupported,
4993 0 : "Unsupported TIFF configuration." );
4994 0 : return CE_Failure;
4995 : }
4996 :
4997 : /* -------------------------------------------------------------------- */
4998 : /* Get the transform or gcps from the GeoTIFF file. */
4999 : /* -------------------------------------------------------------------- */
5000 3188 : if( bBaseIn )
5001 : {
5002 2850 : char *pszTabWKT = NULL;
5003 : double *padfTiePoints, *padfScale, *padfMatrix;
5004 : uint16 nCount;
5005 :
5006 2850 : adfGeoTransform[0] = 0.0;
5007 2850 : adfGeoTransform[1] = 1.0;
5008 2850 : adfGeoTransform[2] = 0.0;
5009 2850 : adfGeoTransform[3] = 0.0;
5010 2850 : adfGeoTransform[4] = 0.0;
5011 2850 : adfGeoTransform[5] = 1.0;
5012 :
5013 7364 : if( TIFFGetField(hTIFF,TIFFTAG_GEOPIXELSCALE,&nCount,&padfScale )
5014 : && nCount >= 2
5015 4514 : && padfScale[0] != 0.0 && padfScale[1] != 0.0 )
5016 : {
5017 2257 : adfGeoTransform[1] = padfScale[0];
5018 2257 : adfGeoTransform[5] = - ABS(padfScale[1]);
5019 :
5020 2257 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
5021 : && nCount >= 6 )
5022 : {
5023 : adfGeoTransform[0] =
5024 2257 : padfTiePoints[3] - padfTiePoints[0] * adfGeoTransform[1];
5025 : adfGeoTransform[3] =
5026 2257 : padfTiePoints[4] - padfTiePoints[1] * adfGeoTransform[5];
5027 :
5028 2257 : bGeoTransformValid = TRUE;
5029 : }
5030 : }
5031 :
5032 593 : else if( TIFFGetField(hTIFF,TIFFTAG_GEOTRANSMATRIX,&nCount,&padfMatrix )
5033 : && nCount == 16 )
5034 : {
5035 8 : adfGeoTransform[0] = padfMatrix[3];
5036 8 : adfGeoTransform[1] = padfMatrix[0];
5037 8 : adfGeoTransform[2] = padfMatrix[1];
5038 8 : adfGeoTransform[3] = padfMatrix[7];
5039 8 : adfGeoTransform[4] = padfMatrix[4];
5040 8 : adfGeoTransform[5] = padfMatrix[5];
5041 8 : bGeoTransformValid = TRUE;
5042 : }
5043 :
5044 : /* -------------------------------------------------------------------- */
5045 : /* Otherwise try looking for a .tfw, .tifw or .wld file. */
5046 : /* -------------------------------------------------------------------- */
5047 : else
5048 : {
5049 : bGeoTransformValid =
5050 585 : GDALReadWorldFile( osFilename, NULL, adfGeoTransform );
5051 :
5052 585 : if( !bGeoTransformValid )
5053 : {
5054 : bGeoTransformValid =
5055 580 : GDALReadWorldFile( osFilename, "wld", adfGeoTransform );
5056 : }
5057 :
5058 585 : if( !bGeoTransformValid )
5059 : {
5060 : int bTabFileOK =
5061 : GDALReadTabFile( osFilename, adfGeoTransform,
5062 575 : &pszTabWKT, &nGCPCount, &pasGCPList );
5063 :
5064 575 : if( bTabFileOK && nGCPCount == 0 )
5065 0 : bGeoTransformValid = TRUE;
5066 : }
5067 : }
5068 :
5069 : /* -------------------------------------------------------------------- */
5070 : /* Check for GCPs. Note, we will allow there to be GCPs and a */
5071 : /* transform in some circumstances. */
5072 : /* -------------------------------------------------------------------- */
5073 2850 : if( TIFFGetField(hTIFF,TIFFTAG_GEOTIEPOINTS,&nCount,&padfTiePoints )
5074 : && !bGeoTransformValid )
5075 : {
5076 38 : nGCPCount = nCount / 6;
5077 38 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPCount);
5078 :
5079 190 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
5080 : {
5081 : char szID[32];
5082 :
5083 152 : sprintf( szID, "%d", iGCP+1 );
5084 152 : pasGCPList[iGCP].pszId = CPLStrdup( szID );
5085 152 : pasGCPList[iGCP].pszInfo = CPLStrdup("");
5086 152 : pasGCPList[iGCP].dfGCPPixel = padfTiePoints[iGCP*6+0];
5087 152 : pasGCPList[iGCP].dfGCPLine = padfTiePoints[iGCP*6+1];
5088 152 : pasGCPList[iGCP].dfGCPX = padfTiePoints[iGCP*6+3];
5089 152 : pasGCPList[iGCP].dfGCPY = padfTiePoints[iGCP*6+4];
5090 152 : pasGCPList[iGCP].dfGCPZ = padfTiePoints[iGCP*6+5];
5091 : }
5092 : }
5093 :
5094 : /* -------------------------------------------------------------------- */
5095 : /* Did we find a tab file? If so we will use it's coordinate */
5096 : /* system and give it precidence. */
5097 : /* -------------------------------------------------------------------- */
5098 2850 : if( pszTabWKT != NULL
5099 0 : && (pszProjection == NULL || pszProjection[0] == '\0') )
5100 : {
5101 0 : CPLFree( pszProjection );
5102 0 : pszProjection = pszTabWKT;
5103 0 : pszTabWKT = NULL;
5104 0 : bLookedForProjection = TRUE;
5105 : }
5106 :
5107 2850 : CPLFree( pszTabWKT );
5108 2850 : bGeoTIFFInfoChanged = FALSE;
5109 : }
5110 :
5111 : /* -------------------------------------------------------------------- */
5112 : /* Capture some other potentially interesting information. */
5113 : /* -------------------------------------------------------------------- */
5114 : char *pszText, szWorkMDI[200];
5115 : float fResolution;
5116 : uint16 nShort;
5117 :
5118 3188 : if( TIFFGetField( hTIFF, TIFFTAG_DOCUMENTNAME, &pszText ) )
5119 14 : SetMetadataItem( "TIFFTAG_DOCUMENTNAME", pszText );
5120 :
5121 3188 : if( TIFFGetField( hTIFF, TIFFTAG_IMAGEDESCRIPTION, &pszText ) )
5122 2 : SetMetadataItem( "TIFFTAG_IMAGEDESCRIPTION", pszText );
5123 :
5124 3188 : if( TIFFGetField( hTIFF, TIFFTAG_SOFTWARE, &pszText ) )
5125 8 : SetMetadataItem( "TIFFTAG_SOFTWARE", pszText );
5126 :
5127 3188 : if( TIFFGetField( hTIFF, TIFFTAG_DATETIME, &pszText ) )
5128 3 : SetMetadataItem( "TIFFTAG_DATETIME", pszText );
5129 :
5130 3188 : if( TIFFGetField( hTIFF, TIFFTAG_ARTIST, &pszText ) )
5131 2 : SetMetadataItem( "TIFFTAG_ARTIST", pszText );
5132 :
5133 3188 : if( TIFFGetField( hTIFF, TIFFTAG_HOSTCOMPUTER, &pszText ) )
5134 2 : SetMetadataItem( "TIFFTAG_HOSTCOMPUTER", pszText );
5135 :
5136 3188 : if( TIFFGetField( hTIFF, TIFFTAG_COPYRIGHT, &pszText ) )
5137 2 : SetMetadataItem( "TIFFTAG_COPYRIGHT", pszText );
5138 :
5139 3188 : if( TIFFGetField( hTIFF, TIFFTAG_XRESOLUTION, &fResolution ) )
5140 : {
5141 31 : sprintf( szWorkMDI, "%.8g", fResolution );
5142 31 : SetMetadataItem( "TIFFTAG_XRESOLUTION", szWorkMDI );
5143 : }
5144 :
5145 3188 : if( TIFFGetField( hTIFF, TIFFTAG_YRESOLUTION, &fResolution ) )
5146 : {
5147 31 : sprintf( szWorkMDI, "%.8g", fResolution );
5148 31 : SetMetadataItem( "TIFFTAG_YRESOLUTION", szWorkMDI );
5149 : }
5150 :
5151 3188 : if( TIFFGetField( hTIFF, TIFFTAG_MINSAMPLEVALUE, &nShort ) )
5152 : {
5153 0 : sprintf( szWorkMDI, "%d", nShort );
5154 0 : SetMetadataItem( "TIFFTAG_MINSAMPLEVALUE", szWorkMDI );
5155 : }
5156 :
5157 3188 : if( TIFFGetField( hTIFF, TIFFTAG_MAXSAMPLEVALUE, &nShort ) )
5158 : {
5159 0 : sprintf( szWorkMDI, "%d", nShort );
5160 0 : SetMetadataItem( "TIFFTAG_MAXSAMPLEVALUE", szWorkMDI );
5161 : }
5162 :
5163 3188 : if( TIFFGetField( hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort ) )
5164 : {
5165 31 : if( nShort == RESUNIT_NONE )
5166 11 : sprintf( szWorkMDI, "%d (unitless)", nShort );
5167 20 : else if( nShort == RESUNIT_INCH )
5168 20 : sprintf( szWorkMDI, "%d (pixels/inch)", nShort );
5169 0 : else if( nShort == RESUNIT_CENTIMETER )
5170 0 : sprintf( szWorkMDI, "%d (pixels/cm)", nShort );
5171 : else
5172 0 : sprintf( szWorkMDI, "%d", nShort );
5173 31 : SetMetadataItem( "TIFFTAG_RESOLUTIONUNIT", szWorkMDI );
5174 : }
5175 :
5176 3188 : if( nCompression == COMPRESSION_NONE )
5177 : /* no compression tag */;
5178 171 : else if( nCompression == COMPRESSION_CCITTRLE )
5179 0 : SetMetadataItem( "COMPRESSION", "CCITTRLE", "IMAGE_STRUCTURE" );
5180 171 : else if( nCompression == COMPRESSION_CCITTFAX3 )
5181 0 : SetMetadataItem( "COMPRESSION", "CCITTFAX3", "IMAGE_STRUCTURE" );
5182 171 : else if( nCompression == COMPRESSION_CCITTFAX4 )
5183 9 : SetMetadataItem( "COMPRESSION", "CCITTFAX4", "IMAGE_STRUCTURE" );
5184 162 : else if( nCompression == COMPRESSION_LZW )
5185 15 : SetMetadataItem( "COMPRESSION", "LZW", "IMAGE_STRUCTURE" );
5186 147 : else if( nCompression == COMPRESSION_OJPEG )
5187 0 : SetMetadataItem( "COMPRESSION", "OJPEG", "IMAGE_STRUCTURE" );
5188 147 : else if( nCompression == COMPRESSION_JPEG )
5189 : {
5190 46 : if ( nPhotometric == PHOTOMETRIC_YCBCR )
5191 44 : SetMetadataItem( "COMPRESSION", "YCbCr JPEG", "IMAGE_STRUCTURE" );
5192 : else
5193 2 : SetMetadataItem( "COMPRESSION", "JPEG", "IMAGE_STRUCTURE" );
5194 : }
5195 101 : else if( nCompression == COMPRESSION_NEXT )
5196 0 : SetMetadataItem( "COMPRESSION", "NEXT", "IMAGE_STRUCTURE" );
5197 101 : else if( nCompression == COMPRESSION_CCITTRLEW )
5198 0 : SetMetadataItem( "COMPRESSION", "CCITTRLEW", "IMAGE_STRUCTURE" );
5199 101 : else if( nCompression == COMPRESSION_PACKBITS )
5200 8 : SetMetadataItem( "COMPRESSION", "PACKBITS", "IMAGE_STRUCTURE" );
5201 93 : else if( nCompression == COMPRESSION_THUNDERSCAN )
5202 0 : SetMetadataItem( "COMPRESSION", "THUNDERSCAN", "IMAGE_STRUCTURE" );
5203 93 : else if( nCompression == COMPRESSION_PIXARFILM )
5204 0 : SetMetadataItem( "COMPRESSION", "PIXARFILM", "IMAGE_STRUCTURE" );
5205 93 : else if( nCompression == COMPRESSION_PIXARLOG )
5206 0 : SetMetadataItem( "COMPRESSION", "PIXARLOG", "IMAGE_STRUCTURE" );
5207 93 : else if( nCompression == COMPRESSION_DEFLATE )
5208 36 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
5209 57 : else if( nCompression == COMPRESSION_ADOBE_DEFLATE )
5210 57 : SetMetadataItem( "COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE" );
5211 0 : else if( nCompression == COMPRESSION_DCS )
5212 0 : SetMetadataItem( "COMPRESSION", "DCS", "IMAGE_STRUCTURE" );
5213 0 : else if( nCompression == COMPRESSION_JBIG )
5214 0 : SetMetadataItem( "COMPRESSION", "JBIG", "IMAGE_STRUCTURE" );
5215 0 : else if( nCompression == COMPRESSION_SGILOG )
5216 0 : SetMetadataItem( "COMPRESSION", "SGILOG", "IMAGE_STRUCTURE" );
5217 0 : else if( nCompression == COMPRESSION_SGILOG24 )
5218 0 : SetMetadataItem( "COMPRESSION", "SGILOG24", "IMAGE_STRUCTURE" );
5219 0 : else if( nCompression == COMPRESSION_JP2000 )
5220 0 : SetMetadataItem( "COMPRESSION", "JP2000", "IMAGE_STRUCTURE" );
5221 : else
5222 : {
5223 0 : CPLString oComp;
5224 : SetMetadataItem( "COMPRESSION",
5225 0 : (const char *) oComp.Printf( "%d", nCompression));
5226 : }
5227 :
5228 3533 : if( nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1 )
5229 345 : SetMetadataItem( "INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE" );
5230 : else
5231 2843 : SetMetadataItem( "INTERLEAVE", "BAND", "IMAGE_STRUCTURE" );
5232 :
5233 3188 : if( (GetRasterBand(1)->GetRasterDataType() == GDT_Byte && nBitsPerSample != 8 ) ||
5234 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 && nBitsPerSample != 16) ||
5235 : (GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 && nBitsPerSample != 32) )
5236 : {
5237 824 : for (int i = 0; i < nBands; ++i)
5238 : GetRasterBand(i+1)->SetMetadataItem( "NBITS",
5239 : CPLString().Printf( "%d", (int)nBitsPerSample ),
5240 251 : "IMAGE_STRUCTURE" );
5241 : }
5242 :
5243 3188 : if( bMinIsWhite )
5244 8 : SetMetadataItem( "MINISWHITE", "YES", "IMAGE_STRUCTURE" );
5245 :
5246 3188 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_METADATA, &pszText ) )
5247 : {
5248 141 : CPLXMLNode *psRoot = CPLParseXMLString( pszText );
5249 141 : CPLXMLNode *psItem = NULL;
5250 :
5251 141 : if( psRoot != NULL && psRoot->eType == CXT_Element
5252 : && EQUAL(psRoot->pszValue,"GDALMetadata") )
5253 141 : psItem = psRoot->psChild;
5254 :
5255 674 : for( ; psItem != NULL; psItem = psItem->psNext )
5256 : {
5257 : const char *pszKey, *pszValue, *pszRole, *pszDomain;
5258 : char *pszUnescapedValue;
5259 533 : int nBand, bIsXML = FALSE;
5260 :
5261 533 : if( psItem->eType != CXT_Element
5262 : || !EQUAL(psItem->pszValue,"Item") )
5263 0 : continue;
5264 :
5265 533 : pszKey = CPLGetXMLValue( psItem, "name", NULL );
5266 533 : pszValue = CPLGetXMLValue( psItem, NULL, NULL );
5267 533 : nBand = atoi(CPLGetXMLValue( psItem, "sample", "-1" )) + 1;
5268 533 : pszRole = CPLGetXMLValue( psItem, "role", "" );
5269 533 : pszDomain = CPLGetXMLValue( psItem, "domain", "" );
5270 :
5271 533 : if( pszKey == NULL || pszValue == NULL )
5272 21 : continue;
5273 :
5274 512 : if( EQUALN(pszDomain,"xml:",4) )
5275 2 : bIsXML = TRUE;
5276 :
5277 : pszUnescapedValue = CPLUnescapeString( pszValue, NULL,
5278 512 : CPLES_XML );
5279 512 : if( nBand == 0 )
5280 : {
5281 414 : if( bIsXML )
5282 : {
5283 2 : char *apszMD[2] = { pszUnescapedValue, NULL };
5284 2 : SetMetadata( apszMD, pszDomain );
5285 : }
5286 : else
5287 412 : SetMetadataItem( pszKey, pszUnescapedValue, pszDomain );
5288 : }
5289 : else
5290 : {
5291 98 : GDALRasterBand *poBand = GetRasterBand(nBand);
5292 98 : if( poBand != NULL )
5293 : {
5294 98 : if( EQUAL(pszRole,"scale") )
5295 0 : poBand->SetScale( atof(pszUnescapedValue) );
5296 98 : else if( EQUAL(pszRole,"offset") )
5297 0 : poBand->SetOffset( atof(pszUnescapedValue) );
5298 : else
5299 : {
5300 98 : if( bIsXML )
5301 : {
5302 0 : char *apszMD[2] = { pszUnescapedValue, NULL };
5303 0 : poBand->SetMetadata( apszMD, pszDomain );
5304 : }
5305 : else
5306 : poBand->SetMetadataItem(pszKey,pszUnescapedValue,
5307 98 : pszDomain );
5308 : }
5309 : }
5310 : }
5311 512 : CPLFree( pszUnescapedValue );
5312 : }
5313 :
5314 141 : CPLDestroyXMLNode( psRoot );
5315 : }
5316 :
5317 3188 : bMetadataChanged = FALSE;
5318 :
5319 : /* -------------------------------------------------------------------- */
5320 : /* Check for RPC metadata in an RPB file. */
5321 : /* -------------------------------------------------------------------- */
5322 3188 : if( bBaseIn )
5323 : {
5324 2850 : char **papszRPCMD = GDALLoadRPBFile( osFilename, NULL );
5325 :
5326 2850 : if( papszRPCMD != NULL )
5327 : {
5328 3 : oGTiffMDMD.SetMetadata( papszRPCMD, "RPC" );
5329 3 : CSLDestroy( papszRPCMD );
5330 3 : bMetadataChanged = FALSE;
5331 : }
5332 : else
5333 2847 : ReadRPCTag();
5334 : }
5335 :
5336 : /* -------------------------------------------------------------------- */
5337 : /* Check for RPC metadata in an RPB file. */
5338 : /* -------------------------------------------------------------------- */
5339 3188 : if( bBaseIn )
5340 : {
5341 2850 : char **papszIMDMD = GDALLoadIMDFile( osFilename, NULL );
5342 :
5343 2850 : if( papszIMDMD != NULL )
5344 : {
5345 6 : oGTiffMDMD.SetMetadata( papszIMDMD, "IMD" );
5346 6 : CSLDestroy( papszIMDMD );
5347 6 : bMetadataChanged = FALSE;
5348 : }
5349 : }
5350 :
5351 : /* -------------------------------------------------------------------- */
5352 : /* Check for NODATA */
5353 : /* -------------------------------------------------------------------- */
5354 3188 : if( TIFFGetField( hTIFF, TIFFTAG_GDAL_NODATA, &pszText ) )
5355 : {
5356 135 : bNoDataSet = TRUE;
5357 135 : dfNoDataValue = atof( pszText );
5358 : }
5359 :
5360 : /* -------------------------------------------------------------------- */
5361 : /* If this is a "base" raster, we should scan for any */
5362 : /* associated overviews, internal mask bands and subdatasets. */
5363 : /* -------------------------------------------------------------------- */
5364 3188 : if( bBase )
5365 : {
5366 2850 : char **papszSubdatasets = NULL;
5367 2850 : int iDirIndex = 0;
5368 :
5369 2850 : FlushDirectory();
5370 6051 : while( !TIFFLastDirectory( hTIFF )
5371 : && (iDirIndex == 0 || TIFFReadDirectory( hTIFF ) != 0) )
5372 : {
5373 351 : toff_t nThisDir = TIFFCurrentDirOffset(hTIFF);
5374 351 : uint32 nSubType = 0;
5375 :
5376 351 : *ppoActiveDSRef = NULL; // our directory no longer matches this ds
5377 :
5378 351 : iDirIndex++;
5379 :
5380 351 : if( !TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType) )
5381 97 : nSubType = 0;
5382 :
5383 : /* Embedded overview of the main image */
5384 515 : if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
5385 : (nSubType & FILETYPE_MASK) == 0 &&
5386 : iDirIndex != 1 )
5387 : {
5388 : GTiffDataset *poODS;
5389 :
5390 164 : poODS = new GTiffDataset();
5391 328 : if( poODS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
5392 : eAccess ) != CE_None
5393 : || poODS->GetRasterCount() != GetRasterCount() )
5394 : {
5395 0 : delete poODS;
5396 : }
5397 : else
5398 : {
5399 : CPLDebug( "GTiff", "Opened %dx%d overview.\n",
5400 164 : poODS->GetRasterXSize(), poODS->GetRasterYSize());
5401 164 : nOverviewCount++;
5402 : papoOverviewDS = (GTiffDataset **)
5403 : CPLRealloc(papoOverviewDS,
5404 164 : nOverviewCount * (sizeof(void*)));
5405 164 : papoOverviewDS[nOverviewCount-1] = poODS;
5406 164 : poODS->poBaseDS = this;
5407 : }
5408 : }
5409 :
5410 : /* Embedded mask of the main image */
5411 207 : else if ((nSubType & FILETYPE_MASK) != 0 &&
5412 : (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
5413 : poMaskDS == NULL )
5414 : {
5415 20 : poMaskDS = new GTiffDataset();
5416 :
5417 : /* The TIFF6 specification - page 37 - only allows 1 SamplesPerPixel and 1 BitsPerSample
5418 : Here we support either 1 or 8 bit per sample
5419 : and we support either 1 sample per pixel or as many samples as in the main image
5420 : We don't check the value of the PhotometricInterpretation tag, which should be
5421 : set to "Transparency mask" (4) according to the specification (page 36)
5422 : ... But the TIFF6 specification allows image masks to have a higher resolution than
5423 : the main image, what we don't support here
5424 : */
5425 :
5426 40 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir,
5427 : FALSE, eAccess ) != CE_None
5428 : || poMaskDS->GetRasterCount() == 0
5429 : || !(poMaskDS->GetRasterCount() == 1 || poMaskDS->GetRasterCount() == GetRasterCount())
5430 : || poMaskDS->GetRasterXSize() != GetRasterXSize()
5431 : || poMaskDS->GetRasterYSize() != GetRasterYSize()
5432 : || poMaskDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
5433 : {
5434 0 : delete poMaskDS;
5435 0 : poMaskDS = NULL;
5436 : }
5437 : else
5438 : {
5439 20 : CPLDebug( "GTiff", "Opened band mask.\n");
5440 20 : poMaskDS->poBaseDS = this;
5441 : }
5442 : }
5443 :
5444 : /* Embedded mask of an overview */
5445 : /* The TIFF6 specification allows the combination of the FILETYPE_xxxx masks */
5446 167 : else if (nSubType & (FILETYPE_REDUCEDIMAGE | FILETYPE_MASK))
5447 : {
5448 70 : GTiffDataset* poDS = new GTiffDataset();
5449 140 : if( poDS->OpenOffset( hTIFF, ppoActiveDSRef, nThisDir, FALSE,
5450 : eAccess ) != CE_None
5451 : || poDS->GetRasterCount() == 0
5452 : || poDS->GetRasterBand(1)->GetRasterDataType() != GDT_Byte)
5453 : {
5454 21 : delete poDS;
5455 : }
5456 : else
5457 : {
5458 : int i;
5459 60 : for(i=0;i<nOverviewCount;i++)
5460 : {
5461 83 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS == NULL &&
5462 24 : poDS->GetRasterXSize() == papoOverviewDS[i]->GetRasterXSize() &&
5463 24 : poDS->GetRasterYSize() == papoOverviewDS[i]->GetRasterYSize() &&
5464 : (poDS->GetRasterCount() == 1 || poDS->GetRasterCount() == GetRasterCount()))
5465 : {
5466 : CPLDebug( "GTiff", "Opened band mask for %dx%d overview.\n",
5467 24 : poDS->GetRasterXSize(), poDS->GetRasterYSize());
5468 24 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS = poDS;
5469 24 : poDS->poBaseDS = this;
5470 24 : break;
5471 : }
5472 : }
5473 49 : if (i == nOverviewCount)
5474 : {
5475 25 : delete poDS;
5476 : }
5477 : }
5478 : }
5479 97 : else if( nSubType == 0 ) {
5480 97 : CPLString osName, osDesc;
5481 : uint32 nXSize, nYSize;
5482 : uint16 nSPP;
5483 :
5484 97 : TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize );
5485 97 : TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &nYSize );
5486 97 : if( !TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP ) )
5487 0 : nSPP = 1;
5488 :
5489 : osName.Printf( "SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
5490 97 : iDirIndex, iDirIndex, osFilename.c_str() );
5491 : osDesc.Printf( "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
5492 : iDirIndex, iDirIndex,
5493 97 : (int)nXSize, (int)nYSize, nSPP );
5494 :
5495 : papszSubdatasets =
5496 97 : CSLAddString( papszSubdatasets, osName );
5497 : papszSubdatasets =
5498 97 : CSLAddString( papszSubdatasets, osDesc );
5499 : }
5500 :
5501 : // Make sure we are stepping from the expected directory regardless
5502 : // of churn done processing the above.
5503 351 : if( TIFFCurrentDirOffset(hTIFF) != nThisDir )
5504 0 : TIFFSetSubDirectory( hTIFF, nThisDir );
5505 351 : *ppoActiveDSRef = NULL;
5506 : }
5507 :
5508 : /* If we have a mask for the main image, loop over the overviews, and if they */
5509 : /* have a mask, let's set this mask as an overview of the main mask... */
5510 2850 : if (poMaskDS != NULL)
5511 : {
5512 : int i;
5513 44 : for(i=0;i<nOverviewCount;i++)
5514 : {
5515 24 : if (((GTiffDataset*)papoOverviewDS[i])->poMaskDS != NULL)
5516 : {
5517 24 : poMaskDS->nOverviewCount++;
5518 : poMaskDS->papoOverviewDS = (GTiffDataset **)
5519 : CPLRealloc(poMaskDS->papoOverviewDS,
5520 24 : poMaskDS->nOverviewCount * (sizeof(void*)));
5521 24 : poMaskDS->papoOverviewDS[poMaskDS->nOverviewCount-1] =
5522 24 : ((GTiffDataset*)papoOverviewDS[i])->poMaskDS;
5523 : }
5524 : }
5525 : }
5526 :
5527 : /* -------------------------------------------------------------------- */
5528 : /* Only keep track of subdatasets if we have more than one */
5529 : /* subdataset (pair). */
5530 : /* -------------------------------------------------------------------- */
5531 2850 : if( CSLCount(papszSubdatasets) > 2 )
5532 : {
5533 1 : oGTiffMDMD.SetMetadata( papszSubdatasets, "SUBDATASETS" );
5534 : }
5535 2850 : CSLDestroy( papszSubdatasets );
5536 : }
5537 :
5538 3188 : return( CE_None );
5539 : }
5540 :
5541 807 : static int GTiffGetZLevel(char** papszOptions)
5542 : {
5543 807 : int nZLevel = -1;
5544 807 : const char* pszValue = CSLFetchNameValue( papszOptions, "ZLEVEL" );
5545 807 : if( pszValue != NULL )
5546 : {
5547 0 : nZLevel = atoi( pszValue );
5548 0 : if (!(nZLevel >= 1 && nZLevel <= 9))
5549 : {
5550 : CPLError( CE_Warning, CPLE_IllegalArg,
5551 : "ZLEVEL=%s value not recognised, ignoring.",
5552 0 : pszValue );
5553 0 : nZLevel = -1;
5554 : }
5555 : }
5556 807 : return nZLevel;
5557 : }
5558 :
5559 808 : static int GTiffGetJpegQuality(char** papszOptions)
5560 : {
5561 808 : int nJpegQuality = -1;
5562 808 : const char* pszValue = CSLFetchNameValue( papszOptions, "JPEG_QUALITY" );
5563 808 : if( pszValue != NULL )
5564 : {
5565 4 : nJpegQuality = atoi( pszValue );
5566 4 : if (!(nJpegQuality >= 1 && nJpegQuality <= 100))
5567 : {
5568 : CPLError( CE_Warning, CPLE_IllegalArg,
5569 : "JPEG_QUALITY=%s value not recognised, ignoring.",
5570 0 : pszValue );
5571 0 : nJpegQuality = -1;
5572 : }
5573 : }
5574 808 : return nJpegQuality;
5575 : }
5576 :
5577 : /************************************************************************/
5578 : /* GTiffCreate() */
5579 : /* */
5580 : /* Shared functionality between GTiffDataset::Create() and */
5581 : /* GTiffCreateCopy() for creating TIFF file based on a set of */
5582 : /* options and a configuration. */
5583 : /************************************************************************/
5584 :
5585 804 : TIFF *GTiffDataset::CreateLL( const char * pszFilename,
5586 : int nXSize, int nYSize, int nBands,
5587 : GDALDataType eType,
5588 : char **papszParmList )
5589 :
5590 : {
5591 : TIFF *hTIFF;
5592 804 : int nBlockXSize = 0, nBlockYSize = 0;
5593 804 : int bTiled = FALSE;
5594 804 : uint16 nCompression = COMPRESSION_NONE;
5595 804 : int nPredictor = 1, nJpegQuality = -1, nZLevel = -1;
5596 : uint16 nSampleFormat;
5597 : int nPlanar;
5598 : const char *pszValue;
5599 : const char *pszProfile;
5600 804 : int bCreateBigTIFF = FALSE;
5601 :
5602 804 : GTiffOneTimeInit();
5603 :
5604 : /* -------------------------------------------------------------------- */
5605 : /* Blow on a few errors. */
5606 : /* -------------------------------------------------------------------- */
5607 804 : if( nXSize < 1 || nYSize < 1 || nBands < 1 )
5608 : {
5609 : CPLError( CE_Failure, CPLE_AppDefined,
5610 : "Attempt to create %dx%dx%d TIFF file, but width, height and bands\n"
5611 : "must be positive.",
5612 1 : nXSize, nYSize, nBands );
5613 :
5614 1 : return NULL;
5615 : }
5616 :
5617 803 : if (nBands > 65535)
5618 : {
5619 : CPLError( CE_Failure, CPLE_AppDefined,
5620 : "Attempt to create %dx%dx%d TIFF file, but bands\n"
5621 : "must be lesser or equal to 65535.",
5622 0 : nXSize, nYSize, nBands );
5623 :
5624 0 : return NULL;
5625 : }
5626 :
5627 : /* -------------------------------------------------------------------- */
5628 : /* Setup values based on options. */
5629 : /* -------------------------------------------------------------------- */
5630 803 : pszProfile = CSLFetchNameValue(papszParmList,"PROFILE");
5631 803 : if( pszProfile == NULL )
5632 791 : pszProfile = "GDALGeoTIFF";
5633 :
5634 803 : if( CSLFetchBoolean( papszParmList, "TILED", FALSE ) )
5635 11 : bTiled = TRUE;
5636 :
5637 803 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKXSIZE");
5638 803 : if( pszValue != NULL )
5639 8 : nBlockXSize = atoi( pszValue );
5640 :
5641 803 : pszValue = CSLFetchNameValue(papszParmList,"BLOCKYSIZE");
5642 803 : if( pszValue != NULL )
5643 12 : nBlockYSize = atoi( pszValue );
5644 :
5645 803 : pszValue = CSLFetchNameValue(papszParmList,"INTERLEAVE");
5646 803 : if( pszValue != NULL )
5647 : {
5648 22 : if( EQUAL( pszValue, "PIXEL" ) )
5649 13 : nPlanar = PLANARCONFIG_CONTIG;
5650 9 : else if( EQUAL( pszValue, "BAND" ) )
5651 9 : nPlanar = PLANARCONFIG_SEPARATE;
5652 : else
5653 : {
5654 : CPLError( CE_Failure, CPLE_AppDefined,
5655 : "INTERLEAVE=%s unsupported, value must be PIXEL or BAND.",
5656 0 : pszValue );
5657 0 : return NULL;
5658 : }
5659 : }
5660 : else
5661 : {
5662 781 : nPlanar = PLANARCONFIG_CONTIG;
5663 : }
5664 :
5665 803 : pszValue = CSLFetchNameValue( papszParmList, "COMPRESS" );
5666 803 : if( pszValue != NULL )
5667 : {
5668 27 : if( EQUAL( pszValue, "NONE" ) )
5669 1 : nCompression = COMPRESSION_NONE;
5670 26 : else if( EQUAL( pszValue, "JPEG" ) )
5671 7 : nCompression = COMPRESSION_JPEG;
5672 19 : else if( EQUAL( pszValue, "LZW" ) )
5673 7 : nCompression = COMPRESSION_LZW;
5674 12 : else if( EQUAL( pszValue, "PACKBITS" ))
5675 2 : nCompression = COMPRESSION_PACKBITS;
5676 18 : else if( EQUAL( pszValue, "DEFLATE" ) || EQUAL( pszValue, "ZIP" ))
5677 8 : nCompression = COMPRESSION_ADOBE_DEFLATE;
5678 2 : else if( EQUAL( pszValue, "FAX3" )
5679 : || EQUAL( pszValue, "CCITTFAX3" ))
5680 0 : nCompression = COMPRESSION_CCITTFAX3;
5681 4 : else if( EQUAL( pszValue, "FAX4" )
5682 : || EQUAL( pszValue, "CCITTFAX4" ))
5683 2 : nCompression = COMPRESSION_CCITTFAX4;
5684 0 : else if( EQUAL( pszValue, "CCITTRLE" ) )
5685 0 : nCompression = COMPRESSION_CCITTRLE;
5686 : else
5687 : CPLError( CE_Warning, CPLE_IllegalArg,
5688 : "COMPRESS=%s value not recognised, ignoring.",
5689 0 : pszValue );
5690 :
5691 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION > 20031007 /* 3.6.0 */
5692 27 : if (nCompression != COMPRESSION_NONE &&
5693 : !TIFFIsCODECConfigured(nCompression))
5694 : {
5695 : CPLError( CE_Failure, CPLE_AppDefined,
5696 0 : "Cannot create TIFF file due to missing codec for %s.", pszValue );
5697 0 : return NULL;
5698 : }
5699 : #endif
5700 : }
5701 :
5702 803 : pszValue = CSLFetchNameValue( papszParmList, "PREDICTOR" );
5703 803 : if( pszValue != NULL )
5704 2 : nPredictor = atoi( pszValue );
5705 :
5706 803 : nZLevel = GTiffGetZLevel(papszParmList);
5707 :
5708 803 : nJpegQuality = GTiffGetJpegQuality(papszParmList);
5709 :
5710 : /* -------------------------------------------------------------------- */
5711 : /* Compute the uncompressed size. */
5712 : /* -------------------------------------------------------------------- */
5713 : double dfUncompressedImageSize;
5714 :
5715 : dfUncompressedImageSize =
5716 803 : nXSize * ((double)nYSize) * nBands * (GDALGetDataTypeSize(eType)/8);
5717 :
5718 803 : if( nCompression == COMPRESSION_NONE
5719 : && dfUncompressedImageSize > 4200000000.0 )
5720 : {
5721 : #ifndef BIGTIFF_SUPPORT
5722 : CPLError( CE_Failure, CPLE_NotSupported,
5723 : "A %d pixels x %d lines x %d bands %s image would be larger than 4GB\n"
5724 : "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
5725 : "Creation failed.",
5726 : nXSize, nYSize, nBands, GDALGetDataTypeName(eType) );
5727 : return NULL;
5728 : #endif
5729 : }
5730 :
5731 : /* -------------------------------------------------------------------- */
5732 : /* Should the file be created as a bigtiff file? */
5733 : /* -------------------------------------------------------------------- */
5734 803 : const char *pszBIGTIFF = CSLFetchNameValue(papszParmList, "BIGTIFF");
5735 :
5736 803 : if( pszBIGTIFF == NULL )
5737 799 : pszBIGTIFF = "IF_NEEDED";
5738 :
5739 803 : if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
5740 : {
5741 800 : if( nCompression == COMPRESSION_NONE
5742 : && dfUncompressedImageSize > 4200000000.0 )
5743 9 : bCreateBigTIFF = TRUE;
5744 : }
5745 3 : else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
5746 : {
5747 1 : if( dfUncompressedImageSize > 2000000000.0 )
5748 1 : bCreateBigTIFF = TRUE;
5749 : }
5750 :
5751 : else
5752 : {
5753 2 : bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
5754 2 : if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE &&
5755 : dfUncompressedImageSize > 4200000000.0 )
5756 : {
5757 : CPLError( CE_Failure, CPLE_NotSupported,
5758 : "The TIFF file will be larger than 4GB, so BigTIFF is necessary.\n"
5759 1 : "Creation failed.");
5760 1 : return NULL;
5761 : }
5762 : }
5763 :
5764 : #ifndef BIGTIFF_SUPPORT
5765 : if( bCreateBigTIFF )
5766 : {
5767 : CPLError( CE_Warning, CPLE_NotSupported,
5768 : "BigTIFF requested, but GDAL built without BigTIFF\n"
5769 : "enabled libtiff, request ignored." );
5770 : bCreateBigTIFF = FALSE;
5771 : }
5772 : #endif
5773 :
5774 802 : if( bCreateBigTIFF )
5775 11 : CPLDebug( "GTiff", "File being created as a BigTIFF." );
5776 :
5777 : /* -------------------------------------------------------------------- */
5778 : /* Check if the user wishes a particular endianness */
5779 : /* -------------------------------------------------------------------- */
5780 :
5781 802 : int eEndianness = ENDIANNESS_NATIVE;
5782 802 : pszValue = CSLFetchNameValue(papszParmList, "ENDIANNESS");
5783 802 : if ( pszValue == NULL )
5784 798 : pszValue = CPLGetConfigOption( "GDAL_TIFF_ENDIANNESS", NULL );
5785 802 : if ( pszValue != NULL )
5786 : {
5787 296 : if (EQUAL(pszValue, "LITTLE"))
5788 4 : eEndianness = ENDIANNESS_LITTLE;
5789 292 : else if (EQUAL(pszValue, "BIG"))
5790 0 : eEndianness = ENDIANNESS_BIG;
5791 292 : else if (EQUAL(pszValue, "INVERTED"))
5792 : {
5793 : #ifdef CPL_LSB
5794 23 : eEndianness = ENDIANNESS_BIG;
5795 : #else
5796 : eEndianness = ENDIANNESS_LITTLE;
5797 : #endif
5798 : }
5799 269 : else if (!EQUAL(pszValue, "NATIVE"))
5800 : {
5801 : CPLError( CE_Warning, CPLE_NotSupported,
5802 0 : "ENDIANNESS=%s not supported. Defaulting to NATIVE", pszValue );
5803 : }
5804 : }
5805 :
5806 : /* -------------------------------------------------------------------- */
5807 : /* Try opening the dataset. */
5808 : /* -------------------------------------------------------------------- */
5809 :
5810 : char szOpeningFlag[5];
5811 802 : strcpy(szOpeningFlag, "w+");
5812 802 : if (bCreateBigTIFF)
5813 11 : strcat(szOpeningFlag, "8");
5814 802 : if (eEndianness == ENDIANNESS_BIG)
5815 23 : strcat(szOpeningFlag, "b");
5816 779 : else if (eEndianness == ENDIANNESS_LITTLE)
5817 4 : strcat(szOpeningFlag, "l");
5818 802 : hTIFF = VSI_TIFFOpen( pszFilename, szOpeningFlag );
5819 802 : if( hTIFF == NULL )
5820 : {
5821 0 : if( CPLGetLastErrorNo() == 0 )
5822 : CPLError( CE_Failure, CPLE_OpenFailed,
5823 : "Attempt to create new tiff file `%s'\n"
5824 : "failed in XTIFFOpen().\n",
5825 0 : pszFilename );
5826 0 : return NULL;
5827 : }
5828 :
5829 : /* -------------------------------------------------------------------- */
5830 : /* How many bits per sample? We have a special case if NBITS */
5831 : /* specified for GDT_Byte, GDT_UInt16, GDT_UInt32. */
5832 : /* -------------------------------------------------------------------- */
5833 802 : int nBitsPerSample = GDALGetDataTypeSize(eType);
5834 802 : if (CSLFetchNameValue(papszParmList, "NBITS") != NULL)
5835 : {
5836 38 : int nMinBits = 0, nMaxBits = 0;
5837 38 : nBitsPerSample = atoi(CSLFetchNameValue(papszParmList, "NBITS"));
5838 38 : if( eType == GDT_Byte )
5839 : {
5840 13 : nMinBits = 1;
5841 13 : nMaxBits = 8;
5842 : }
5843 25 : else if( eType == GDT_UInt16 )
5844 : {
5845 13 : nMinBits = 9;
5846 13 : nMaxBits = 16;
5847 : }
5848 12 : else if( eType == GDT_UInt32 )
5849 : {
5850 12 : nMinBits = 17;
5851 12 : nMaxBits = 32;
5852 : }
5853 : else
5854 : {
5855 : CPLError(CE_Warning, CPLE_NotSupported,
5856 : "NBITS is not supported for data type %s",
5857 0 : GDALGetDataTypeName(eType));
5858 0 : nBitsPerSample = GDALGetDataTypeSize(eType);
5859 : }
5860 :
5861 38 : if (nMinBits != 0)
5862 : {
5863 38 : if (nBitsPerSample < nMinBits)
5864 : {
5865 : CPLError(CE_Warning, CPLE_AppDefined,
5866 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
5867 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMinBits);
5868 0 : nBitsPerSample = nMinBits;
5869 : }
5870 38 : else if (nBitsPerSample > nMaxBits)
5871 : {
5872 : CPLError(CE_Warning, CPLE_AppDefined,
5873 : "NBITS=%d is invalid for data type %s. Using NBITS=%d",
5874 0 : nBitsPerSample, GDALGetDataTypeName(eType), nMaxBits);
5875 0 : nBitsPerSample = nMaxBits;
5876 : }
5877 : }
5878 : }
5879 :
5880 : /* -------------------------------------------------------------------- */
5881 : /* Do we have a custom pixel type (just used for signed byte now). */
5882 : /* -------------------------------------------------------------------- */
5883 802 : const char *pszPixelType = CSLFetchNameValue( papszParmList, "PIXELTYPE" );
5884 802 : if( pszPixelType == NULL )
5885 802 : pszPixelType = "";
5886 :
5887 : /* -------------------------------------------------------------------- */
5888 : /* Setup some standard flags. */
5889 : /* -------------------------------------------------------------------- */
5890 802 : TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
5891 802 : TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
5892 802 : TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerSample );
5893 :
5894 908 : if( (eType == GDT_Byte && EQUAL(pszPixelType,"SIGNEDBYTE"))
5895 : || eType == GDT_Int16 || eType == GDT_Int32 )
5896 106 : nSampleFormat = SAMPLEFORMAT_INT;
5897 788 : else if( eType == GDT_CInt16 || eType == GDT_CInt32 )
5898 92 : nSampleFormat = SAMPLEFORMAT_COMPLEXINT;
5899 711 : else if( eType == GDT_Float32 || eType == GDT_Float64 )
5900 107 : nSampleFormat = SAMPLEFORMAT_IEEEFP;
5901 594 : else if( eType == GDT_CFloat32 || eType == GDT_CFloat64 )
5902 97 : nSampleFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
5903 : else
5904 400 : nSampleFormat = SAMPLEFORMAT_UINT;
5905 :
5906 802 : TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
5907 802 : TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nBands );
5908 802 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanar );
5909 :
5910 : /* -------------------------------------------------------------------- */
5911 : /* Setup Photometric Interpretation. Take this value from the user */
5912 : /* passed option or guess correct value otherwise. */
5913 : /* -------------------------------------------------------------------- */
5914 802 : int nSamplesAccountedFor = 1;
5915 802 : int bForceColorTable = FALSE;
5916 :
5917 802 : pszValue = CSLFetchNameValue(papszParmList,"PHOTOMETRIC");
5918 802 : if( pszValue != NULL )
5919 : {
5920 15 : if( EQUAL( pszValue, "MINISBLACK" ) )
5921 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
5922 15 : else if( EQUAL( pszValue, "MINISWHITE" ) )
5923 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISWHITE );
5924 13 : else if( EQUAL( pszValue, "PALETTE" ))
5925 : {
5926 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
5927 3 : nSamplesAccountedFor = 1;
5928 3 : bForceColorTable = TRUE;
5929 : }
5930 10 : else if( EQUAL( pszValue, "RGB" ))
5931 : {
5932 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
5933 2 : nSamplesAccountedFor = 3;
5934 : }
5935 8 : else if( EQUAL( pszValue, "CMYK" ))
5936 : {
5937 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_SEPARATED );
5938 2 : nSamplesAccountedFor = 4;
5939 : }
5940 6 : else if( EQUAL( pszValue, "YCBCR" ))
5941 : {
5942 : /* Because of subsampling, setting YCBCR without JPEG compression leads */
5943 : /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
5944 : /* aware of subsampling so that it doesn't overrun buffer size returned */
5945 : /* by libtiff */
5946 6 : if ( nCompression != COMPRESSION_JPEG )
5947 : {
5948 : CPLError(CE_Failure, CPLE_NotSupported,
5949 0 : "Currently, PHOTOMETRIC=YCBCR requires COMPRESS=JPEG");
5950 0 : XTIFFClose(hTIFF);
5951 0 : return NULL;
5952 : }
5953 :
5954 6 : if ( nPlanar == PLANARCONFIG_SEPARATE )
5955 : {
5956 : CPLError(CE_Failure, CPLE_NotSupported,
5957 0 : "PHOTOMETRIC=YCBCR requires INTERLEAVE=PIXEL");
5958 0 : XTIFFClose(hTIFF);
5959 0 : return NULL;
5960 : }
5961 :
5962 : /* YCBCR strictly requires 3 bands. Not less, not more */
5963 : /* Issue an explicit error message as libtiff one is a bit cryptic : */
5964 : /* TIFFVStripSize64:Invalid td_samplesperpixel value */
5965 6 : if ( nBands != 3 )
5966 : {
5967 : CPLError(CE_Failure, CPLE_NotSupported,
5968 0 : "PHOTOMETRIC=YCBCR requires a source raster with only 3 bands (RGB)");
5969 0 : XTIFFClose(hTIFF);
5970 0 : return NULL;
5971 : }
5972 :
5973 6 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR );
5974 6 : nSamplesAccountedFor = 3;
5975 : }
5976 0 : else if( EQUAL( pszValue, "CIELAB" ))
5977 : {
5978 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CIELAB );
5979 0 : nSamplesAccountedFor = 3;
5980 : }
5981 0 : else if( EQUAL( pszValue, "ICCLAB" ))
5982 : {
5983 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ICCLAB );
5984 0 : nSamplesAccountedFor = 3;
5985 : }
5986 0 : else if( EQUAL( pszValue, "ITULAB" ))
5987 : {
5988 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_ITULAB );
5989 0 : nSamplesAccountedFor = 3;
5990 : }
5991 : else
5992 : {
5993 : CPLError( CE_Warning, CPLE_IllegalArg,
5994 : "PHOTOMETRIC=%s value not recognised, ignoring.\n"
5995 : "Set the Photometric Interpretation as MINISBLACK.",
5996 0 : pszValue );
5997 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
5998 : }
5999 :
6000 15 : if ( nBands < nSamplesAccountedFor )
6001 : {
6002 : CPLError( CE_Warning, CPLE_IllegalArg,
6003 : "PHOTOMETRIC=%s value does not correspond to number "
6004 : "of bands (%d), ignoring.\n"
6005 : "Set the Photometric Interpretation as MINISBLACK.",
6006 0 : pszValue, nBands );
6007 0 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6008 : }
6009 : }
6010 : else
6011 : {
6012 : /*
6013 : * If image contains 3 or 4 bands and datatype is Byte then we will
6014 : * assume it is RGB. In all other cases assume it is MINISBLACK.
6015 : */
6016 819 : if( nBands == 3 && eType == GDT_Byte )
6017 : {
6018 32 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6019 32 : nSamplesAccountedFor = 3;
6020 : }
6021 769 : else if( nBands == 4 && eType == GDT_Byte )
6022 : {
6023 : uint16 v[1];
6024 :
6025 14 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6026 14 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
6027 14 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6028 14 : nSamplesAccountedFor = 4;
6029 : }
6030 : else
6031 : {
6032 741 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK );
6033 741 : nSamplesAccountedFor = 1;
6034 : }
6035 : }
6036 :
6037 : /* -------------------------------------------------------------------- */
6038 : /* If there are extra samples, we need to mark them with an */
6039 : /* appropriate extrasamples definition here. */
6040 : /* -------------------------------------------------------------------- */
6041 802 : if( nBands > nSamplesAccountedFor )
6042 : {
6043 : uint16 *v;
6044 : int i;
6045 57 : int nExtraSamples = nBands - nSamplesAccountedFor;
6046 :
6047 57 : v = (uint16 *) CPLMalloc( sizeof(uint16) * nExtraSamples );
6048 :
6049 57 : if( CSLFetchBoolean(papszParmList,"ALPHA",FALSE) )
6050 1 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6051 : else
6052 56 : v[0] = EXTRASAMPLE_UNSPECIFIED;
6053 :
6054 131166 : for( i = 1; i < nExtraSamples; i++ )
6055 131109 : v[i] = EXTRASAMPLE_UNSPECIFIED;
6056 :
6057 57 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, v );
6058 :
6059 57 : CPLFree(v);
6060 : }
6061 :
6062 : /* Set the compression method before asking the default strip size */
6063 : /* This is usefull when translating to a JPEG-In-TIFF file where */
6064 : /* the default strip size is 8 or 16 depending on the photometric value */
6065 802 : TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompression );
6066 :
6067 : /* -------------------------------------------------------------------- */
6068 : /* Setup tiling/stripping flags. */
6069 : /* -------------------------------------------------------------------- */
6070 802 : if( bTiled )
6071 : {
6072 11 : if( nBlockXSize == 0 )
6073 3 : nBlockXSize = 256;
6074 :
6075 11 : if( nBlockYSize == 0 )
6076 3 : nBlockYSize = 256;
6077 :
6078 11 : if (!TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize ) ||
6079 : !TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize ))
6080 : {
6081 0 : XTIFFClose(hTIFF);
6082 0 : return NULL;
6083 : }
6084 : }
6085 : else
6086 : {
6087 : uint32 nRowsPerStrip;
6088 :
6089 791 : if( nBlockYSize == 0 )
6090 787 : nRowsPerStrip = MIN(nYSize, (int)TIFFDefaultStripSize(hTIFF,0));
6091 : else
6092 4 : nRowsPerStrip = nBlockYSize;
6093 :
6094 791 : TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nRowsPerStrip );
6095 : }
6096 :
6097 : /* -------------------------------------------------------------------- */
6098 : /* Set compression related tags. */
6099 : /* -------------------------------------------------------------------- */
6100 802 : if ( nCompression == COMPRESSION_LZW ||
6101 : nCompression == COMPRESSION_ADOBE_DEFLATE )
6102 15 : TIFFSetField( hTIFF, TIFFTAG_PREDICTOR, nPredictor );
6103 802 : if (nCompression == COMPRESSION_ADOBE_DEFLATE
6104 : && nZLevel != -1)
6105 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
6106 802 : if( nCompression == COMPRESSION_JPEG
6107 : && nJpegQuality != -1 )
6108 2 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
6109 :
6110 : /* -------------------------------------------------------------------- */
6111 : /* If we forced production of a file with photometric=palette, */
6112 : /* we need to push out a default color table. */
6113 : /* -------------------------------------------------------------------- */
6114 802 : if( bForceColorTable )
6115 : {
6116 : int nColors;
6117 :
6118 3 : if( eType == GDT_Byte )
6119 3 : nColors = 256;
6120 : else
6121 0 : nColors = 65536;
6122 :
6123 : unsigned short *panTRed, *panTGreen, *panTBlue;
6124 :
6125 3 : panTRed = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6126 3 : panTGreen = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6127 3 : panTBlue = (unsigned short *) CPLMalloc(sizeof(unsigned short)*nColors);
6128 :
6129 771 : for( int iColor = 0; iColor < nColors; iColor++ )
6130 : {
6131 768 : if( eType == GDT_Byte )
6132 : {
6133 768 : panTRed[iColor] = (unsigned short) (257 * iColor);
6134 768 : panTGreen[iColor] = (unsigned short) (257 * iColor);
6135 768 : panTBlue[iColor] = (unsigned short) (257 * iColor);
6136 : }
6137 : else
6138 : {
6139 0 : panTRed[iColor] = (unsigned short) iColor;
6140 0 : panTGreen[iColor] = (unsigned short) iColor;
6141 0 : panTBlue[iColor] = (unsigned short) iColor;
6142 : }
6143 : }
6144 :
6145 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP,
6146 3 : panTRed, panTGreen, panTBlue );
6147 :
6148 3 : CPLFree( panTRed );
6149 3 : CPLFree( panTGreen );
6150 3 : CPLFree( panTBlue );
6151 : }
6152 :
6153 802 : return( hTIFF );
6154 : }
6155 :
6156 : /************************************************************************/
6157 : /* Create() */
6158 : /* */
6159 : /* Create a new GeoTIFF or TIFF file. */
6160 : /************************************************************************/
6161 :
6162 694 : GDALDataset *GTiffDataset::Create( const char * pszFilename,
6163 : int nXSize, int nYSize, int nBands,
6164 : GDALDataType eType,
6165 : char **papszParmList )
6166 :
6167 : {
6168 : GTiffDataset * poDS;
6169 : TIFF *hTIFF;
6170 :
6171 : /* -------------------------------------------------------------------- */
6172 : /* Create the underlying TIFF file. */
6173 : /* -------------------------------------------------------------------- */
6174 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
6175 694 : eType, papszParmList );
6176 :
6177 694 : if( hTIFF == NULL )
6178 2 : return NULL;
6179 :
6180 : /* -------------------------------------------------------------------- */
6181 : /* Create the new GTiffDataset object. */
6182 : /* -------------------------------------------------------------------- */
6183 692 : poDS = new GTiffDataset();
6184 692 : poDS->hTIFF = hTIFF;
6185 692 : poDS->poActiveDS = poDS;
6186 692 : poDS->ppoActiveDSRef = &(poDS->poActiveDS);
6187 :
6188 692 : poDS->nRasterXSize = nXSize;
6189 692 : poDS->nRasterYSize = nYSize;
6190 692 : poDS->eAccess = GA_Update;
6191 692 : poDS->bCrystalized = FALSE;
6192 692 : poDS->nSamplesPerPixel = (uint16) nBands;
6193 1384 : poDS->osFilename = pszFilename;
6194 :
6195 : /* Avoid premature crystalization that will cause directory re-writting */
6196 : /* if GetProjectionRef() or GetGeoTransform() are called on the newly created GeoTIFF */
6197 692 : poDS->bLookedForProjection = TRUE;
6198 :
6199 692 : TIFFGetField( hTIFF, TIFFTAG_SAMPLEFORMAT, &(poDS->nSampleFormat) );
6200 692 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(poDS->nPlanarConfig) );
6201 692 : TIFFGetField( hTIFF, TIFFTAG_PHOTOMETRIC, &(poDS->nPhotometric) );
6202 692 : TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(poDS->nBitsPerSample) );
6203 692 : TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(poDS->nCompression) );
6204 :
6205 692 : if( TIFFIsTiled(hTIFF) )
6206 : {
6207 8 : TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(poDS->nBlockXSize) );
6208 8 : TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(poDS->nBlockYSize) );
6209 : }
6210 : else
6211 : {
6212 684 : if( !TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP,
6213 : &(poDS->nRowsPerStrip) ) )
6214 0 : poDS->nRowsPerStrip = 1; /* dummy value */
6215 :
6216 684 : poDS->nBlockXSize = nXSize;
6217 684 : poDS->nBlockYSize = MIN((int)poDS->nRowsPerStrip,nYSize);
6218 : }
6219 :
6220 : poDS->nBlocksPerBand =
6221 : ((nYSize + poDS->nBlockYSize - 1) / poDS->nBlockYSize)
6222 692 : * ((nXSize + poDS->nBlockXSize - 1) / poDS->nBlockXSize);
6223 :
6224 692 : if( CSLFetchNameValue( papszParmList, "PROFILE" ) != NULL )
6225 4 : poDS->osProfile = CSLFetchNameValue( papszParmList, "PROFILE" );
6226 :
6227 : /* -------------------------------------------------------------------- */
6228 : /* YCbCr JPEG compressed images should be translated on the fly */
6229 : /* to RGB by libtiff/libjpeg unless specifically requested */
6230 : /* otherwise. */
6231 : /* -------------------------------------------------------------------- */
6232 692 : if( poDS->nCompression == COMPRESSION_JPEG
6233 : && poDS->nPhotometric == PHOTOMETRIC_YCBCR
6234 : && CSLTestBoolean( CPLGetConfigOption("CONVERT_YCBCR_TO_RGB",
6235 : "YES") ) )
6236 : {
6237 : int nColorMode;
6238 :
6239 1 : poDS->SetMetadataItem( "SOURCE_COLOR_SPACE", "YCbCr", "IMAGE_STRUCTURE" );
6240 1 : if ( !TIFFGetField( hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode ) ||
6241 : nColorMode != JPEGCOLORMODE_RGB )
6242 1 : TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
6243 : }
6244 :
6245 : /* -------------------------------------------------------------------- */
6246 : /* Read palette back as a color table if it has one. */
6247 : /* -------------------------------------------------------------------- */
6248 : unsigned short *panRed, *panGreen, *panBlue;
6249 :
6250 692 : if( poDS->nPhotometric == PHOTOMETRIC_PALETTE
6251 : && TIFFGetField( hTIFF, TIFFTAG_COLORMAP,
6252 : &panRed, &panGreen, &panBlue) )
6253 : {
6254 : int nColorCount;
6255 : GDALColorEntry oEntry;
6256 :
6257 3 : poDS->poColorTable = new GDALColorTable();
6258 :
6259 3 : nColorCount = 1 << poDS->nBitsPerSample;
6260 :
6261 771 : for( int iColor = nColorCount - 1; iColor >= 0; iColor-- )
6262 : {
6263 768 : oEntry.c1 = panRed[iColor] / 256;
6264 768 : oEntry.c2 = panGreen[iColor] / 256;
6265 768 : oEntry.c3 = panBlue[iColor] / 256;
6266 768 : oEntry.c4 = 255;
6267 :
6268 768 : poDS->poColorTable->SetColorEntry( iColor, &oEntry );
6269 : }
6270 : }
6271 :
6272 : /* -------------------------------------------------------------------- */
6273 : /* Do we want to ensure all blocks get written out on close to */
6274 : /* avoid sparse files? */
6275 : /* -------------------------------------------------------------------- */
6276 692 : if( !CSLFetchBoolean( papszParmList, "SPARSE_OK", FALSE ) )
6277 678 : poDS->bFillEmptyTiles = TRUE;
6278 :
6279 : /* -------------------------------------------------------------------- */
6280 : /* Preserve creation options for consulting later (for instance */
6281 : /* to decide if a TFW file should be written). */
6282 : /* -------------------------------------------------------------------- */
6283 692 : poDS->papszCreationOptions = CSLDuplicate( papszParmList );
6284 :
6285 : /* -------------------------------------------------------------------- */
6286 : /* Create band information objects. */
6287 : /* -------------------------------------------------------------------- */
6288 : int iBand;
6289 :
6290 132595 : for( iBand = 0; iBand < nBands; iBand++ )
6291 : {
6292 263783 : if( poDS->nBitsPerSample == 8 ||
6293 : poDS->nBitsPerSample == 16 ||
6294 : poDS->nBitsPerSample == 32 ||
6295 : poDS->nBitsPerSample == 64 ||
6296 : poDS->nBitsPerSample == 128)
6297 131880 : poDS->SetBand( iBand+1, new GTiffRasterBand( poDS, iBand+1 ) );
6298 : else
6299 : {
6300 23 : poDS->SetBand( iBand+1, new GTiffOddBitsBand( poDS, iBand+1 ) );
6301 : poDS->GetRasterBand( iBand+1 )->
6302 : SetMetadataItem( "NBITS",
6303 : CPLString().Printf("%d",poDS->nBitsPerSample),
6304 46 : "IMAGE_STRUCTURE" );
6305 : }
6306 : }
6307 :
6308 692 : return( poDS );
6309 : }
6310 :
6311 : /************************************************************************/
6312 : /* CreateCopy() */
6313 : /************************************************************************/
6314 :
6315 : GDALDataset *
6316 111 : GTiffDataset::CreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
6317 : int bStrict, char ** papszOptions,
6318 : GDALProgressFunc pfnProgress, void * pProgressData )
6319 :
6320 : {
6321 : TIFF *hTIFF;
6322 111 : int nXSize = poSrcDS->GetRasterXSize();
6323 111 : int nYSize = poSrcDS->GetRasterYSize();
6324 111 : int nBands = poSrcDS->GetRasterCount();
6325 : int iBand;
6326 111 : CPLErr eErr = CE_None;
6327 : uint16 nPlanarConfig;
6328 : uint16 nBitsPerSample;
6329 : GDALRasterBand *poPBand;
6330 :
6331 111 : if( poSrcDS->GetRasterCount() == 0 )
6332 : {
6333 : CPLError( CE_Failure, CPLE_AppDefined,
6334 1 : "Unable to export GeoTIFF files with zero bands." );
6335 1 : return NULL;
6336 : }
6337 :
6338 110 : poPBand = poSrcDS->GetRasterBand(1);
6339 110 : GDALDataType eType = poPBand->GetRasterDataType();
6340 :
6341 : /* -------------------------------------------------------------------- */
6342 : /* Check, whether all bands in input dataset has the same type. */
6343 : /* -------------------------------------------------------------------- */
6344 193 : for ( iBand = 2; iBand <= nBands; iBand++ )
6345 : {
6346 83 : if ( eType != poSrcDS->GetRasterBand(iBand)->GetRasterDataType() )
6347 : {
6348 0 : if ( bStrict )
6349 : {
6350 : CPLError( CE_Failure, CPLE_AppDefined,
6351 : "Unable to export GeoTIFF file with different datatypes per\n"
6352 0 : "different bands. All bands should have the same types in TIFF." );
6353 0 : return NULL;
6354 : }
6355 : else
6356 : {
6357 : CPLError( CE_Warning, CPLE_AppDefined,
6358 : "Unable to export GeoTIFF file with different datatypes per\n"
6359 0 : "different bands. All bands should have the same types in TIFF." );
6360 : }
6361 : }
6362 : }
6363 :
6364 110 : if( !pfnProgress( 0.0, NULL, pProgressData ) )
6365 0 : return NULL;
6366 :
6367 : /* -------------------------------------------------------------------- */
6368 : /* Capture the profile. */
6369 : /* -------------------------------------------------------------------- */
6370 : const char *pszProfile;
6371 : int bGeoTIFF;
6372 :
6373 110 : pszProfile = CSLFetchNameValue(papszOptions,"PROFILE");
6374 110 : if( pszProfile == NULL )
6375 102 : pszProfile = "GDALGeoTIFF";
6376 :
6377 110 : if( !EQUAL(pszProfile,"BASELINE")
6378 : && !EQUAL(pszProfile,"GeoTIFF")
6379 : && !EQUAL(pszProfile,"GDALGeoTIFF") )
6380 : {
6381 : CPLError( CE_Failure, CPLE_AppDefined,
6382 : "PROFILE=%s not supported in GTIFF driver.",
6383 0 : pszProfile );
6384 0 : return NULL;
6385 : }
6386 :
6387 110 : if( EQUAL(pszProfile,"BASELINE") )
6388 5 : bGeoTIFF = FALSE;
6389 : else
6390 105 : bGeoTIFF = TRUE;
6391 :
6392 : /* -------------------------------------------------------------------- */
6393 : /* Special handling for NBITS. Copy from band metadata if found. */
6394 : /* -------------------------------------------------------------------- */
6395 110 : char **papszCreateOptions = CSLDuplicate( papszOptions );
6396 :
6397 115 : if( poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) != NULL
6398 5 : && atoi(poPBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" )) > 0
6399 : && CSLFetchNameValue( papszCreateOptions, "NBITS") == NULL )
6400 : {
6401 : papszCreateOptions =
6402 : CSLSetNameValue( papszCreateOptions, "NBITS",
6403 : poPBand->GetMetadataItem( "NBITS",
6404 3 : "IMAGE_STRUCTURE" ) );
6405 : }
6406 :
6407 179 : if( CSLFetchNameValue( papszOptions, "PIXELTYPE" ) == NULL
6408 : && eType == GDT_Byte
6409 69 : && poPBand->GetMetadataItem( "PIXELTYPE", "IMAGE_STRUCTURE" ) )
6410 : {
6411 : papszCreateOptions =
6412 : CSLSetNameValue( papszCreateOptions, "PIXELTYPE",
6413 : poPBand->GetMetadataItem(
6414 0 : "PIXELTYPE", "IMAGE_STRUCTURE" ) );
6415 : }
6416 :
6417 : /* -------------------------------------------------------------------- */
6418 : /* Create the file. */
6419 : /* -------------------------------------------------------------------- */
6420 : hTIFF = CreateLL( pszFilename, nXSize, nYSize, nBands,
6421 110 : eType, papszCreateOptions );
6422 :
6423 110 : CSLDestroy( papszCreateOptions );
6424 :
6425 110 : if( hTIFF == NULL )
6426 0 : return NULL;
6427 :
6428 110 : TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &nPlanarConfig );
6429 110 : TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &nBitsPerSample );
6430 :
6431 : /* -------------------------------------------------------------------- */
6432 : /* Are we really producing an RGBA image? If so, set the */
6433 : /* associated alpha information. */
6434 : /* -------------------------------------------------------------------- */
6435 : int bForcePhotometric =
6436 110 : CSLFetchNameValue(papszOptions,"PHOTOMETRIC") != NULL;
6437 :
6438 112 : if( nBands == 4 && !bForcePhotometric
6439 2 : && poSrcDS->GetRasterBand(4)->GetColorInterpretation()==GCI_AlphaBand)
6440 : {
6441 : uint16 v[1];
6442 :
6443 2 : v[0] = EXTRASAMPLE_ASSOCALPHA;
6444 2 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, 1, v);
6445 2 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB );
6446 : }
6447 :
6448 : /* -------------------------------------------------------------------- */
6449 : /* If the output is jpeg compressed, and the input is RGB make */
6450 : /* sure we note that. */
6451 : /* -------------------------------------------------------------------- */
6452 : uint16 nCompression;
6453 :
6454 110 : if( !TIFFGetField( hTIFF, TIFFTAG_COMPRESSION, &(nCompression) ) )
6455 0 : nCompression = COMPRESSION_NONE;
6456 :
6457 110 : if( nCompression == COMPRESSION_JPEG )
6458 : {
6459 10 : if( nBands >= 3
6460 5 : && (poSrcDS->GetRasterBand(1)->GetColorInterpretation()
6461 : == GCI_YCbCr_YBand)
6462 0 : && (poSrcDS->GetRasterBand(2)->GetColorInterpretation()
6463 : == GCI_YCbCr_CbBand)
6464 0 : && (poSrcDS->GetRasterBand(3)->GetColorInterpretation()
6465 : == GCI_YCbCr_CrBand) )
6466 : {
6467 : /* do nothing ... */
6468 : }
6469 : else
6470 : {
6471 : /* we assume RGB if it isn't explicitly YCbCr */
6472 5 : CPLDebug( "GTiff", "Setting JPEGCOLORMODE_RGB" );
6473 5 : TIFFSetField( hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB );
6474 : }
6475 : }
6476 :
6477 : /* -------------------------------------------------------------------- */
6478 : /* Does the source image consist of one band, with a palette? */
6479 : /* If so, copy over. */
6480 : /* -------------------------------------------------------------------- */
6481 110 : if( nBands == 1 && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
6482 : && eType == GDT_Byte )
6483 : {
6484 : unsigned short anTRed[256], anTGreen[256], anTBlue[256];
6485 : GDALColorTable *poCT;
6486 :
6487 3 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
6488 :
6489 771 : for( int iColor = 0; iColor < 256; iColor++ )
6490 : {
6491 768 : if( iColor < poCT->GetColorEntryCount() )
6492 : {
6493 : GDALColorEntry sRGB;
6494 :
6495 221 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
6496 :
6497 221 : anTRed[iColor] = (unsigned short) (257 * sRGB.c1);
6498 221 : anTGreen[iColor] = (unsigned short) (257 * sRGB.c2);
6499 221 : anTBlue[iColor] = (unsigned short) (257 * sRGB.c3);
6500 : }
6501 : else
6502 : {
6503 547 : anTRed[iColor] = anTGreen[iColor] = anTBlue[iColor] = 0;
6504 : }
6505 : }
6506 :
6507 3 : if( !bForcePhotometric )
6508 3 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
6509 3 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, anTRed, anTGreen, anTBlue );
6510 : }
6511 174 : else if( nBands == 1
6512 67 : && poSrcDS->GetRasterBand(1)->GetColorTable() != NULL
6513 : && eType == GDT_UInt16 )
6514 : {
6515 : unsigned short *panTRed, *panTGreen, *panTBlue;
6516 : GDALColorTable *poCT;
6517 :
6518 1 : panTRed = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6519 1 : panTGreen = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6520 1 : panTBlue = (unsigned short *) CPLMalloc(65536*sizeof(unsigned short));
6521 :
6522 1 : poCT = poSrcDS->GetRasterBand(1)->GetColorTable();
6523 :
6524 65537 : for( int iColor = 0; iColor < 65536; iColor++ )
6525 : {
6526 65536 : if( iColor < poCT->GetColorEntryCount() )
6527 : {
6528 : GDALColorEntry sRGB;
6529 :
6530 65536 : poCT->GetColorEntryAsRGB( iColor, &sRGB );
6531 :
6532 65536 : panTRed[iColor] = (unsigned short) (256 * sRGB.c1);
6533 65536 : panTGreen[iColor] = (unsigned short) (256 * sRGB.c2);
6534 65536 : panTBlue[iColor] = (unsigned short) (256 * sRGB.c3);
6535 : }
6536 : else
6537 : {
6538 0 : panTRed[iColor] = panTGreen[iColor] = panTBlue[iColor] = 0;
6539 : }
6540 : }
6541 :
6542 1 : if( !bForcePhotometric )
6543 1 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE );
6544 1 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panTRed, panTGreen, panTBlue );
6545 :
6546 1 : CPLFree( panTRed );
6547 1 : CPLFree( panTGreen );
6548 1 : CPLFree( panTBlue );
6549 : }
6550 106 : else if( poSrcDS->GetRasterBand(1)->GetColorTable() != NULL )
6551 : CPLError( CE_Warning, CPLE_AppDefined,
6552 : "Unable to export color table to GeoTIFF file. Color tables\n"
6553 0 : "can only be written to 1 band Byte or UInt16 GeoTIFF files." );
6554 :
6555 : /* -------------------------------------------------------------------- */
6556 : /* Transfer some TIFF specific metadata, if available. */
6557 : /* The return value will tell us if we need to try again later with*/
6558 : /* PAM because the profile doesn't allow to write some metadata */
6559 : /* as TIFF tag */
6560 : /* -------------------------------------------------------------------- */
6561 : int bHasWrittenMDInGeotiffTAG =
6562 : GTiffDataset::WriteMetadata( poSrcDS, hTIFF, FALSE, pszProfile,
6563 110 : pszFilename, papszOptions );
6564 :
6565 : /* -------------------------------------------------------------------- */
6566 : /* Write NoData value, if exist. */
6567 : /* -------------------------------------------------------------------- */
6568 110 : if( EQUAL(pszProfile,"GDALGeoTIFF") )
6569 : {
6570 : int bSuccess;
6571 : double dfNoData;
6572 :
6573 103 : dfNoData = poSrcDS->GetRasterBand(1)->GetNoDataValue( &bSuccess );
6574 103 : if ( bSuccess )
6575 17 : GTiffDataset::WriteNoDataValue( hTIFF, dfNoData );
6576 : }
6577 :
6578 : /* -------------------------------------------------------------------- */
6579 : /* Write affine transform if it is meaningful. */
6580 : /* -------------------------------------------------------------------- */
6581 110 : const char *pszProjection = NULL;
6582 : double adfGeoTransform[6];
6583 :
6584 192 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None
6585 82 : && (adfGeoTransform[0] != 0.0 || adfGeoTransform[1] != 1.0
6586 0 : || adfGeoTransform[2] != 0.0 || adfGeoTransform[3] != 0.0
6587 0 : || adfGeoTransform[4] != 0.0 || ABS(adfGeoTransform[5]) != 1.0 ))
6588 : {
6589 82 : if( bGeoTIFF )
6590 : {
6591 232 : if( adfGeoTransform[2] == 0.0 && adfGeoTransform[4] == 0.0
6592 77 : && adfGeoTransform[5] < 0.0 )
6593 : {
6594 :
6595 : double adfPixelScale[3], adfTiePoints[6];
6596 :
6597 77 : adfPixelScale[0] = adfGeoTransform[1];
6598 77 : adfPixelScale[1] = fabs(adfGeoTransform[5]);
6599 77 : adfPixelScale[2] = 0.0;
6600 :
6601 77 : TIFFSetField( hTIFF, TIFFTAG_GEOPIXELSCALE, 3, adfPixelScale );
6602 :
6603 77 : adfTiePoints[0] = 0.0;
6604 77 : adfTiePoints[1] = 0.0;
6605 77 : adfTiePoints[2] = 0.0;
6606 77 : adfTiePoints[3] = adfGeoTransform[0];
6607 77 : adfTiePoints[4] = adfGeoTransform[3];
6608 77 : adfTiePoints[5] = 0.0;
6609 :
6610 77 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS, 6, adfTiePoints );
6611 : }
6612 : else
6613 : {
6614 : double adfMatrix[16];
6615 :
6616 1 : memset(adfMatrix,0,sizeof(double) * 16);
6617 :
6618 1 : adfMatrix[0] = adfGeoTransform[1];
6619 1 : adfMatrix[1] = adfGeoTransform[2];
6620 1 : adfMatrix[3] = adfGeoTransform[0];
6621 1 : adfMatrix[4] = adfGeoTransform[4];
6622 1 : adfMatrix[5] = adfGeoTransform[5];
6623 1 : adfMatrix[7] = adfGeoTransform[3];
6624 1 : adfMatrix[15] = 1.0;
6625 :
6626 1 : TIFFSetField( hTIFF, TIFFTAG_GEOTRANSMATRIX, 16, adfMatrix );
6627 : }
6628 :
6629 78 : pszProjection = poSrcDS->GetProjectionRef();
6630 : }
6631 :
6632 : /* -------------------------------------------------------------------- */
6633 : /* Do we need a TFW file? */
6634 : /* -------------------------------------------------------------------- */
6635 82 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE ) )
6636 1 : GDALWriteWorldFile( pszFilename, "tfw", adfGeoTransform );
6637 81 : else if( CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
6638 1 : GDALWriteWorldFile( pszFilename, "wld", adfGeoTransform );
6639 : }
6640 :
6641 : /* -------------------------------------------------------------------- */
6642 : /* Otherwise write tiepoints if they are available. */
6643 : /* -------------------------------------------------------------------- */
6644 28 : else if( poSrcDS->GetGCPCount() > 0 && bGeoTIFF )
6645 : {
6646 3 : const GDAL_GCP *pasGCPs = poSrcDS->GetGCPs();
6647 : double *padfTiePoints;
6648 :
6649 : padfTiePoints = (double *)
6650 3 : CPLMalloc(6*sizeof(double)*poSrcDS->GetGCPCount());
6651 :
6652 15 : for( int iGCP = 0; iGCP < poSrcDS->GetGCPCount(); iGCP++ )
6653 : {
6654 :
6655 12 : padfTiePoints[iGCP*6+0] = pasGCPs[iGCP].dfGCPPixel;
6656 12 : padfTiePoints[iGCP*6+1] = pasGCPs[iGCP].dfGCPLine;
6657 12 : padfTiePoints[iGCP*6+2] = 0;
6658 12 : padfTiePoints[iGCP*6+3] = pasGCPs[iGCP].dfGCPX;
6659 12 : padfTiePoints[iGCP*6+4] = pasGCPs[iGCP].dfGCPY;
6660 12 : padfTiePoints[iGCP*6+5] = pasGCPs[iGCP].dfGCPZ;
6661 : }
6662 :
6663 : TIFFSetField( hTIFF, TIFFTAG_GEOTIEPOINTS,
6664 3 : 6*poSrcDS->GetGCPCount(), padfTiePoints );
6665 3 : CPLFree( padfTiePoints );
6666 :
6667 3 : pszProjection = poSrcDS->GetGCPProjection();
6668 :
6669 3 : if( CSLFetchBoolean( papszOptions, "TFW", FALSE )
6670 : || CSLFetchBoolean( papszOptions, "WORLDFILE", FALSE ) )
6671 : {
6672 : CPLError(CE_Warning, CPLE_AppDefined,
6673 0 : "TFW=ON or WORLDFILE=ON creation options are ignored when GCPs are available");
6674 : }
6675 : }
6676 :
6677 : else
6678 25 : pszProjection = poSrcDS->GetProjectionRef();
6679 :
6680 : /* -------------------------------------------------------------------- */
6681 : /* Write the projection information, if possible. */
6682 : /* -------------------------------------------------------------------- */
6683 110 : if( pszProjection != NULL && strlen(pszProjection) > 0 && bGeoTIFF )
6684 : {
6685 : GTIF *psGTIF;
6686 :
6687 79 : psGTIF = GTIFNew( hTIFF );
6688 79 : GTIFSetFromOGISDefn( psGTIF, pszProjection );
6689 :
6690 139 : if( poSrcDS->GetMetadataItem( GDALMD_AREA_OR_POINT )
6691 60 : && EQUAL(poSrcDS->GetMetadataItem(GDALMD_AREA_OR_POINT),
6692 : GDALMD_AOP_POINT) )
6693 : {
6694 : GTIFKeySet(psGTIF, GTRasterTypeGeoKey, TYPE_SHORT, 1,
6695 1 : RasterPixelIsPoint);
6696 : }
6697 :
6698 79 : GTIFWriteKeys( psGTIF );
6699 79 : GTIFFree( psGTIF );
6700 : }
6701 :
6702 : /* -------------------------------------------------------------------- */
6703 : /* Cleanup */
6704 : /* -------------------------------------------------------------------- */
6705 :
6706 110 : TIFFWriteCheck( hTIFF, TIFFIsTiled(hTIFF), "GTiffCreateCopy()");
6707 110 : TIFFWriteDirectory( hTIFF );
6708 110 : TIFFFlush( hTIFF );
6709 110 : XTIFFClose( hTIFF );
6710 110 : hTIFF = NULL;
6711 :
6712 110 : if( eErr != CE_None )
6713 : {
6714 0 : VSIUnlink( pszFilename );
6715 0 : return NULL;
6716 : }
6717 :
6718 : /* -------------------------------------------------------------------- */
6719 : /* Re-open as a dataset and copy over missing metadata using */
6720 : /* PAM facilities. */
6721 : /* -------------------------------------------------------------------- */
6722 : GTiffDataset *poDS;
6723 110 : CPLString osFileName("GTIFF_RAW:");
6724 :
6725 110 : osFileName += pszFilename;
6726 :
6727 110 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_Update );
6728 110 : if( poDS == NULL )
6729 0 : poDS = (GTiffDataset *) GDALOpen( osFileName, GA_ReadOnly );
6730 :
6731 110 : if ( poDS == NULL )
6732 : {
6733 0 : VSIUnlink( pszFilename );
6734 0 : return NULL;
6735 : }
6736 :
6737 110 : poDS->osProfile = pszProfile;
6738 110 : poDS->CloneInfo( poSrcDS, GCIF_PAM_DEFAULT );
6739 110 : poDS->papszCreationOptions = CSLDuplicate( papszOptions );
6740 :
6741 : /* -------------------------------------------------------------------- */
6742 : /* CloneInfo() doesn't merge metadata, it just replaces it totally */
6743 : /* So we have to merge it */
6744 : /* -------------------------------------------------------------------- */
6745 :
6746 110 : char **papszSRC_MD = poSrcDS->GetMetadata();
6747 110 : char **papszDST_MD = CSLDuplicate(poDS->GetMetadata());
6748 :
6749 110 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
6750 :
6751 110 : poDS->SetMetadata( papszDST_MD );
6752 110 : CSLDestroy( papszDST_MD );
6753 :
6754 : /* Depending on the PHOTOMETRIC tag, the TIFF file may not have */
6755 : /* the same band count as the source. Will fail later in GDALDatasetCopyWholeRaster anyway... */
6756 303 : for( int nBand = 1;
6757 : nBand <= MIN(poDS->GetRasterCount(), poSrcDS->GetRasterCount()) ;
6758 : nBand++ )
6759 : {
6760 193 : char **papszSRC_MD = poSrcDS->GetRasterBand(nBand)->GetMetadata();
6761 193 : char **papszDST_MD = CSLDuplicate(poDS->GetRasterBand(nBand)->GetMetadata());
6762 :
6763 193 : papszDST_MD = CSLMerge( papszDST_MD, papszSRC_MD );
6764 :
6765 193 : poDS->GetRasterBand(nBand)->SetMetadata( papszDST_MD );
6766 193 : CSLDestroy( papszDST_MD );
6767 : }
6768 :
6769 110 : hTIFF = (TIFF*) poDS->GetInternalHandle(NULL);
6770 :
6771 : /* -------------------------------------------------------------------- */
6772 : /* Second chance : now that we have a PAM dataset, it is possible */
6773 : /* to write metadata that we couldn't be writen as TIFF tag */
6774 : /* -------------------------------------------------------------------- */
6775 110 : if (!bHasWrittenMDInGeotiffTAG)
6776 : GTiffDataset::WriteMetadata( poDS, hTIFF, TRUE, pszProfile,
6777 4 : pszFilename, papszOptions, TRUE /* don't write RPC and IMG file again */);
6778 :
6779 : /* To avoid unnecessary directory rewriting */
6780 110 : poDS->bMetadataChanged = FALSE;
6781 110 : poDS->bGeoTIFFInfoChanged = FALSE;
6782 :
6783 : /* We must re-set the compression level at this point, since it has */
6784 : /* been lost a few lines above when closing the newly create TIFF file */
6785 : /* The TIFFTAG_ZIPQUALITY & TIFFTAG_JPEGQUALITY are not store in the TIFF file. */
6786 : /* They are just TIFF session parameters */
6787 110 : if (nCompression == COMPRESSION_ADOBE_DEFLATE)
6788 : {
6789 4 : int nZLevel = GTiffGetZLevel(papszOptions);
6790 4 : if (nZLevel != -1)
6791 : {
6792 0 : TIFFSetField( hTIFF, TIFFTAG_ZIPQUALITY, nZLevel );
6793 : }
6794 : }
6795 106 : else if( nCompression == COMPRESSION_JPEG)
6796 : {
6797 5 : int nJpegQuality = GTiffGetJpegQuality(papszOptions);
6798 5 : if (nJpegQuality != -1)
6799 : {
6800 2 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality );
6801 : }
6802 : }
6803 :
6804 : /* -------------------------------------------------------------------- */
6805 : /* Copy actual imagery. */
6806 : /* -------------------------------------------------------------------- */
6807 :
6808 113 : if (poDS->bTreatAsSplit || poDS->bTreatAsSplitBitmap)
6809 : {
6810 : /* For split bands, we use TIFFWriteScanline() interface */
6811 : CPLAssert(poDS->nBitsPerSample == 8 || poDS->nBitsPerSample == 1);
6812 :
6813 5 : if (poDS->nPlanarConfig == PLANARCONFIG_CONTIG && poDS->nBands > 1)
6814 : {
6815 : int j;
6816 2 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
6817 2 : eErr = CE_None;
6818 7050 : for(j=0;j<nYSize && eErr == CE_None;j++)
6819 : {
6820 : eErr = poSrcDS->RasterIO(GF_Read, 0, j, nXSize, 1,
6821 : pabyScanline, nXSize, 1,
6822 7048 : GDT_Byte, nBands, NULL, poDS->nBands, 0, 1);
6823 7048 : if (eErr == CE_None &&
6824 : TIFFWriteScanline( hTIFF, pabyScanline, j, 0) == -1)
6825 : {
6826 : CPLError( CE_Failure, CPLE_AppDefined,
6827 0 : "TIFFWriteScanline() failed." );
6828 0 : eErr = CE_Failure;
6829 : }
6830 7048 : if( !pfnProgress( (j+1) * 1.0 / nYSize, NULL, pProgressData ) )
6831 0 : eErr = CE_Failure;
6832 : }
6833 2 : CPLFree(pabyScanline);
6834 : }
6835 : else
6836 : {
6837 : int iBand, j;
6838 1 : GByte* pabyScanline = (GByte *) CPLMalloc(TIFFScanlineSize(hTIFF));
6839 1 : eErr = CE_None;
6840 4 : for(iBand=1;iBand<=nBands && eErr == CE_None;iBand++)
6841 : {
6842 15003 : for(j=0;j<nYSize && eErr == CE_None;j++)
6843 : {
6844 : eErr = poSrcDS->GetRasterBand(iBand)->RasterIO(
6845 : GF_Read, 0, j, nXSize, 1,
6846 : pabyScanline, nXSize, 1,
6847 15000 : GDT_Byte, 0, 0);
6848 15000 : if (poDS->bTreatAsSplitBitmap)
6849 : {
6850 0 : for(int i=0;i<nXSize;i++)
6851 : {
6852 0 : GByte byVal = pabyScanline[i];
6853 0 : if ((i & 0x7) == 0)
6854 0 : pabyScanline[i >> 3] = 0;
6855 0 : if (byVal)
6856 0 : pabyScanline[i >> 3] |= (0x80 >> (i & 0x7));
6857 : }
6858 : }
6859 15000 : if (eErr == CE_None &&
6860 : TIFFWriteScanline( hTIFF, pabyScanline, j, iBand - 1) == -1)
6861 : {
6862 : CPLError( CE_Failure, CPLE_AppDefined,
6863 0 : "TIFFWriteScanline() failed." );
6864 0 : eErr = CE_Failure;
6865 : }
6866 15000 : if( !pfnProgress( (j+1 + (iBand - 1) * nYSize) * 1.0 /
6867 : (nBands * nYSize), NULL, pProgressData ) )
6868 0 : eErr = CE_Failure;
6869 : }
6870 : }
6871 1 : CPLFree(pabyScanline);
6872 : }
6873 :
6874 : /* Necessary to be able to read the file without re-opening */
6875 3 : TIFFFlush( hTIFF );
6876 : }
6877 : else
6878 : {
6879 107 : char* papszCopyWholeRasterOptions[2] = { NULL, NULL };
6880 107 : if (nCompression != COMPRESSION_NONE)
6881 11 : papszCopyWholeRasterOptions[0] = (char*) "COMPRESSED=YES";
6882 : eErr = GDALDatasetCopyWholeRaster( (GDALDatasetH) poSrcDS,
6883 : (GDALDatasetH) poDS,
6884 : papszCopyWholeRasterOptions,
6885 107 : pfnProgress, pProgressData );
6886 : }
6887 :
6888 110 : if( eErr == CE_Failure )
6889 : {
6890 0 : delete poDS;
6891 0 : poDS = NULL;
6892 :
6893 0 : VSIUnlink( pszFilename ); // should really delete more carefully.
6894 : }
6895 :
6896 110 : return poDS;
6897 : }
6898 :
6899 : /************************************************************************/
6900 : /* GetProjectionRef() */
6901 : /************************************************************************/
6902 :
6903 2949 : const char *GTiffDataset::GetProjectionRef()
6904 :
6905 : {
6906 2949 : if( nGCPCount == 0 )
6907 : {
6908 2921 : LookForProjection();
6909 :
6910 2921 : if( EQUAL(pszProjection,"") )
6911 59 : return GDALPamDataset::GetProjectionRef();
6912 : else
6913 2862 : return( pszProjection );
6914 : }
6915 : else
6916 28 : return "";
6917 : }
6918 :
6919 : /************************************************************************/
6920 : /* SetProjection() */
6921 : /************************************************************************/
6922 :
6923 524 : CPLErr GTiffDataset::SetProjection( const char * pszNewProjection )
6924 :
6925 : {
6926 524 : LookForProjection();
6927 :
6928 524 : if( !EQUALN(pszNewProjection,"GEOGCS",6)
6929 : && !EQUALN(pszNewProjection,"PROJCS",6)
6930 : && !EQUALN(pszNewProjection,"LOCAL_CS",6)
6931 : && !EQUAL(pszNewProjection,"") )
6932 : {
6933 : CPLError( CE_Failure, CPLE_AppDefined,
6934 : "Only OGC WKT Projections supported for writing to GeoTIFF.\n"
6935 : "%s not supported.",
6936 0 : pszNewProjection );
6937 :
6938 0 : return CE_Failure;
6939 : }
6940 :
6941 524 : CPLFree( pszProjection );
6942 524 : pszProjection = CPLStrdup( pszNewProjection );
6943 :
6944 524 : bGeoTIFFInfoChanged = TRUE;
6945 :
6946 524 : return CE_None;
6947 : }
6948 :
6949 : /************************************************************************/
6950 : /* GetGeoTransform() */
6951 : /************************************************************************/
6952 :
6953 1888 : CPLErr GTiffDataset::GetGeoTransform( double * padfTransform )
6954 :
6955 : {
6956 1888 : memcpy( padfTransform, adfGeoTransform, sizeof(double)*6 );
6957 :
6958 1888 : if( !bGeoTransformValid )
6959 76 : return CE_Failure;
6960 : else
6961 1812 : return CE_None;
6962 : }
6963 :
6964 : /************************************************************************/
6965 : /* SetGeoTransform() */
6966 : /************************************************************************/
6967 :
6968 529 : CPLErr GTiffDataset::SetGeoTransform( double * padfTransform )
6969 :
6970 : {
6971 529 : if( GetAccess() == GA_Update )
6972 : {
6973 529 : memcpy( adfGeoTransform, padfTransform, sizeof(double)*6 );
6974 529 : bGeoTransformValid = TRUE;
6975 529 : bGeoTIFFInfoChanged = TRUE;
6976 :
6977 529 : return( CE_None );
6978 : }
6979 : else
6980 : {
6981 : CPLError( CE_Failure, CPLE_NotSupported,
6982 0 : "SetGeoTransform() is only supported on newly created GeoTIFF files." );
6983 0 : return CE_Failure;
6984 : }
6985 : }
6986 :
6987 : /************************************************************************/
6988 : /* GetGCPCount() */
6989 : /************************************************************************/
6990 :
6991 774 : int GTiffDataset::GetGCPCount()
6992 :
6993 : {
6994 774 : return nGCPCount;
6995 : }
6996 :
6997 : /************************************************************************/
6998 : /* GetGCPProjection() */
6999 : /************************************************************************/
7000 :
7001 72 : const char *GTiffDataset::GetGCPProjection()
7002 :
7003 : {
7004 72 : if( nGCPCount > 0 )
7005 : {
7006 72 : LookForProjection();
7007 72 : return pszProjection;
7008 : }
7009 : else
7010 0 : return GDALPamDataset::GetGCPProjection();
7011 : }
7012 :
7013 : /************************************************************************/
7014 : /* GetGCPs() */
7015 : /************************************************************************/
7016 :
7017 42 : const GDAL_GCP *GTiffDataset::GetGCPs()
7018 :
7019 : {
7020 42 : return pasGCPList;
7021 : }
7022 :
7023 : /************************************************************************/
7024 : /* SetGCPs() */
7025 : /************************************************************************/
7026 :
7027 1 : CPLErr GTiffDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
7028 : const char *pszGCPProjection )
7029 : {
7030 1 : if( GetAccess() == GA_Update )
7031 : {
7032 1 : bLookedForProjection = TRUE;
7033 :
7034 1 : if( this->nGCPCount > 0 )
7035 : {
7036 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
7037 0 : CPLFree( this->pasGCPList );
7038 : }
7039 :
7040 1 : this->nGCPCount = nGCPCount;
7041 1 : this->pasGCPList = GDALDuplicateGCPs(nGCPCount, pasGCPList);
7042 :
7043 1 : CPLFree( this->pszProjection );
7044 1 : this->pszProjection = CPLStrdup( pszGCPProjection );
7045 1 : bGeoTIFFInfoChanged = TRUE;
7046 :
7047 1 : return CE_None;
7048 : }
7049 : else
7050 : {
7051 : CPLError( CE_Failure, CPLE_NotSupported,
7052 0 : "SetGCPs() is only supported on newly created GeoTIFF files." );
7053 0 : return CE_Failure;
7054 : }
7055 : }
7056 :
7057 : /************************************************************************/
7058 : /* GetMetadata() */
7059 : /************************************************************************/
7060 :
7061 3766 : char **GTiffDataset::GetMetadata( const char * pszDomain )
7062 :
7063 : {
7064 3766 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
7065 0 : return GDALPamDataset::GetMetadata( pszDomain );
7066 : else
7067 3766 : return oGTiffMDMD.GetMetadata( pszDomain );
7068 : }
7069 :
7070 : /************************************************************************/
7071 : /* SetMetadata() */
7072 : /************************************************************************/
7073 147 : CPLErr GTiffDataset::SetMetadata( char ** papszMD, const char *pszDomain )
7074 :
7075 : {
7076 147 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
7077 147 : bMetadataChanged = TRUE;
7078 :
7079 147 : return oGTiffMDMD.SetMetadata( papszMD, pszDomain );
7080 : }
7081 :
7082 : /************************************************************************/
7083 : /* GetMetadataItem() */
7084 : /************************************************************************/
7085 :
7086 16570 : const char *GTiffDataset::GetMetadataItem( const char * pszName,
7087 : const char * pszDomain )
7088 :
7089 : {
7090 16570 : if( pszDomain != NULL && EQUAL(pszDomain,"ProxyOverviewRequest") )
7091 2 : return GDALPamDataset::GetMetadataItem( pszName, pszDomain );
7092 : else
7093 16568 : return oGTiffMDMD.GetMetadataItem( pszName, pszDomain );
7094 : }
7095 :
7096 : /************************************************************************/
7097 : /* SetMetadataItem() */
7098 : /************************************************************************/
7099 :
7100 4786 : CPLErr GTiffDataset::SetMetadataItem( const char *pszName,
7101 : const char *pszValue,
7102 : const char *pszDomain )
7103 :
7104 : {
7105 4786 : if( pszDomain == NULL || !EQUAL(pszDomain,"_temporary_") )
7106 4786 : bMetadataChanged = TRUE;
7107 :
7108 4786 : return oGTiffMDMD.SetMetadataItem( pszName, pszValue, pszDomain );
7109 : }
7110 :
7111 : /************************************************************************/
7112 : /* GetInternalHandle() */
7113 : /************************************************************************/
7114 :
7115 142 : void *GTiffDataset::GetInternalHandle( const char * /* pszHandleName */ )
7116 :
7117 : {
7118 142 : return hTIFF;
7119 : }
7120 :
7121 : /************************************************************************/
7122 : /* GetFileList() */
7123 : /************************************************************************/
7124 :
7125 772 : char **GTiffDataset::GetFileList()
7126 :
7127 : {
7128 772 : char **papszFileList = GDALPamDataset::GetFileList();
7129 : VSIStatBufL sStatBuf;
7130 :
7131 : /* -------------------------------------------------------------------- */
7132 : /* Check for .imd file. */
7133 : /* -------------------------------------------------------------------- */
7134 772 : CPLString osTarget = CPLResetExtension( osFilename, "IMD" );
7135 772 : if( VSIStatL( osTarget, &sStatBuf ) == 0 )
7136 2 : papszFileList = CSLAddString( papszFileList, osTarget );
7137 : else
7138 : {
7139 770 : osTarget = CPLResetExtension( osFilename, "imd" );
7140 770 : if( VSIStatL( osTarget, &sStatBuf ) == 0 )
7141 0 : papszFileList = CSLAddString( papszFileList, osTarget );
7142 : }
7143 :
7144 : /* -------------------------------------------------------------------- */
7145 : /* Check for .rpb file. */
7146 : /* -------------------------------------------------------------------- */
7147 772 : osTarget = CPLResetExtension( osFilename, "RPB" );
7148 772 : if( VSIStatL( osTarget, &sStatBuf ) == 0 )
7149 1 : papszFileList = CSLAddString( papszFileList, osTarget );
7150 : else
7151 : {
7152 771 : osTarget = CPLResetExtension( osFilename, "rpb" );
7153 771 : if( VSIStatL( osTarget, &sStatBuf ) == 0 )
7154 0 : papszFileList = CSLAddString( papszFileList, osTarget );
7155 : }
7156 :
7157 772 : return papszFileList;
7158 : }
7159 :
7160 : /************************************************************************/
7161 : /* CreateMaskBand() */
7162 : /************************************************************************/
7163 :
7164 12 : CPLErr GTiffDataset::CreateMaskBand(int nFlags)
7165 : {
7166 12 : if (poMaskDS != NULL)
7167 : {
7168 : CPLError(CE_Failure, CPLE_AppDefined,
7169 0 : "This TIFF dataset has already an internal mask band");
7170 0 : return CE_Failure;
7171 : }
7172 12 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
7173 : {
7174 : toff_t nOffset;
7175 : int bIsTiled;
7176 11 : int bIsOverview = FALSE;
7177 : uint32 nSubType;
7178 :
7179 11 : if (nFlags != GMF_PER_DATASET)
7180 : {
7181 : CPLError(CE_Failure, CPLE_AppDefined,
7182 0 : "The only flag value supported for internal mask is GMF_PER_DATASET");
7183 0 : return CE_Failure;
7184 : }
7185 :
7186 : /* -------------------------------------------------------------------- */
7187 : /* If we don't have read access, then create the mask externally. */
7188 : /* -------------------------------------------------------------------- */
7189 11 : if( GetAccess() != GA_Update )
7190 : {
7191 : CPLError( CE_Warning, CPLE_AppDefined,
7192 : "File open for read-only accessing, "
7193 0 : "creating mask externally." );
7194 :
7195 0 : return GDALPamDataset::CreateMaskBand(nFlags);
7196 : }
7197 :
7198 11 : if (poBaseDS)
7199 : {
7200 6 : if (!poBaseDS->SetDirectory())
7201 0 : return CE_Failure;
7202 : }
7203 11 : if (!SetDirectory())
7204 0 : return CE_Failure;
7205 :
7206 11 : if( TIFFGetField(hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
7207 : {
7208 6 : bIsOverview = (nSubType & FILETYPE_REDUCEDIMAGE) != 0;
7209 :
7210 6 : if ((nSubType & FILETYPE_MASK) != 0)
7211 : {
7212 : CPLError( CE_Failure, CPLE_AppDefined,
7213 0 : "Cannot create a mask on a TIFF mask IFD !" );
7214 0 : return CE_Failure;
7215 : }
7216 : }
7217 :
7218 11 : TIFFFlush( hTIFF );
7219 :
7220 11 : bIsTiled = TIFFIsTiled(hTIFF);
7221 :
7222 : nOffset = GTIFFWriteDirectory(hTIFF,
7223 : (bIsOverview) ? FILETYPE_REDUCEDIMAGE | FILETYPE_MASK : FILETYPE_MASK,
7224 : nRasterXSize, nRasterYSize,
7225 : 1, PLANARCONFIG_CONTIG, 1,
7226 : nBlockXSize, nBlockYSize,
7227 : bIsTiled, COMPRESSION_NONE, PHOTOMETRIC_MASK,
7228 11 : SAMPLEFORMAT_UINT, NULL, NULL, NULL, 0, NULL, "");
7229 11 : if (nOffset == 0)
7230 0 : return CE_Failure;
7231 :
7232 11 : poMaskDS = new GTiffDataset();
7233 11 : if( poMaskDS->OpenOffset( hTIFF, ppoActiveDSRef, nOffset,
7234 : FALSE, GA_Update ) != CE_None)
7235 : {
7236 0 : delete poMaskDS;
7237 0 : poMaskDS = NULL;
7238 0 : return CE_Failure;
7239 : }
7240 :
7241 11 : return CE_None;
7242 : }
7243 : else
7244 : {
7245 1 : return GDALPamDataset::CreateMaskBand(nFlags);
7246 : }
7247 : }
7248 :
7249 : /************************************************************************/
7250 : /* CreateMaskBand() */
7251 : /************************************************************************/
7252 :
7253 6 : CPLErr GTiffRasterBand::CreateMaskBand(int nFlags)
7254 : {
7255 6 : if (poGDS->poMaskDS != NULL)
7256 : {
7257 : CPLError(CE_Failure, CPLE_AppDefined,
7258 0 : "This TIFF dataset has already an internal mask band");
7259 0 : return CE_Failure;
7260 : }
7261 6 : else if (CSLTestBoolean(CPLGetConfigOption("GDAL_TIFF_INTERNAL_MASK", "NO")))
7262 : {
7263 6 : return poGDS->CreateMaskBand(nFlags);
7264 : }
7265 : else
7266 : {
7267 0 : return GDALPamRasterBand::CreateMaskBand(nFlags);
7268 : }
7269 : }
7270 :
7271 : /************************************************************************/
7272 : /* PrepareTIFFErrorFormat() */
7273 : /* */
7274 : /* sometimes the "module" has stuff in it that has special */
7275 : /* meaning in a printf() style format, so we try to escape it. */
7276 : /* For now we hope the only thing we have to escape is %'s. */
7277 : /************************************************************************/
7278 :
7279 0 : static char *PrepareTIFFErrorFormat( const char *module, const char *fmt )
7280 :
7281 : {
7282 : char *pszModFmt;
7283 : int iIn, iOut;
7284 :
7285 0 : pszModFmt = (char *) CPLMalloc( strlen(module)*2 + strlen(fmt) + 2 );
7286 0 : for( iOut = 0, iIn = 0; module[iIn] != '\0'; iIn++ )
7287 : {
7288 0 : if( module[iIn] == '%' )
7289 : {
7290 0 : pszModFmt[iOut++] = '%';
7291 0 : pszModFmt[iOut++] = '%';
7292 : }
7293 : else
7294 0 : pszModFmt[iOut++] = module[iIn];
7295 : }
7296 0 : pszModFmt[iOut] = '\0';
7297 0 : strcat( pszModFmt, ":" );
7298 0 : strcat( pszModFmt, fmt );
7299 :
7300 0 : return pszModFmt;
7301 : }
7302 :
7303 : /************************************************************************/
7304 : /* GTiffWarningHandler() */
7305 : /************************************************************************/
7306 : void
7307 0 : GTiffWarningHandler(const char* module, const char* fmt, va_list ap )
7308 : {
7309 : char *pszModFmt;
7310 :
7311 0 : if( strstr(fmt,"unknown field") != NULL )
7312 0 : return;
7313 :
7314 0 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
7315 0 : CPLErrorV( CE_Warning, CPLE_AppDefined, pszModFmt, ap );
7316 0 : CPLFree( pszModFmt );
7317 : }
7318 :
7319 : /************************************************************************/
7320 : /* GTiffWarningHandler() */
7321 : /************************************************************************/
7322 : void
7323 0 : GTiffErrorHandler(const char* module, const char* fmt, va_list ap )
7324 : {
7325 : char *pszModFmt;
7326 :
7327 0 : pszModFmt = PrepareTIFFErrorFormat( module, fmt );
7328 0 : CPLErrorV( CE_Failure, CPLE_AppDefined, pszModFmt, ap );
7329 0 : CPLFree( pszModFmt );
7330 0 : }
7331 :
7332 : /************************************************************************/
7333 : /* GTiffTagExtender() */
7334 : /* */
7335 : /* Install tags specially known to GDAL. */
7336 : /************************************************************************/
7337 :
7338 : static TIFFExtendProc _ParentExtender = NULL;
7339 :
7340 7062 : static void GTiffTagExtender(TIFF *tif)
7341 :
7342 : {
7343 : static const TIFFFieldInfo xtiffFieldInfo[] = {
7344 : { TIFFTAG_GDAL_METADATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
7345 : TRUE, FALSE, (char*) "GDALMetadata" },
7346 : { TIFFTAG_GDAL_NODATA, -1,-1, TIFF_ASCII, FIELD_CUSTOM,
7347 : TRUE, FALSE, (char*) "GDALNoDataValue" },
7348 : { TIFFTAG_RPCCOEFFICIENT, -1,-1, TIFF_DOUBLE, FIELD_CUSTOM,
7349 : TRUE, TRUE, (char*) "RPCCoefficient" }
7350 : };
7351 :
7352 7062 : if (_ParentExtender)
7353 0 : (*_ParentExtender)(tif);
7354 :
7355 : TIFFMergeFieldInfo( tif, xtiffFieldInfo,
7356 7062 : sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]) );
7357 7062 : }
7358 :
7359 : /************************************************************************/
7360 : /* GTiffOneTimeInit() */
7361 : /* */
7362 : /* This is stuff that is initialized for the TIFF library just */
7363 : /* once. We deliberately defer the initialization till the */
7364 : /* first time we are likely to call into libtiff to avoid */
7365 : /* unnecessary paging in of the library for GDAL apps that */
7366 : /* don't use it. */
7367 : /************************************************************************/
7368 :
7369 3692 : void GTiffOneTimeInit()
7370 :
7371 : {
7372 : static int bOneTimeInitDone = FALSE;
7373 :
7374 3692 : if( bOneTimeInitDone )
7375 3382 : return;
7376 :
7377 310 : bOneTimeInitDone = TRUE;
7378 :
7379 310 : _ParentExtender = TIFFSetTagExtender(GTiffTagExtender);
7380 :
7381 310 : TIFFSetWarningHandler( GTiffWarningHandler );
7382 310 : TIFFSetErrorHandler( GTiffErrorHandler );
7383 :
7384 : // This only really needed if we are linked to an external libgeotiff
7385 : // with its own (lame) file searching logic.
7386 310 : SetCSVFilenameHook( GDALDefaultCSVFilename );
7387 : }
7388 :
7389 : /************************************************************************/
7390 : /* GDALDeregister_GTiff() */
7391 : /************************************************************************/
7392 :
7393 325 : void GDALDeregister_GTiff( GDALDriver * )
7394 :
7395 : {
7396 325 : CPLDebug( "GDAL", "GDALDeregister_GTiff() called." );
7397 325 : CSVDeaccess( NULL );
7398 :
7399 : #if defined(LIBGEOTIFF_VERSION) && LIBGEOTIFF_VERSION > 1150
7400 325 : GTIFDeaccessCSV();
7401 : #endif
7402 325 : }
7403 :
7404 : /************************************************************************/
7405 : /* GDALRegister_GTiff() */
7406 : /************************************************************************/
7407 :
7408 338 : void GDALRegister_GTiff()
7409 :
7410 : {
7411 338 : if( GDALGetDriverByName( "GTiff" ) == NULL )
7412 : {
7413 : GDALDriver *poDriver;
7414 : char szCreateOptions[3072];
7415 : char szOptionalCompressItems[500];
7416 336 : int bHasJPEG = FALSE, bHasLZW = FALSE, bHasDEFLATE = FALSE;
7417 :
7418 336 : poDriver = new GDALDriver();
7419 :
7420 : /* -------------------------------------------------------------------- */
7421 : /* Determine which compression codecs are available that we */
7422 : /* want to advertise. If we are using an old libtiff we won't */
7423 : /* be able to find out so we just assume all are available. */
7424 : /* -------------------------------------------------------------------- */
7425 : strcpy( szOptionalCompressItems,
7426 336 : " <Value>NONE</Value>" );
7427 :
7428 : #if TIFFLIB_VERSION <= 20040919
7429 : strcat( szOptionalCompressItems,
7430 : " <Value>PACKBITS</Value>"
7431 : " <Value>JPEG</Value>"
7432 : " <Value>LZW</Value>"
7433 : " <Value>DEFLATE</Value>" );
7434 : bHasLZW = bHasDEFLATE = TRUE;
7435 : #else
7436 336 : TIFFCodec *c, *codecs = TIFFGetConfiguredCODECs();
7437 :
7438 5712 : for( c = codecs; c->name; c++ )
7439 : {
7440 5376 : if( c->scheme == COMPRESSION_PACKBITS )
7441 : strcat( szOptionalCompressItems,
7442 336 : " <Value>PACKBITS</Value>" );
7443 5040 : else if( c->scheme == COMPRESSION_JPEG )
7444 : {
7445 336 : bHasJPEG = TRUE;
7446 : strcat( szOptionalCompressItems,
7447 336 : " <Value>JPEG</Value>" );
7448 : }
7449 4704 : else if( c->scheme == COMPRESSION_LZW )
7450 : {
7451 336 : bHasLZW = TRUE;
7452 : strcat( szOptionalCompressItems,
7453 336 : " <Value>LZW</Value>" );
7454 : }
7455 4368 : else if( c->scheme == COMPRESSION_ADOBE_DEFLATE )
7456 : {
7457 336 : bHasDEFLATE = TRUE;
7458 : strcat( szOptionalCompressItems,
7459 336 : " <Value>DEFLATE</Value>" );
7460 : }
7461 4032 : else if( c->scheme == COMPRESSION_CCITTRLE )
7462 : strcat( szOptionalCompressItems,
7463 336 : " <Value>CCITTRLE</Value>" );
7464 3696 : else if( c->scheme == COMPRESSION_CCITTFAX3 )
7465 : strcat( szOptionalCompressItems,
7466 336 : " <Value>CCITTFAX3</Value>" );
7467 3360 : else if( c->scheme == COMPRESSION_CCITTFAX4 )
7468 : strcat( szOptionalCompressItems,
7469 336 : " <Value>CCITTFAX4</Value>" );
7470 : }
7471 336 : _TIFFfree( codecs );
7472 : #endif
7473 :
7474 : /* -------------------------------------------------------------------- */
7475 : /* Build full creation option list. */
7476 : /* -------------------------------------------------------------------- */
7477 : sprintf( szCreateOptions, "%s%s%s",
7478 : "<CreationOptionList>"
7479 : " <Option name='COMPRESS' type='string-select'>",
7480 : szOptionalCompressItems,
7481 336 : " </Option>");
7482 336 : if (bHasLZW || bHasDEFLATE)
7483 : strcat( szCreateOptions, ""
7484 336 : " <Option name='PREDICTOR' type='int' description='Predictor Type'/>");
7485 336 : if (bHasJPEG)
7486 : strcat( szCreateOptions, ""
7487 336 : " <Option name='JPEG_QUALITY' type='int' description='JPEG quality 1-100' default='75'/>");
7488 336 : if (bHasDEFLATE)
7489 : strcat( szCreateOptions, ""
7490 336 : " <Option name='ZLEVEL' type='int' description='DEFLATE compression level 1-9' default='6'/>");
7491 : strcat( szCreateOptions, ""
7492 : " <Option name='NBITS' type='int' description='BITS for sub-byte files (1-7), sub-uint16 (9-15), sub-uint32 (17-31)'/>"
7493 : " <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
7494 : " <Value>BAND</Value>"
7495 : " <Value>PIXEL</Value>"
7496 : " </Option>"
7497 : " <Option name='TILED' type='boolean' description='Switch to tiled format'/>"
7498 : " <Option name='TFW' type='boolean' description='Write out world file'/>"
7499 : " <Option name='RPB' type='boolean' description='Write out .RPB (RPC) file'/>"
7500 : " <Option name='BLOCKXSIZE' type='int' description='Tile Width'/>"
7501 : " <Option name='BLOCKYSIZE' type='int' description='Tile/Strip Height'/>"
7502 : " <Option name='PHOTOMETRIC' type='string-select'>"
7503 : " <Value>MINISBLACK</Value>"
7504 : " <Value>MINISWHITE</Value>"
7505 : " <Value>PALETTE</Value>"
7506 : " <Value>RGB</Value>"
7507 : " <Value>CMYK</Value>"
7508 : " <Value>YCBCR</Value>"
7509 : " <Value>CIELAB</Value>"
7510 : " <Value>ICCLAB</Value>"
7511 : " <Value>ITULAB</Value>"
7512 : " </Option>"
7513 : " <Option name='SPARSE_OK' type='boolean' description='Can newly created files have missing blocks?' default='FALSE'/>"
7514 : " <Option name='ALPHA' type='boolean' description='Mark first extrasample as being alpha'/>"
7515 : " <Option name='PROFILE' type='string-select' default='GDALGeoTIFF'>"
7516 : " <Value>GDALGeoTIFF</Value>"
7517 : " <Value>GeoTIFF</Value>"
7518 : " <Value>BASELINE</Value>"
7519 : " </Option>"
7520 : " <Option name='PIXELTYPE' type='string-select'>"
7521 : " <Value>DEFAULT</Value>"
7522 : " <Value>SIGNEDBYTE</Value>"
7523 : " </Option>"
7524 : #ifdef BIGTIFF_SUPPORT
7525 : " <Option name='BIGTIFF' type='string-select' description='Force creation of BigTIFF file'>"
7526 : " <Value>YES</Value>"
7527 : " <Value>NO</Value>"
7528 : " <Value>IF_NEEDED</Value>"
7529 : " <Value>IF_SAFER</Value>"
7530 : " </Option>"
7531 : #endif
7532 : " <Option name='ENDIANNESS' type='string-select' default='NATIVE' description='Force endianness of created file. For DEBUG purpose mostly'>"
7533 : " <Value>NATIVE</Value>"
7534 : " <Value>INVERTED</Value>"
7535 : " <Value>LITTLE</Value>"
7536 : " <Value>BIG</Value>"
7537 : " </Option>"
7538 336 : "</CreationOptionList>" );
7539 :
7540 : /* -------------------------------------------------------------------- */
7541 : /* Set the driver details. */
7542 : /* -------------------------------------------------------------------- */
7543 336 : poDriver->SetDescription( "GTiff" );
7544 336 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoTIFF" );
7545 336 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "frmt_gtiff.html" );
7546 336 : poDriver->SetMetadataItem( GDAL_DMD_MIMETYPE, "image/tiff" );
7547 336 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "tif" );
7548 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
7549 : "Byte UInt16 Int16 UInt32 Int32 Float32 "
7550 336 : "Float64 CInt16 CInt32 CFloat32 CFloat64" );
7551 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
7552 336 : szCreateOptions );
7553 :
7554 336 : poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
7555 :
7556 336 : poDriver->pfnOpen = GTiffDataset::Open;
7557 336 : poDriver->pfnCreate = GTiffDataset::Create;
7558 336 : poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
7559 336 : poDriver->pfnUnloadDriver = GDALDeregister_GTiff;
7560 336 : poDriver->pfnIdentify = GTiffDataset::Identify;
7561 :
7562 336 : GetGDALDriverManager()->RegisterDriver( poDriver );
7563 : }
7564 338 : }
|