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