1 : /******************************************************************************
2 : * $Id: gt_overview.cpp 18243 2009-12-10 17:01:50Z warmerdam $
3 : *
4 : * Project: GeoTIFF Driver
5 : * Purpose: Code to build overviews of external databases as a TIFF file.
6 : * Only used by the GDALDefaultOverviews::BuildOverviews() method.
7 : * Author: Frank Warmerdam, warmerdam@pobox.com
8 : *
9 : ******************************************************************************
10 : * Copyright (c) 2000, Frank Warmerdam
11 : *
12 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "gdal_priv.h"
32 : #define CPL_SERV_H_INCLUDED
33 :
34 : #include "tiffio.h"
35 : #include "xtiffio.h"
36 : #include "geotiff.h"
37 : #include "gt_overview.h"
38 :
39 : CPL_CVSID("$Id: gt_overview.cpp 18243 2009-12-10 17:01:50Z warmerdam $");
40 :
41 : #define TIFFTAG_GDAL_METADATA 42112
42 :
43 : CPL_C_START
44 : void GTiffOneTimeInit();
45 : CPL_C_END
46 :
47 : /************************************************************************/
48 : /* GTIFFWriteDirectory() */
49 : /* */
50 : /* Create a new directory, without any image data for an overview */
51 : /* or a mask */
52 : /* Returns offset of newly created directory, but the */
53 : /* current directory is reset to be the one in used when this */
54 : /* function is called. */
55 : /************************************************************************/
56 :
57 127 : toff_t GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize, int nYSize,
58 : int nBitsPerPixel, int nPlanarConfig, int nSamples,
59 : int nBlockXSize, int nBlockYSize,
60 : int bTiled, int nCompressFlag, int nPhotometric,
61 : int nSampleFormat,
62 : unsigned short *panRed,
63 : unsigned short *panGreen,
64 : unsigned short *panBlue,
65 : int nExtraSamples,
66 : unsigned short *panExtraSampleValues,
67 : const char *pszMetadata )
68 :
69 : {
70 : toff_t nBaseDirOffset;
71 : toff_t nOffset;
72 :
73 127 : nBaseDirOffset = TIFFCurrentDirOffset( hTIFF );
74 :
75 : #if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20051201 /* 3.8.0 */
76 127 : TIFFFreeDirectory( hTIFF );
77 : #endif
78 :
79 127 : TIFFCreateDirectory( hTIFF );
80 :
81 : /* -------------------------------------------------------------------- */
82 : /* Setup TIFF fields. */
83 : /* -------------------------------------------------------------------- */
84 127 : TIFFSetField( hTIFF, TIFFTAG_IMAGEWIDTH, nXSize );
85 127 : TIFFSetField( hTIFF, TIFFTAG_IMAGELENGTH, nYSize );
86 127 : if( nSamples == 1 )
87 83 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG );
88 : else
89 44 : TIFFSetField( hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig );
90 :
91 127 : TIFFSetField( hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel );
92 127 : TIFFSetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples );
93 127 : TIFFSetField( hTIFF, TIFFTAG_COMPRESSION, nCompressFlag );
94 127 : TIFFSetField( hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric );
95 127 : TIFFSetField( hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat );
96 :
97 127 : if( bTiled )
98 : {
99 122 : TIFFSetField( hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize );
100 122 : TIFFSetField( hTIFF, TIFFTAG_TILELENGTH, nBlockYSize );
101 : }
102 : else
103 5 : TIFFSetField( hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize );
104 :
105 127 : TIFFSetField( hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType );
106 :
107 127 : if (panExtraSampleValues != NULL)
108 : {
109 16 : TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples, panExtraSampleValues );
110 : }
111 :
112 : /* -------------------------------------------------------------------- */
113 : /* Write color table if one is present. */
114 : /* -------------------------------------------------------------------- */
115 127 : if( panRed != NULL )
116 : {
117 9 : TIFFSetField( hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue );
118 : }
119 :
120 : /* -------------------------------------------------------------------- */
121 : /* Write metadata if we have some. */
122 : /* -------------------------------------------------------------------- */
123 127 : if( pszMetadata && strlen(pszMetadata) > 0 )
124 12 : TIFFSetField( hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata );
125 :
126 : /* -------------------------------------------------------------------- */
127 : /* Write directory, and return byte offset. */
128 : /* -------------------------------------------------------------------- */
129 127 : if( TIFFWriteCheck( hTIFF, bTiled, "GTIFFWriteDirectory" ) == 0 )
130 : {
131 0 : TIFFSetSubDirectory( hTIFF, nBaseDirOffset );
132 0 : return 0;
133 : }
134 :
135 127 : TIFFWriteDirectory( hTIFF );
136 127 : TIFFSetDirectory( hTIFF, (tdir_t) (TIFFNumberOfDirectories(hTIFF)-1) );
137 :
138 127 : nOffset = TIFFCurrentDirOffset( hTIFF );
139 :
140 127 : TIFFSetSubDirectory( hTIFF, nBaseDirOffset );
141 :
142 127 : return nOffset;
143 : }
144 :
145 : /************************************************************************/
146 : /* GTIFFBuildOverviewMetadata() */
147 : /************************************************************************/
148 :
149 87 : void GTIFFBuildOverviewMetadata( const char *pszResampling,
150 : GDALDataset *poBaseDS,
151 : CPLString &osMetadata )
152 :
153 : {
154 87 : osMetadata = "<GDALMetadata>";
155 :
156 174 : if( pszResampling && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
157 2 : osMetadata += "<Item name=\"RESAMPLING\" sample=\"0\">AVERAGE_BIT2GRAYSCALE</Item>";
158 :
159 87 : if( poBaseDS->GetMetadataItem( "INTERNAL_MASK_FLAGS_1" ) )
160 : {
161 : int iBand;
162 :
163 201 : for( iBand = 0; iBand < 200; iBand++ )
164 : {
165 200 : CPLString osItem;
166 200 : CPLString osName;
167 :
168 200 : osName.Printf( "INTERNAL_MASK_FLAGS_%d", iBand+1 );
169 200 : if( poBaseDS->GetMetadataItem( osName ) )
170 : {
171 : osItem.Printf( "<Item name=\"%s\">%s</Item>",
172 : osName.c_str(),
173 3 : poBaseDS->GetMetadataItem( osName ) );
174 3 : osMetadata += osItem;
175 : }
176 : }
177 : }
178 :
179 87 : const char* pszNoDataValues = poBaseDS->GetMetadataItem("NODATA_VALUES");
180 87 : if (pszNoDataValues)
181 : {
182 6 : CPLString osItem;
183 6 : osItem.Printf( "<Item name=\"NODATA_VALUES\">%s</Item>", pszNoDataValues );
184 6 : osMetadata += osItem;
185 : }
186 :
187 87 : if( !EQUAL(osMetadata,"<GDALMetadata>") )
188 9 : osMetadata += "</GDALMetadata>";
189 : else
190 78 : osMetadata = "";
191 87 : }
192 :
193 : /************************************************************************/
194 : /* GTIFFBuildOverviews() */
195 : /************************************************************************/
196 :
197 : CPLErr
198 34 : GTIFFBuildOverviews( const char * pszFilename,
199 : int nBands, GDALRasterBand **papoBandList,
200 : int nOverviews, int * panOverviewList,
201 : const char * pszResampling,
202 : GDALProgressFunc pfnProgress, void * pProgressData )
203 :
204 : {
205 : TIFF *hOTIFF;
206 34 : int nBitsPerPixel=0, nCompression=COMPRESSION_NONE, nPhotometric=0;
207 34 : int nSampleFormat=0, nPlanarConfig, iOverview, iBand;
208 34 : int nXSize=0, nYSize=0;
209 :
210 34 : if( nBands == 0 || nOverviews == 0 )
211 0 : return CE_None;
212 :
213 34 : GTiffOneTimeInit();
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* Verify that the list of bands is suitable for emitting in */
217 : /* TIFF file. */
218 : /* -------------------------------------------------------------------- */
219 91 : for( iBand = 0; iBand < nBands; iBand++ )
220 : {
221 : int nBandBits, nBandFormat;
222 57 : GDALRasterBand *hBand = papoBandList[iBand];
223 :
224 57 : switch( hBand->GetRasterDataType() )
225 : {
226 : case GDT_Byte:
227 35 : nBandBits = 8;
228 35 : nBandFormat = SAMPLEFORMAT_UINT;
229 35 : break;
230 :
231 : case GDT_UInt16:
232 0 : nBandBits = 16;
233 0 : nBandFormat = SAMPLEFORMAT_UINT;
234 0 : break;
235 :
236 : case GDT_Int16:
237 0 : nBandBits = 16;
238 0 : nBandFormat = SAMPLEFORMAT_INT;
239 0 : break;
240 :
241 : case GDT_UInt32:
242 0 : nBandBits = 32;
243 0 : nBandFormat = SAMPLEFORMAT_UINT;
244 0 : break;
245 :
246 : case GDT_Int32:
247 1 : nBandBits = 32;
248 1 : nBandFormat = SAMPLEFORMAT_INT;
249 1 : break;
250 :
251 : case GDT_Float32:
252 21 : nBandBits = 32;
253 21 : nBandFormat = SAMPLEFORMAT_IEEEFP;
254 21 : break;
255 :
256 : case GDT_Float64:
257 0 : nBandBits = 64;
258 0 : nBandFormat = SAMPLEFORMAT_IEEEFP;
259 0 : break;
260 :
261 : case GDT_CInt16:
262 0 : nBandBits = 32;
263 0 : nBandFormat = SAMPLEFORMAT_COMPLEXINT;
264 0 : break;
265 :
266 : case GDT_CInt32:
267 0 : nBandBits = 64;
268 0 : nBandFormat = SAMPLEFORMAT_COMPLEXINT;
269 0 : break;
270 :
271 : case GDT_CFloat32:
272 0 : nBandBits = 64;
273 0 : nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
274 0 : break;
275 :
276 : case GDT_CFloat64:
277 0 : nBandBits = 128;
278 0 : nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
279 0 : break;
280 :
281 : default:
282 : CPLAssert( FALSE );
283 0 : return CE_Failure;
284 : }
285 :
286 57 : if( hBand->GetMetadataItem( "NBITS", "IMAGE_STRUCTURE" ) )
287 : {
288 : nBandBits =
289 0 : atoi(hBand->GetMetadataItem("NBITS","IMAGE_STRUCTURE"));
290 :
291 0 : if( nBandBits == 1
292 : && EQUALN(pszResampling,"AVERAGE_BIT2",12) )
293 0 : nBandBits = 8;
294 : }
295 :
296 57 : if( iBand == 0 )
297 : {
298 34 : nBitsPerPixel = nBandBits;
299 34 : nSampleFormat = nBandFormat;
300 34 : nXSize = hBand->GetXSize();
301 34 : nYSize = hBand->GetYSize();
302 : }
303 23 : else if( nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat )
304 : {
305 : CPLError( CE_Failure, CPLE_NotSupported,
306 : "GTIFFBuildOverviews() doesn't support a mixture of band"
307 0 : " data types." );
308 0 : return CE_Failure;
309 : }
310 23 : else if( hBand->GetColorTable() != NULL )
311 : {
312 : CPLError( CE_Failure, CPLE_NotSupported,
313 : "GTIFFBuildOverviews() doesn't support building"
314 0 : " overviews of multiple colormapped bands." );
315 0 : return CE_Failure;
316 : }
317 23 : else if( hBand->GetXSize() != nXSize
318 : || hBand->GetYSize() != nYSize )
319 : {
320 : CPLError( CE_Failure, CPLE_NotSupported,
321 : "GTIFFBuildOverviews() doesn't support building"
322 0 : " overviews of different sized bands." );
323 0 : return CE_Failure;
324 : }
325 : }
326 :
327 : /* -------------------------------------------------------------------- */
328 : /* Use specified compression method. */
329 : /* -------------------------------------------------------------------- */
330 34 : const char *pszCompress = CPLGetConfigOption( "COMPRESS_OVERVIEW", NULL );
331 :
332 34 : if( pszCompress != NULL && pszCompress[0] != '\0' )
333 : {
334 4 : if( EQUAL( pszCompress, "JPEG" ) )
335 2 : nCompression = COMPRESSION_JPEG;
336 2 : else if( EQUAL( pszCompress, "LZW" ) )
337 0 : nCompression = COMPRESSION_LZW;
338 2 : else if( EQUAL( pszCompress, "PACKBITS" ))
339 0 : nCompression = COMPRESSION_PACKBITS;
340 4 : else if( EQUAL( pszCompress, "DEFLATE" ) || EQUAL( pszCompress, "ZIP" ))
341 2 : nCompression = COMPRESSION_ADOBE_DEFLATE;
342 : else
343 : CPLError( CE_Warning, CPLE_IllegalArg,
344 : "COMPRESS_OVERVIEW=%s value not recognised, ignoring.",
345 0 : pszCompress );
346 : }
347 :
348 : /* -------------------------------------------------------------------- */
349 : /* Figure out the planar configuration to use. */
350 : /* -------------------------------------------------------------------- */
351 34 : if( nBands == 1 )
352 23 : nPlanarConfig = PLANARCONFIG_CONTIG;
353 : else
354 11 : nPlanarConfig = PLANARCONFIG_SEPARATE;
355 :
356 34 : const char* pszInterleave = CPLGetConfigOption( "INTERLEAVE_OVERVIEW", NULL );
357 34 : if (pszInterleave != NULL && pszInterleave[0] != '\0')
358 : {
359 0 : if( EQUAL( pszInterleave, "PIXEL" ) )
360 0 : nPlanarConfig = PLANARCONFIG_CONTIG;
361 0 : else if( EQUAL( pszInterleave, "BAND" ) )
362 0 : nPlanarConfig = PLANARCONFIG_SEPARATE;
363 : else
364 : {
365 : CPLError( CE_Failure, CPLE_AppDefined,
366 : "INTERLEAVE_OVERVIEW=%s unsupported, value must be PIXEL or BAND. ignoring",
367 0 : pszInterleave );
368 : }
369 : }
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Figure out the photometric interpretation to use. */
373 : /* -------------------------------------------------------------------- */
374 34 : if( nBands == 3 )
375 10 : nPhotometric = PHOTOMETRIC_RGB;
376 24 : else if( papoBandList[0]->GetColorTable() != NULL
377 : && !EQUALN(pszResampling,"AVERAGE_BIT2",12) )
378 : {
379 0 : nPhotometric = PHOTOMETRIC_PALETTE;
380 : /* should set the colormap up at this point too! */
381 : }
382 : else
383 24 : nPhotometric = PHOTOMETRIC_MINISBLACK;
384 :
385 34 : const char* pszPhotometric = CPLGetConfigOption( "PHOTOMETRIC_OVERVIEW", NULL );
386 34 : if (pszPhotometric != NULL && pszPhotometric[0] != '\0')
387 : {
388 2 : if( EQUAL( pszPhotometric, "MINISBLACK" ) )
389 0 : nPhotometric = PHOTOMETRIC_MINISBLACK;
390 2 : else if( EQUAL( pszPhotometric, "MINISWHITE" ) )
391 0 : nPhotometric = PHOTOMETRIC_MINISWHITE;
392 2 : else if( EQUAL( pszPhotometric, "RGB" ))
393 : {
394 0 : nPhotometric = PHOTOMETRIC_RGB;
395 : }
396 2 : else if( EQUAL( pszPhotometric, "CMYK" ))
397 : {
398 0 : nPhotometric = PHOTOMETRIC_SEPARATED;
399 : }
400 2 : else if( EQUAL( pszPhotometric, "YCBCR" ))
401 : {
402 2 : nPhotometric = PHOTOMETRIC_YCBCR;
403 :
404 : /* Because of subsampling, setting YCBCR without JPEG compression leads */
405 : /* to a crash currently. Would need to make GTiffRasterBand::IWriteBlock() */
406 : /* aware of subsampling so that it doesn't overrun buffer size returned */
407 : /* by libtiff */
408 2 : if ( nCompression != COMPRESSION_JPEG )
409 : {
410 : CPLError(CE_Failure, CPLE_NotSupported,
411 0 : "Currently, PHOTOMETRIC_OVERVIEW=YCBCR requires COMPRESS_OVERVIEW=JPEG");
412 0 : return CE_Failure;
413 : }
414 :
415 2 : if (pszInterleave != NULL && pszInterleave[0] != '\0' && nPlanarConfig == PLANARCONFIG_SEPARATE)
416 : {
417 : CPLError(CE_Failure, CPLE_NotSupported,
418 0 : "PHOTOMETRIC_OVERVIEW=YCBCR requires INTERLEAVE_OVERVIEW=PIXEL");
419 0 : return CE_Failure;
420 : }
421 : else
422 : {
423 2 : nPlanarConfig = PLANARCONFIG_CONTIG;
424 : }
425 :
426 : /* YCBCR strictly requires 3 bands. Not less, not more */
427 : /* Issue an explicit error message as libtiff one is a bit cryptic : */
428 : /* JPEGLib:Bogus input colorspace */
429 2 : if ( nBands != 3 )
430 : {
431 : CPLError(CE_Failure, CPLE_NotSupported,
432 0 : "PHOTOMETRIC_OVERVIEW=YCBCR requires a source raster with only 3 bands (RGB)");
433 0 : return CE_Failure;
434 : }
435 : }
436 0 : else if( EQUAL( pszPhotometric, "CIELAB" ))
437 : {
438 0 : nPhotometric = PHOTOMETRIC_CIELAB;
439 : }
440 0 : else if( EQUAL( pszPhotometric, "ICCLAB" ))
441 : {
442 0 : nPhotometric = PHOTOMETRIC_ICCLAB;
443 : }
444 0 : else if( EQUAL( pszPhotometric, "ITULAB" ))
445 : {
446 0 : nPhotometric = PHOTOMETRIC_ITULAB;
447 : }
448 : else
449 : {
450 : CPLError( CE_Warning, CPLE_IllegalArg,
451 : "PHOTOMETRIC_OVERVIEW=%s value not recognised, ignoring.\n",
452 0 : pszPhotometric );
453 : }
454 : }
455 :
456 : /* -------------------------------------------------------------------- */
457 : /* Create the file, if it does not already exist. */
458 : /* -------------------------------------------------------------------- */
459 : VSIStatBufL sStatBuf;
460 :
461 34 : if( VSIStatL( pszFilename, &sStatBuf ) != 0 )
462 : {
463 : /* -------------------------------------------------------------------- */
464 : /* Compute the uncompressed size. */
465 : /* -------------------------------------------------------------------- */
466 34 : double dfUncompressedOverviewSize = 0;
467 34 : int nDataTypeSize = GDALGetDataTypeSize(papoBandList[0]->GetRasterDataType())/8;
468 :
469 83 : for( iOverview = 0; iOverview < nOverviews; iOverview++ )
470 : {
471 : int nOXSize, nOYSize;
472 :
473 49 : nOXSize = (nXSize + panOverviewList[iOverview] - 1)
474 49 : / panOverviewList[iOverview];
475 49 : nOYSize = (nYSize + panOverviewList[iOverview] - 1)
476 49 : / panOverviewList[iOverview];
477 :
478 : dfUncompressedOverviewSize +=
479 49 : nOXSize * ((double)nOYSize) * nBands * nDataTypeSize;
480 : }
481 :
482 34 : if( nCompression == COMPRESSION_NONE
483 : && dfUncompressedOverviewSize > 4200000000.0 )
484 : {
485 : #ifndef BIGTIFF_SUPPORT
486 : CPLError( CE_Failure, CPLE_NotSupported,
487 : "The overview file would be larger than 4GB\n"
488 : "but this is the largest size a TIFF can be, and BigTIFF is unavailable.\n"
489 : "Creation failed." );
490 : return CE_Failure;
491 : #endif
492 : }
493 : /* -------------------------------------------------------------------- */
494 : /* Should the file be created as a bigtiff file? */
495 : /* -------------------------------------------------------------------- */
496 34 : const char *pszBIGTIFF = CPLGetConfigOption( "BIGTIFF_OVERVIEW", NULL );
497 :
498 34 : if( pszBIGTIFF == NULL )
499 9 : pszBIGTIFF = "IF_NEEDED";
500 :
501 34 : int bCreateBigTIFF = FALSE;
502 34 : if( EQUAL(pszBIGTIFF,"IF_NEEDED") )
503 : {
504 26 : if( nCompression == COMPRESSION_NONE
505 : && dfUncompressedOverviewSize > 4200000000.0 )
506 2 : bCreateBigTIFF = TRUE;
507 : }
508 8 : else if( EQUAL(pszBIGTIFF,"IF_SAFER") )
509 : {
510 : /* Look at the size of the base image and suppose that */
511 : /* the added overview levels won't be more than 1/2 of */
512 : /* the size of the base image. The theory says 1/3 of the */
513 : /* base image size if the overview levels are 2, 4, 8, 16... */
514 : /* Thus take 1/2 as the security margin for 1/3 */
515 : double dfUncompressedImageSize =
516 2 : nXSize * ((double)nYSize) * nBands * nDataTypeSize;
517 2 : if( dfUncompressedImageSize * .5 > 4200000000.0 )
518 2 : bCreateBigTIFF = TRUE;
519 : }
520 : else
521 : {
522 6 : bCreateBigTIFF = CSLTestBoolean( pszBIGTIFF );
523 6 : if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE
524 : && dfUncompressedOverviewSize > 4200000000.0 )
525 : {
526 : CPLError( CE_Failure, CPLE_NotSupported,
527 : "The overview file will be larger than 4GB, so BigTIFF is necessary.\n"
528 2 : "Creation failed.");
529 2 : return CE_Failure;
530 : }
531 : }
532 :
533 : #ifndef BIGTIFF_SUPPORT
534 : if( bCreateBigTIFF )
535 : {
536 : CPLError( CE_Warning, CPLE_NotSupported,
537 : "BigTIFF requested, but GDAL built without BigTIFF\n"
538 : "enabled libtiff, request ignored." );
539 : bCreateBigTIFF = FALSE;
540 : }
541 : #endif
542 :
543 32 : if( bCreateBigTIFF )
544 6 : CPLDebug( "GTiff", "File being created as a BigTIFF." );
545 :
546 32 : hOTIFF = XTIFFOpen( pszFilename, (bCreateBigTIFF) ? "w+8" : "w+" );
547 32 : if( hOTIFF == NULL )
548 : {
549 0 : if( CPLGetLastErrorNo() == 0 )
550 : CPLError( CE_Failure, CPLE_OpenFailed,
551 : "Attempt to create new tiff file `%s'\n"
552 : "failed in XTIFFOpen().\n",
553 0 : pszFilename );
554 :
555 0 : return CE_Failure;
556 : }
557 : }
558 : /* -------------------------------------------------------------------- */
559 : /* Otherwise just open it for update access. */
560 : /* -------------------------------------------------------------------- */
561 : else
562 : {
563 0 : hOTIFF = XTIFFOpen( pszFilename, "r+" );
564 0 : if( hOTIFF == NULL )
565 : {
566 0 : if( CPLGetLastErrorNo() == 0 )
567 : CPLError( CE_Failure, CPLE_OpenFailed,
568 : "Attempt to create new tiff file `%s'\n"
569 : "failed in XTIFFOpen().\n",
570 0 : pszFilename );
571 :
572 0 : return CE_Failure;
573 : }
574 : }
575 :
576 : /* -------------------------------------------------------------------- */
577 : /* Do we have a palette? If so, create a TIFF compatible version. */
578 : /* -------------------------------------------------------------------- */
579 32 : unsigned short *panRed=NULL, *panGreen=NULL, *panBlue=NULL;
580 :
581 32 : if( nPhotometric == PHOTOMETRIC_PALETTE )
582 : {
583 0 : GDALColorTable *poCT = papoBandList[0]->GetColorTable();
584 : int nColorCount;
585 :
586 0 : if( nBitsPerPixel <= 8 )
587 0 : nColorCount = 256;
588 : else
589 0 : nColorCount = 65536;
590 :
591 : panRed = (unsigned short *)
592 0 : CPLCalloc(nColorCount,sizeof(unsigned short));
593 : panGreen = (unsigned short *)
594 0 : CPLCalloc(nColorCount,sizeof(unsigned short));
595 : panBlue = (unsigned short *)
596 0 : CPLCalloc(nColorCount,sizeof(unsigned short));
597 :
598 0 : for( int iColor = 0; iColor < nColorCount; iColor++ )
599 : {
600 : GDALColorEntry sRGB;
601 :
602 0 : if( poCT->GetColorEntryAsRGB( iColor, &sRGB ) )
603 : {
604 0 : panRed[iColor] = (unsigned short) (257 * sRGB.c1);
605 0 : panGreen[iColor] = (unsigned short) (257 * sRGB.c2);
606 0 : panBlue[iColor] = (unsigned short) (257 * sRGB.c3);
607 : }
608 : }
609 : }
610 :
611 : /* -------------------------------------------------------------------- */
612 : /* Do we need some metadata for the overviews? */
613 : /* -------------------------------------------------------------------- */
614 32 : CPLString osMetadata;
615 32 : GDALDataset *poBaseDS = papoBandList[0]->GetDataset();
616 :
617 32 : GTIFFBuildOverviewMetadata( pszResampling, poBaseDS, osMetadata );
618 :
619 : /* -------------------------------------------------------------------- */
620 : /* Loop, creating overviews. */
621 : /* -------------------------------------------------------------------- */
622 79 : for( iOverview = 0; iOverview < nOverviews; iOverview++ )
623 : {
624 : int nOXSize, nOYSize;
625 :
626 47 : nOXSize = (nXSize + panOverviewList[iOverview] - 1)
627 47 : / panOverviewList[iOverview];
628 47 : nOYSize = (nYSize + panOverviewList[iOverview] - 1)
629 47 : / panOverviewList[iOverview];
630 :
631 : GTIFFWriteDirectory(hOTIFF, FILETYPE_REDUCEDIMAGE,
632 : nOXSize, nOYSize, nBitsPerPixel,
633 : nPlanarConfig, nBands,
634 : 128, 128, TRUE, nCompression,
635 : nPhotometric, nSampleFormat,
636 : panRed, panGreen, panBlue,
637 : 0, NULL, /* FIXME? how can we fetch extrasamples */
638 47 : osMetadata );
639 : }
640 :
641 32 : if (panRed)
642 : {
643 0 : CPLFree(panRed);
644 0 : CPLFree(panGreen);
645 0 : CPLFree(panBlue);
646 0 : panRed = panGreen = panBlue = NULL;
647 : }
648 :
649 32 : XTIFFClose( hOTIFF );
650 :
651 : /* -------------------------------------------------------------------- */
652 : /* Open the overview dataset so that we can get at the overview */
653 : /* bands. */
654 : /* -------------------------------------------------------------------- */
655 : GDALDataset *hODS;
656 32 : CPLErr eErr = CE_None;
657 :
658 32 : hODS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
659 32 : if( hODS == NULL )
660 0 : return CE_Failure;
661 :
662 : /* -------------------------------------------------------------------- */
663 : /* Do we need to set the jpeg quality? */
664 : /* -------------------------------------------------------------------- */
665 32 : TIFF *hTIFF = (TIFF*) hODS->GetInternalHandle(NULL);
666 :
667 32 : if( nCompression == COMPRESSION_JPEG
668 : && CPLGetConfigOption( "JPEG_QUALITY_OVERVIEW", NULL ) != NULL )
669 : {
670 : TIFFSetField( hTIFF, TIFFTAG_JPEGQUALITY,
671 0 : atoi(CPLGetConfigOption("JPEG_QUALITY_OVERVIEW","75")) );
672 : }
673 :
674 : /* -------------------------------------------------------------------- */
675 : /* Loop writing overview data. */
676 : /* -------------------------------------------------------------------- */
677 :
678 40 : if (nCompression != COMPRESSION_NONE &&
679 : nPlanarConfig == PLANARCONFIG_CONTIG &&
680 4 : GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) == FALSE &&
681 4 : papoBandList[0]->GetColorTable() == NULL &&
682 : (EQUALN(pszResampling, "NEAR", 4) || EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "GAUSS")))
683 : {
684 : /* In the case of pixel interleaved compressed overviews, we want to generate */
685 : /* the overviews for all the bands block by block, and not band after band, */
686 : /* in order to write the block once and not loose space in the TIFF file */
687 : GDALRasterBand ***papapoOverviewBands;
688 :
689 2 : papapoOverviewBands = (GDALRasterBand ***) CPLCalloc(sizeof(void*),nBands);
690 8 : for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
691 : {
692 6 : GDALRasterBand *hDstBand = hODS->GetRasterBand( iBand+1 );
693 6 : papapoOverviewBands[iBand] = (GDALRasterBand **) CPLCalloc(sizeof(void*),nOverviews);
694 6 : papapoOverviewBands[iBand][0] = hDstBand;
695 6 : for( int i = 0; i < nOverviews-1 && eErr == CE_None; i++ )
696 : {
697 0 : papapoOverviewBands[iBand][i+1] = hDstBand->GetOverview(i);
698 0 : if (papapoOverviewBands[iBand][i+1] == NULL)
699 0 : eErr = CE_Failure;
700 : }
701 : }
702 :
703 2 : if (eErr == CE_None)
704 : eErr = GDALRegenerateOverviewsMultiBand(nBands, papoBandList,
705 : nOverviews, papapoOverviewBands,
706 2 : pszResampling, pfnProgress, pProgressData );
707 :
708 8 : for( iBand = 0; iBand < nBands; iBand++ )
709 : {
710 6 : CPLFree(papapoOverviewBands[iBand]);
711 : }
712 2 : CPLFree(papapoOverviewBands);
713 : }
714 : else
715 : {
716 : GDALRasterBand **papoOverviews;
717 :
718 30 : papoOverviews = (GDALRasterBand **) CPLCalloc(sizeof(void*),128);
719 :
720 79 : for( iBand = 0; iBand < nBands && eErr == CE_None; iBand++ )
721 : {
722 49 : GDALRasterBand *hSrcBand = papoBandList[iBand];
723 : GDALRasterBand *hDstBand;
724 : int nDstOverviews;
725 :
726 49 : hDstBand = hODS->GetRasterBand( iBand+1 );
727 :
728 49 : papoOverviews[0] = hDstBand;
729 49 : nDstOverviews = hDstBand->GetOverviewCount() + 1;
730 : CPLAssert( nDstOverviews < 128 );
731 49 : nDstOverviews = MIN(128,nDstOverviews);
732 :
733 83 : for( int i = 0; i < nDstOverviews-1 && eErr == CE_None; i++ )
734 : {
735 34 : papoOverviews[i+1] = hDstBand->GetOverview(i);
736 34 : if (papoOverviews[i+1] == NULL)
737 0 : eErr = CE_Failure;
738 : }
739 :
740 : void *pScaledProgressData;
741 :
742 : pScaledProgressData =
743 : GDALCreateScaledProgress( iBand / (double) nBands,
744 : (iBand+1) / (double) nBands,
745 49 : pfnProgress, pProgressData );
746 :
747 49 : if (eErr == CE_None)
748 : eErr =
749 : GDALRegenerateOverviews( (GDALRasterBandH) hSrcBand,
750 : nDstOverviews,
751 : (GDALRasterBandH *) papoOverviews,
752 : pszResampling,
753 : GDALScaledProgress,
754 49 : pScaledProgressData);
755 :
756 49 : GDALDestroyScaledProgress( pScaledProgressData );
757 : }
758 :
759 30 : CPLFree( papoOverviews );
760 : }
761 :
762 : /* -------------------------------------------------------------------- */
763 : /* Cleanup */
764 : /* -------------------------------------------------------------------- */
765 32 : if (eErr == CE_None)
766 32 : hODS->FlushCache();
767 32 : delete hODS;
768 :
769 32 : pfnProgress( 1.0, NULL, pProgressData );
770 :
771 32 : return eErr;
772 : }
773 :
|