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