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