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