LCOV - code coverage report
Current view: top level - frmts/gtiff - gt_overview.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 528 595 88.7 %
Date: 2025-05-31 00:00:17 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  Code to build overviews of external databases as a TIFF file.
       5             :  *           Only used by the GDALDefaultOverviews::BuildOverviews() method.
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2000, Frank Warmerdam
      10             :  * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * SPDX-License-Identifier: MIT
      13             :  ****************************************************************************/
      14             : 
      15             : #include "cpl_port.h"
      16             : 
      17             : #include "gt_overview.h"
      18             : 
      19             : #include <cstdlib>
      20             : #include <cstring>
      21             : 
      22             : #include <algorithm>
      23             : #include <string>
      24             : 
      25             : #include "cpl_conv.h"
      26             : #include "cpl_error.h"
      27             : #include "cpl_progress.h"
      28             : #include "cpl_string.h"
      29             : #include "cpl_vsi.h"
      30             : #include "gdal.h"
      31             : #include "gdal_priv.h"
      32             : #include "gtiff.h"
      33             : #include "gtiffdataset.h"
      34             : #include "tiff.h"
      35             : #include "tiffvers.h"
      36             : #include "tifvsi.h"
      37             : #include "tif_jxl.h"
      38             : #include "xtiffio.h"
      39             : 
      40             : // TODO(schwehr): Explain why 128 and not 127.
      41             : constexpr int knMaxOverviews = 128;
      42             : 
      43             : /************************************************************************/
      44             : /*                         GTIFFWriteDirectory()                        */
      45             : /*                                                                      */
      46             : /*      Create a new directory, without any image data for an overview  */
      47             : /*      or a mask                                                       */
      48             : /*      Returns offset of newly created directory, but the              */
      49             : /*      current directory is reset to be the one in used when this      */
      50             : /*      function is called.                                             */
      51             : /************************************************************************/
      52             : 
      53         991 : toff_t GTIFFWriteDirectory(TIFF *hTIFF, int nSubfileType, int nXSize,
      54             :                            int nYSize, int nBitsPerPixel, int nPlanarConfig,
      55             :                            int nSamples, int nBlockXSize, int nBlockYSize,
      56             :                            int bTiled, int nCompressFlag, int nPhotometric,
      57             :                            int nSampleFormat, int nPredictor,
      58             :                            unsigned short *panRed, unsigned short *panGreen,
      59             :                            unsigned short *panBlue, int nExtraSamples,
      60             :                            unsigned short *panExtraSampleValues,
      61             :                            const char *pszMetadata, const char *pszJPEGQuality,
      62             :                            const char *pszJPEGTablesMode, const char *pszNoData,
      63             :                            const uint32_t *panLercAddCompressionAndVersion,
      64             :                            bool bDeferStrileArrayWriting)
      65             : 
      66             : {
      67         991 :     const toff_t nBaseDirOffset = TIFFCurrentDirOffset(hTIFF);
      68             : 
      69             : #if !(defined(INTERNAL_LIBTIFF) || TIFFLIB_VERSION > 20240911)
      70             :     // This is a bit of a hack to cause (*tif->tif_cleanup)(tif); to be
      71             :     // called. See https://trac.osgeo.org/gdal/ticket/2055
      72             :     // Fixed in libtiff > 4.7.0
      73             :     TIFFSetField(hTIFF, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
      74             :     TIFFFreeDirectory(hTIFF);
      75             : #endif
      76             : 
      77         991 :     TIFFCreateDirectory(hTIFF);
      78             : 
      79             :     /* -------------------------------------------------------------------- */
      80             :     /*      Setup TIFF fields.                                              */
      81             :     /* -------------------------------------------------------------------- */
      82         991 :     TIFFSetField(hTIFF, TIFFTAG_IMAGEWIDTH, nXSize);
      83         991 :     TIFFSetField(hTIFF, TIFFTAG_IMAGELENGTH, nYSize);
      84         991 :     if (nSamples == 1)
      85         616 :         TIFFSetField(hTIFF, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
      86             :     else
      87         375 :         TIFFSetField(hTIFF, TIFFTAG_PLANARCONFIG, nPlanarConfig);
      88             : 
      89         991 :     TIFFSetField(hTIFF, TIFFTAG_BITSPERSAMPLE, nBitsPerPixel);
      90         991 :     TIFFSetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, nSamples);
      91         991 :     TIFFSetField(hTIFF, TIFFTAG_COMPRESSION, nCompressFlag);
      92         991 :     TIFFSetField(hTIFF, TIFFTAG_PHOTOMETRIC, nPhotometric);
      93         991 :     TIFFSetField(hTIFF, TIFFTAG_SAMPLEFORMAT, nSampleFormat);
      94             : 
      95         991 :     if (bTiled)
      96             :     {
      97         947 :         TIFFSetField(hTIFF, TIFFTAG_TILEWIDTH, nBlockXSize);
      98         947 :         TIFFSetField(hTIFF, TIFFTAG_TILELENGTH, nBlockYSize);
      99             :     }
     100             :     else
     101             :     {
     102          44 :         TIFFSetField(hTIFF, TIFFTAG_ROWSPERSTRIP, nBlockYSize);
     103             :     }
     104             : 
     105         991 :     TIFFSetField(hTIFF, TIFFTAG_SUBFILETYPE, nSubfileType);
     106             : 
     107         991 :     if (panExtraSampleValues != nullptr)
     108             :     {
     109         115 :         TIFFSetField(hTIFF, TIFFTAG_EXTRASAMPLES, nExtraSamples,
     110             :                      panExtraSampleValues);
     111             :     }
     112             : 
     113         991 :     if (GTIFFSupportsPredictor(nCompressFlag))
     114         404 :         TIFFSetField(hTIFF, TIFFTAG_PREDICTOR, nPredictor);
     115             : 
     116             :     /* -------------------------------------------------------------------- */
     117             :     /*      Write color table if one is present.                            */
     118             :     /* -------------------------------------------------------------------- */
     119         991 :     if (panRed != nullptr)
     120             :     {
     121          18 :         TIFFSetField(hTIFF, TIFFTAG_COLORMAP, panRed, panGreen, panBlue);
     122             :     }
     123             : 
     124             :     /* -------------------------------------------------------------------- */
     125             :     /*      Write metadata if we have some.                                 */
     126             :     /* -------------------------------------------------------------------- */
     127         991 :     if (pszMetadata && strlen(pszMetadata) > 0)
     128         668 :         TIFFSetField(hTIFF, TIFFTAG_GDAL_METADATA, pszMetadata);
     129             : 
     130             :     /* -------------------------------------------------------------------- */
     131             :     /*      Write JPEG tables if needed.                                    */
     132             :     /* -------------------------------------------------------------------- */
     133         991 :     if (nCompressFlag == COMPRESSION_JPEG)
     134             :     {
     135         113 :         GTiffWriteJPEGTables(hTIFF,
     136             :                              (nPhotometric == PHOTOMETRIC_RGB) ? "RGB"
     137             :                              : (nPhotometric == PHOTOMETRIC_YCBCR)
     138          54 :                                  ? "YCBCR"
     139             :                                  : "MINISBLACK",
     140             :                              pszJPEGQuality, pszJPEGTablesMode);
     141             : 
     142          59 :         if (nPhotometric == PHOTOMETRIC_YCBCR)
     143             :         {
     144             :             // Explicitly register the subsampling so that JPEGFixupTags
     145             :             // is a no-op (helps for cloud optimized geotiffs)
     146          46 :             TIFFSetField(hTIFF, TIFFTAG_YCBCRSUBSAMPLING, 2, 2);
     147             :         }
     148             :     }
     149             : 
     150         991 :     if (nCompressFlag == COMPRESSION_LERC && panLercAddCompressionAndVersion)
     151             :     {
     152          48 :         TIFFSetField(hTIFF, TIFFTAG_LERC_PARAMETERS, 2,
     153             :                      panLercAddCompressionAndVersion);
     154             :     }
     155             : 
     156             :     /* -------------------------------------------------------------------- */
     157             :     /*      Write no data value if we have one.                             */
     158             :     /* -------------------------------------------------------------------- */
     159         991 :     if (pszNoData != nullptr)
     160             :     {
     161          41 :         TIFFSetField(hTIFF, TIFFTAG_GDAL_NODATA, pszNoData);
     162             :     }
     163             : 
     164         991 :     if (bDeferStrileArrayWriting)
     165             :     {
     166         188 :         TIFFDeferStrileArrayWriting(hTIFF);
     167             :     }
     168             : 
     169             :     /* -------------------------------------------------------------------- */
     170             :     /*      Write directory, and return byte offset.                        */
     171             :     /* -------------------------------------------------------------------- */
     172         991 :     if (TIFFWriteCheck(hTIFF, bTiled, "GTIFFWriteDirectory") == 0)
     173             :     {
     174           0 :         TIFFSetSubDirectory(hTIFF, nBaseDirOffset);
     175           0 :         return 0;
     176             :     }
     177             : 
     178         991 :     TIFFWriteDirectory(hTIFF);
     179         991 :     const tdir_t nNumberOfDirs = TIFFNumberOfDirectories(hTIFF);
     180         991 :     if (nNumberOfDirs > 0)  // always true, but to please Coverity
     181             :     {
     182         991 :         TIFFSetDirectory(hTIFF, static_cast<tdir_t>(nNumberOfDirs - 1));
     183             :     }
     184             : 
     185         991 :     const toff_t nOffset = TIFFCurrentDirOffset(hTIFF);
     186             : 
     187         991 :     TIFFSetSubDirectory(hTIFF, nBaseDirOffset);
     188             : 
     189         991 :     return nOffset;
     190             : }
     191             : 
     192             : /************************************************************************/
     193             : /*                     GTIFFBuildOverviewMetadata()                     */
     194             : /************************************************************************/
     195             : 
     196         539 : void GTIFFBuildOverviewMetadata(const char *pszResampling,
     197             :                                 GDALDataset *poBaseDS, bool bIsForMaskBand,
     198             :                                 CPLString &osMetadata)
     199             : 
     200             : {
     201         539 :     osMetadata = "<GDALMetadata>";
     202             : 
     203        1078 :     auto osNormalizedResampling = GDALGetNormalizedOvrResampling(pszResampling);
     204         539 :     if (!osNormalizedResampling.empty())
     205             :     {
     206         444 :         osMetadata += "<Item name=\"RESAMPLING\" sample=\"0\">";
     207         444 :         osMetadata += osNormalizedResampling;
     208         444 :         osMetadata += "</Item>";
     209             :     }
     210             : 
     211         539 :     if (bIsForMaskBand)
     212             :     {
     213          11 :         osMetadata += "<Item name=\"INTERNAL_MASK_FLAGS_1\">2</Item>";
     214             :     }
     215         528 :     else if (poBaseDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1"))
     216             :     {
     217           0 :         for (int iBand = 0; iBand < 200; iBand++)
     218             :         {
     219           0 :             CPLString osItem;
     220           0 :             CPLString osName;
     221             : 
     222           0 :             osName.Printf("INTERNAL_MASK_FLAGS_%d", iBand + 1);
     223           0 :             if (poBaseDS->GetMetadataItem(osName))
     224             :             {
     225             :                 osItem.Printf("<Item name=\"%s\">%s</Item>", osName.c_str(),
     226           0 :                               poBaseDS->GetMetadataItem(osName));
     227           0 :                 osMetadata += osItem;
     228             :             }
     229             :         }
     230             :     }
     231             : 
     232         539 :     const char *pszNoDataValues = poBaseDS->GetMetadataItem("NODATA_VALUES");
     233         539 :     if (pszNoDataValues)
     234             :     {
     235          12 :         CPLString osItem;
     236             :         osItem.Printf("<Item name=\"NODATA_VALUES\">%s</Item>",
     237           6 :                       pszNoDataValues);
     238           6 :         osMetadata += osItem;
     239             :     }
     240             : 
     241         539 :     if (!EQUAL(osMetadata, "<GDALMetadata>"))
     242         444 :         osMetadata += "</GDALMetadata>";
     243             :     else
     244          95 :         osMetadata = "";
     245         539 : }
     246             : 
     247             : /************************************************************************/
     248             : /*                      GTIFFGetMaxColorChannels()                      */
     249             : /************************************************************************/
     250             : 
     251             : /*
     252             :  * Return the maximum number of color channels specified for a given photometric
     253             :  * type. 0 is returned if photometric type isn't supported or no default value
     254             :  * is defined by the specification.
     255             :  */
     256         228 : static int GTIFFGetMaxColorChannels(int photometric)
     257             : {
     258         228 :     switch (photometric)
     259             :     {
     260         166 :         case PHOTOMETRIC_PALETTE:
     261             :         case PHOTOMETRIC_MINISWHITE:
     262             :         case PHOTOMETRIC_MINISBLACK:
     263         166 :             return 1;
     264          62 :         case PHOTOMETRIC_YCBCR:
     265             :         case PHOTOMETRIC_RGB:
     266             :         case PHOTOMETRIC_CIELAB:
     267             :         case PHOTOMETRIC_LOGLUV:
     268             :         case PHOTOMETRIC_ITULAB:
     269             :         case PHOTOMETRIC_ICCLAB:
     270          62 :             return 3;
     271           0 :         case PHOTOMETRIC_SEPARATED:
     272             :         case PHOTOMETRIC_MASK:
     273           0 :             return 4;
     274           0 :         case PHOTOMETRIC_LOGL:
     275             :         default:
     276           0 :             return 0;
     277             :     }
     278             : }
     279             : 
     280             : /************************************************************************/
     281             : /*                        GTIFFBuildOverviews()                         */
     282             : /************************************************************************/
     283             : 
     284         188 : CPLErr GTIFFBuildOverviews(const char *pszFilename, int nBands,
     285             :                            GDALRasterBand *const *papoBandList, int nOverviews,
     286             :                            const int *panOverviewList,
     287             :                            const char *pszResampling,
     288             :                            GDALProgressFunc pfnProgress, void *pProgressData,
     289             :                            CSLConstList papszOptions)
     290             : 
     291             : {
     292         188 :     return GTIFFBuildOverviewsEx(pszFilename, nBands, papoBandList, nOverviews,
     293             :                                  panOverviewList, nullptr, pszResampling,
     294         188 :                                  papszOptions, pfnProgress, pProgressData);
     295             : }
     296             : 
     297         237 : CPLErr GTIFFBuildOverviewsEx(const char *pszFilename, int nBands,
     298             :                              GDALRasterBand *const *papoBandList,
     299             :                              int nOverviews, const int *panOverviewList,
     300             :                              const std::pair<int, int> *pasOverviewSize,
     301             :                              const char *pszResampling,
     302             :                              const char *const *papszOptions,
     303             :                              GDALProgressFunc pfnProgress, void *pProgressData)
     304             : {
     305         237 :     if (nBands == 0 || nOverviews == 0)
     306           5 :         return CE_None;
     307             : 
     308         232 :     CPLAssert((panOverviewList != nullptr) ^ (pasOverviewSize != nullptr));
     309             : 
     310         232 :     GTiffOneTimeInit();
     311             : 
     312         232 :     TIFF *hOTIFF = nullptr;
     313         232 :     int nBitsPerPixel = 0;
     314         232 :     int nCompression = COMPRESSION_NONE;
     315         232 :     uint16_t nPhotometric = 0;
     316         232 :     int nSampleFormat = 0;
     317         232 :     uint16_t nPlanarConfig = 0;
     318         232 :     int iOverview = 0;
     319         232 :     int nXSize = 0;
     320         232 :     int nYSize = 0;
     321             : 
     322             :     /* -------------------------------------------------------------------- */
     323             :     /*      Verify that the list of bands is suitable for emitting in       */
     324             :     /*      TIFF file.                                                      */
     325             :     /* -------------------------------------------------------------------- */
     326         616 :     for (int iBand = 0; iBand < nBands; iBand++)
     327             :     {
     328         384 :         int nBandBits = 0;
     329         384 :         int nBandFormat = 0;
     330         384 :         GDALRasterBand *hBand = papoBandList[iBand];
     331             : 
     332         384 :         switch (hBand->GetRasterDataType())
     333             :         {
     334         324 :             case GDT_Byte:
     335         324 :                 nBandBits = 8;
     336         324 :                 nBandFormat = SAMPLEFORMAT_UINT;
     337         324 :                 break;
     338             : 
     339           0 :             case GDT_Int8:
     340           0 :                 nBandBits = 8;
     341           0 :                 nBandFormat = SAMPLEFORMAT_INT;
     342           0 :                 break;
     343             : 
     344           4 :             case GDT_UInt16:
     345           4 :                 nBandBits = 16;
     346           4 :                 nBandFormat = SAMPLEFORMAT_UINT;
     347           4 :                 break;
     348             : 
     349          10 :             case GDT_Int16:
     350          10 :                 nBandBits = 16;
     351          10 :                 nBandFormat = SAMPLEFORMAT_INT;
     352          10 :                 break;
     353             : 
     354           2 :             case GDT_UInt32:
     355           2 :                 nBandBits = 32;
     356           2 :                 nBandFormat = SAMPLEFORMAT_UINT;
     357           2 :                 break;
     358             : 
     359           3 :             case GDT_Int32:
     360           3 :                 nBandBits = 32;
     361           3 :                 nBandFormat = SAMPLEFORMAT_INT;
     362           3 :                 break;
     363             : 
     364           1 :             case GDT_UInt64:
     365           1 :                 nBandBits = 64;
     366           1 :                 nBandFormat = SAMPLEFORMAT_UINT;
     367           1 :                 break;
     368             : 
     369           1 :             case GDT_Int64:
     370           1 :                 nBandBits = 64;
     371           1 :                 nBandFormat = SAMPLEFORMAT_INT;
     372           1 :                 break;
     373             : 
     374           0 :             case GDT_Float16:
     375             :                 // Convert Float16 to float.
     376             :                 // TODO: At some point we should support Float16.
     377           0 :                 nBandBits = 32;
     378           0 :                 nBandFormat = SAMPLEFORMAT_IEEEFP;
     379           0 :                 break;
     380             : 
     381          29 :             case GDT_Float32:
     382          29 :                 nBandBits = 32;
     383          29 :                 nBandFormat = SAMPLEFORMAT_IEEEFP;
     384          29 :                 break;
     385             : 
     386           2 :             case GDT_Float64:
     387           2 :                 nBandBits = 64;
     388           2 :                 nBandFormat = SAMPLEFORMAT_IEEEFP;
     389           2 :                 break;
     390             : 
     391           2 :             case GDT_CInt16:
     392           2 :                 nBandBits = 32;
     393           2 :                 nBandFormat = SAMPLEFORMAT_COMPLEXINT;
     394           2 :                 break;
     395             : 
     396           2 :             case GDT_CInt32:
     397           2 :                 nBandBits = 64;
     398           2 :                 nBandFormat = SAMPLEFORMAT_COMPLEXINT;
     399           2 :                 break;
     400             : 
     401           0 :             case GDT_CFloat16:
     402             :                 // Convert Float16 to float.
     403             :                 // TODO: At some point we should support Float16.
     404           0 :                 nBandBits = 64;
     405           0 :                 nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
     406           0 :                 break;
     407             : 
     408           2 :             case GDT_CFloat32:
     409           2 :                 nBandBits = 64;
     410           2 :                 nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
     411           2 :                 break;
     412             : 
     413           2 :             case GDT_CFloat64:
     414           2 :                 nBandBits = 128;
     415           2 :                 nBandFormat = SAMPLEFORMAT_COMPLEXIEEEFP;
     416           2 :                 break;
     417             : 
     418           0 :             case GDT_Unknown:
     419             :             case GDT_TypeCount:
     420           0 :                 CPLAssert(false);
     421             :                 return CE_Failure;
     422             :         }
     423             : 
     424         384 :         if (hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"))
     425             :         {
     426             :             nBandBits =
     427           8 :                 atoi(hBand->GetMetadataItem("NBITS", "IMAGE_STRUCTURE"));
     428             : 
     429           8 :             if (nBandBits == 1 && STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
     430           4 :                 nBandBits = 8;
     431             :         }
     432             : 
     433         384 :         if (iBand == 0)
     434             :         {
     435         232 :             nBitsPerPixel = nBandBits;
     436         232 :             nSampleFormat = nBandFormat;
     437         232 :             nXSize = hBand->GetXSize();
     438         232 :             nYSize = hBand->GetYSize();
     439             :         }
     440         152 :         else if (nBitsPerPixel != nBandBits || nSampleFormat != nBandFormat)
     441             :         {
     442           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     443             :                      "GTIFFBuildOverviews() doesn't support a mixture of band"
     444             :                      " data types.");
     445           0 :             return CE_Failure;
     446             :         }
     447         152 :         else if (hBand->GetColorTable() != nullptr)
     448             :         {
     449           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     450             :                      "GTIFFBuildOverviews() doesn't support building"
     451             :                      " overviews of multiple colormapped bands.");
     452           0 :             return CE_Failure;
     453             :         }
     454         152 :         else if (hBand->GetXSize() != nXSize || hBand->GetYSize() != nYSize)
     455             :         {
     456           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     457             :                      "GTIFFBuildOverviews() doesn't support building"
     458             :                      " overviews of different sized bands.");
     459           0 :             return CE_Failure;
     460             :         }
     461             :     }
     462             : 
     463             :     const auto GetOptionValue =
     464        3539 :         [papszOptions](const char *pszOptionKey, const char *pszConfigOptionKey,
     465        3539 :                        const char **ppszKeyUsed = nullptr)
     466             :     {
     467        3539 :         const char *pszVal = CSLFetchNameValue(papszOptions, pszOptionKey);
     468        3539 :         if (pszVal)
     469             :         {
     470         179 :             if (ppszKeyUsed)
     471          56 :                 *ppszKeyUsed = pszOptionKey;
     472         179 :             return pszVal;
     473             :         }
     474        3360 :         pszVal = CPLGetConfigOption(pszConfigOptionKey, nullptr);
     475        3360 :         if (pszVal && ppszKeyUsed)
     476          57 :             *ppszKeyUsed = pszConfigOptionKey;
     477        3360 :         return pszVal;
     478         232 :     };
     479             : 
     480             :     /* -------------------------------------------------------------------- */
     481             :     /*      Use specified compression method.                               */
     482             :     /* -------------------------------------------------------------------- */
     483         232 :     const char *pszCompressKey = "";
     484             :     const char *pszCompress =
     485         232 :         GetOptionValue("COMPRESS", "COMPRESS_OVERVIEW", &pszCompressKey);
     486             : 
     487         232 :     if (pszCompress != nullptr && pszCompress[0] != '\0')
     488             :     {
     489         104 :         nCompression = GTIFFGetCompressionMethod(pszCompress, pszCompressKey);
     490         104 :         if (nCompression < 0)
     491           0 :             return CE_Failure;
     492             :     }
     493             : 
     494         232 :     if (nCompression == COMPRESSION_JPEG && nBitsPerPixel > 8)
     495             :     {
     496           2 :         if (nBitsPerPixel > 16)
     497             :         {
     498           0 :             CPLError(CE_Failure, CPLE_NotSupported,
     499             :                      "GTIFFBuildOverviews() doesn't support building"
     500             :                      " JPEG compressed overviews of nBitsPerPixel > 16.");
     501           0 :             return CE_Failure;
     502             :         }
     503             : 
     504           2 :         nBitsPerPixel = 12;
     505             :     }
     506             : 
     507             :     /* -------------------------------------------------------------------- */
     508             :     /*      Figure out the planar configuration to use.                     */
     509             :     /* -------------------------------------------------------------------- */
     510         232 :     if (nBands == 1)
     511         160 :         nPlanarConfig = PLANARCONFIG_CONTIG;
     512             :     else
     513          72 :         nPlanarConfig = PLANARCONFIG_SEPARATE;
     514             : 
     515         232 :     bool bSourceIsPixelInterleaved = false;
     516         232 :     bool bSourceIsJPEG2000 = false;
     517         232 :     if (nBands > 1)
     518             :     {
     519          72 :         GDALDataset *poSrcDS = papoBandList[0]->GetDataset();
     520          72 :         if (poSrcDS)
     521             :         {
     522             :             const char *pszSrcInterleave =
     523          72 :                 poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
     524          72 :             if (pszSrcInterleave && EQUAL(pszSrcInterleave, "PIXEL"))
     525             :             {
     526          42 :                 bSourceIsPixelInterleaved = true;
     527             :             }
     528             :         }
     529             : 
     530             :         const char *pszSrcCompression =
     531          72 :             papoBandList[0]->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
     532          72 :         if (pszSrcCompression)
     533             :         {
     534           2 :             bSourceIsJPEG2000 = EQUAL(pszSrcCompression, "JPEG2000");
     535             :         }
     536          72 :         if (bSourceIsPixelInterleaved && bSourceIsJPEG2000)
     537             :         {
     538           1 :             nPlanarConfig = PLANARCONFIG_CONTIG;
     539             :         }
     540          71 :         else if (nCompression == COMPRESSION_WEBP ||
     541          66 :                  nCompression == COMPRESSION_JXL ||
     542             :                  nCompression == COMPRESSION_JXL_DNG_1_7)
     543             :         {
     544           7 :             nPlanarConfig = PLANARCONFIG_CONTIG;
     545             :         }
     546             :     }
     547             : 
     548             :     const char *pszInterleave =
     549         232 :         GetOptionValue("INTERLEAVE", "INTERLEAVE_OVERVIEW");
     550         232 :     if (pszInterleave != nullptr && pszInterleave[0] != '\0')
     551             :     {
     552          31 :         if (EQUAL(pszInterleave, "PIXEL"))
     553          31 :             nPlanarConfig = PLANARCONFIG_CONTIG;
     554           0 :         else if (EQUAL(pszInterleave, "BAND"))
     555           0 :             nPlanarConfig = PLANARCONFIG_SEPARATE;
     556             :         else
     557             :         {
     558           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     559             :                      "INTERLEAVE_OVERVIEW=%s unsupported, "
     560             :                      "value must be PIXEL or BAND. ignoring",
     561             :                      pszInterleave);
     562             :         }
     563             :     }
     564             : 
     565             :     /* -------------------------------------------------------------------- */
     566             :     /*      Figure out the photometric interpretation to use.               */
     567             :     /* -------------------------------------------------------------------- */
     568         232 :     if (nBands == 3)
     569          47 :         nPhotometric = PHOTOMETRIC_RGB;
     570         185 :     else if (papoBandList[0]->GetColorTable() != nullptr &&
     571           7 :              (papoBandList[0]->GetRasterDataType() == GDT_Byte ||
     572         192 :               papoBandList[0]->GetRasterDataType() == GDT_UInt16) &&
     573           6 :              !STARTS_WITH_CI(pszResampling, "AVERAGE_BIT2"))
     574             :     {
     575             :         // Would also apply to other lossy compression scheme, but for JPEG,
     576             :         // this at least avoids a later cryptic error message from libtiff:
     577             :         // "JPEGSetupEncode:PhotometricInterpretation 3 not allowed for JPEG"
     578           6 :         if (nCompression == COMPRESSION_JPEG)
     579             :         {
     580           1 :             CPLError(CE_Failure, CPLE_AppDefined,
     581             :                      "Cannot create JPEG compressed overviews on a raster "
     582             :                      "with a color table");
     583           1 :             return CE_Failure;
     584             :         }
     585             : 
     586           5 :         nPhotometric = PHOTOMETRIC_PALETTE;
     587             :         // Color map is set up after
     588             :     }
     589         195 :     else if (nBands >= 3 &&
     590          16 :              papoBandList[0]->GetColorInterpretation() == GCI_RedBand &&
     591         210 :              papoBandList[1]->GetColorInterpretation() == GCI_GreenBand &&
     592          15 :              papoBandList[2]->GetColorInterpretation() == GCI_BlueBand)
     593             :     {
     594          15 :         nPhotometric = PHOTOMETRIC_RGB;
     595             :     }
     596             :     else
     597         164 :         nPhotometric = PHOTOMETRIC_MINISBLACK;
     598             : 
     599         231 :     const char *pszOptionKey = "";
     600             :     const char *pszPhotometric =
     601         231 :         GetOptionValue("PHOTOMETRIC", "PHOTOMETRIC_OVERVIEW", &pszOptionKey);
     602         231 :     if (!GTIFFUpdatePhotometric(pszPhotometric, pszOptionKey, nCompression,
     603             :                                 pszInterleave, nBands, nPhotometric,
     604             :                                 nPlanarConfig))
     605             :     {
     606           0 :         return CE_Failure;
     607             :     }
     608             : 
     609             :     /* -------------------------------------------------------------------- */
     610             :     /*      Figure out the predictor value to use.                          */
     611             :     /* -------------------------------------------------------------------- */
     612         231 :     int nPredictor = PREDICTOR_NONE;
     613         231 :     if (GTIFFSupportsPredictor(nCompression))
     614             :     {
     615             :         const char *pszPredictor =
     616          71 :             GetOptionValue("PREDICTOR", "PREDICTOR_OVERVIEW");
     617          71 :         if (pszPredictor != nullptr)
     618             :         {
     619           2 :             nPredictor = atoi(pszPredictor);
     620             :         }
     621             :     }
     622             : 
     623             :     /* -------------------------------------------------------------------- */
     624             :     /*      Create the file, if it does not already exist.                  */
     625             :     /* -------------------------------------------------------------------- */
     626             :     VSIStatBufL sStatBuf;
     627         231 :     VSILFILE *fpL = nullptr;
     628             : 
     629         231 :     bool bCreateBigTIFF = false;
     630         231 :     if (VSIStatExL(pszFilename, &sStatBuf, VSI_STAT_EXISTS_FLAG) != 0)
     631             :     {
     632             :         /* --------------------------------------------------------------------
     633             :          */
     634             :         /*      Compute the uncompressed size. */
     635             :         /* --------------------------------------------------------------------
     636             :          */
     637         227 :         double dfUncompressedOverviewSize = 0;
     638             :         int nDataTypeSize =
     639         227 :             GDALGetDataTypeSizeBytes(papoBandList[0]->GetRasterDataType());
     640             : 
     641         573 :         for (iOverview = 0; iOverview < nOverviews; iOverview++)
     642             :         {
     643         346 :             const int nOXSize =
     644             :                 panOverviewList
     645         346 :                     ? DIV_ROUND_UP(nXSize, panOverviewList[iOverview])
     646             :                     :
     647             :                     // cppcheck-suppress nullPointer
     648         104 :                     pasOverviewSize[iOverview].first;
     649         346 :             const int nOYSize =
     650             :                 panOverviewList
     651         346 :                     ? DIV_ROUND_UP(nYSize, panOverviewList[iOverview])
     652             :                     :
     653             :                     // cppcheck-suppress nullPointer
     654         104 :                     pasOverviewSize[iOverview].second;
     655             : 
     656         346 :             dfUncompressedOverviewSize +=
     657         346 :                 nOXSize * static_cast<double>(nOYSize) * nBands * nDataTypeSize;
     658             :         }
     659             : 
     660             :         /* --------------------------------------------------------------------
     661             :          */
     662             :         /*      Should the file be created as a bigtiff file? */
     663             :         /* --------------------------------------------------------------------
     664             :          */
     665         227 :         const char *pszBIGTIFF = GetOptionValue("BIGTIFF", "BIGTIFF_OVERVIEW");
     666             : 
     667         227 :         if (pszBIGTIFF == nullptr)
     668         170 :             pszBIGTIFF = "IF_SAFER";
     669             : 
     670         227 :         if (EQUAL(pszBIGTIFF, "IF_NEEDED"))
     671             :         {
     672           0 :             if (nCompression == COMPRESSION_NONE &&
     673             :                 dfUncompressedOverviewSize > 4200000000.0)
     674           0 :                 bCreateBigTIFF = true;
     675             :         }
     676         227 :         else if (EQUAL(pszBIGTIFF, "IF_SAFER"))
     677             :         {
     678             :             // Look at the size of the base image and suppose that
     679             :             // the added overview levels won't be more than 1/2 of
     680             :             // the size of the base image. The theory says 1/3 of the
     681             :             // base image size if the overview levels are 2, 4, 8, 16.
     682             :             // Thus take 1/2 as the security margin for 1/3.
     683         172 :             const double dfUncompressedImageSize =
     684         172 :                 nXSize * static_cast<double>(nYSize) * nBands * nDataTypeSize;
     685         172 :             if (dfUncompressedImageSize * 0.5 > 4200000000.0)
     686           5 :                 bCreateBigTIFF = true;
     687             :         }
     688             :         else
     689             :         {
     690          55 :             bCreateBigTIFF = CPLTestBool(pszBIGTIFF);
     691          55 :             if (!bCreateBigTIFF && nCompression == COMPRESSION_NONE &&
     692             :                 dfUncompressedOverviewSize > 4200000000.0)
     693             :             {
     694           2 :                 CPLError(CE_Failure, CPLE_NotSupported,
     695             :                          "The overview file will be larger than 4GB, "
     696             :                          "so BigTIFF is necessary.  "
     697             :                          "Creation failed.");
     698           2 :                 return CE_Failure;
     699             :             }
     700             :         }
     701             : 
     702         225 :         if (bCreateBigTIFF)
     703          56 :             CPLDebug("GTiff", "File being created as a BigTIFF.");
     704             : 
     705         225 :         fpL = VSIFOpenL(pszFilename, "w+");
     706         225 :         if (fpL == nullptr)
     707           1 :             hOTIFF = nullptr;
     708             :         else
     709             :             hOTIFF =
     710         224 :                 VSI_TIFFOpen(pszFilename, bCreateBigTIFF ? "w+8" : "w+", fpL);
     711         225 :         if (hOTIFF == nullptr)
     712             :         {
     713           1 :             if (CPLGetLastErrorNo() == 0)
     714           1 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     715             :                          "Attempt to create new tiff file `%s' "
     716             :                          "failed in VSI_TIFFOpen().",
     717             :                          pszFilename);
     718           1 :             if (fpL != nullptr)
     719           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
     720           1 :             return CE_Failure;
     721             :         }
     722             :     }
     723             :     /* -------------------------------------------------------------------- */
     724             :     /*      Otherwise just open it for update access.                       */
     725             :     /* -------------------------------------------------------------------- */
     726             :     else
     727             :     {
     728           4 :         fpL = VSIFOpenL(pszFilename, "r+");
     729           4 :         if (fpL == nullptr)
     730           0 :             hOTIFF = nullptr;
     731             :         else
     732             :         {
     733           4 :             GByte abyBuffer[4] = {0};
     734           4 :             VSIFReadL(abyBuffer, 1, 4, fpL);
     735           4 :             VSIFSeekL(fpL, 0, SEEK_SET);
     736           4 :             bCreateBigTIFF = abyBuffer[2] == 43 || abyBuffer[3] == 43;
     737           4 :             hOTIFF = VSI_TIFFOpen(pszFilename, "r+", fpL);
     738             :         }
     739           4 :         if (hOTIFF == nullptr)
     740             :         {
     741           0 :             if (CPLGetLastErrorNo() == 0)
     742           0 :                 CPLError(CE_Failure, CPLE_OpenFailed,
     743             :                          "Attempt to create new tiff file `%s' "
     744             :                          "failed in VSI_TIFFOpen().",
     745             :                          pszFilename);
     746           0 :             if (fpL != nullptr)
     747           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpL));
     748           0 :             return CE_Failure;
     749             :         }
     750             :     }
     751             : 
     752             :     /* -------------------------------------------------------------------- */
     753             :     /*      Do we have a palette?  If so, create a TIFF compatible version. */
     754             :     /* -------------------------------------------------------------------- */
     755         228 :     unsigned short *panRed = nullptr;
     756         228 :     unsigned short *panGreen = nullptr;
     757         228 :     unsigned short *panBlue = nullptr;
     758             : 
     759         228 :     if (nPhotometric == PHOTOMETRIC_PALETTE)
     760             :     {
     761           5 :         GDALColorTable *poCT = papoBandList[0]->GetColorTable();
     762           5 :         int nColorCount = 65536;
     763             : 
     764           5 :         if (nBitsPerPixel <= 8)
     765           5 :             nColorCount = 256;
     766             : 
     767             :         panRed = static_cast<unsigned short *>(
     768           5 :             CPLCalloc(nColorCount, sizeof(unsigned short)));
     769             :         panGreen = static_cast<unsigned short *>(
     770           5 :             CPLCalloc(nColorCount, sizeof(unsigned short)));
     771             :         panBlue = static_cast<unsigned short *>(
     772           5 :             CPLCalloc(nColorCount, sizeof(unsigned short)));
     773             : 
     774             :         const int nColorTableMultiplier = std::max(
     775          10 :             1,
     776             :             std::min(
     777          10 :                 257,
     778           5 :                 atoi(CSLFetchNameValueDef(
     779             :                     papszOptions, "COLOR_TABLE_MULTIPLIER",
     780             :                     CPLSPrintf(
     781             :                         "%d",
     782           5 :                         GTiffDataset::DEFAULT_COLOR_TABLE_MULTIPLIER_257)))));
     783             : 
     784        1285 :         for (int iColor = 0; iColor < nColorCount; iColor++)
     785             :         {
     786        1280 :             GDALColorEntry sRGB = {0, 0, 0, 0};
     787             : 
     788        1280 :             if (poCT->GetColorEntryAsRGB(iColor, &sRGB))
     789             :             {
     790        2560 :                 panRed[iColor] = GTiffDataset::ClampCTEntry(
     791        1280 :                     iColor, 1, sRGB.c1, nColorTableMultiplier);
     792        2560 :                 panGreen[iColor] = GTiffDataset::ClampCTEntry(
     793        1280 :                     iColor, 2, sRGB.c2, nColorTableMultiplier);
     794        1280 :                 panBlue[iColor] = GTiffDataset::ClampCTEntry(
     795        1280 :                     iColor, 3, sRGB.c3, nColorTableMultiplier);
     796             :             }
     797             :         }
     798             :     }
     799             : 
     800             :     /* -------------------------------------------------------------------- */
     801             :     /*      Do we need some metadata for the overviews?                     */
     802             :     /* -------------------------------------------------------------------- */
     803         456 :     CPLString osMetadata;
     804         228 :     GDALDataset *poBaseDS = papoBandList[0]->GetDataset();
     805         228 :     if (poBaseDS)
     806             :     {
     807             :         const bool bIsForMaskBand =
     808         224 :             nBands == 1 && papoBandList[0]->IsMaskBand();
     809         224 :         GTIFFBuildOverviewMetadata(pszResampling, poBaseDS, bIsForMaskBand,
     810             :                                    osMetadata);
     811             :     }
     812             : 
     813         228 :     if (poBaseDS != nullptr && poBaseDS->GetRasterCount() == nBands)
     814             :     {
     815         218 :         const bool bStandardColorInterp = GTIFFIsStandardColorInterpretation(
     816             :             GDALDataset::ToHandle(poBaseDS),
     817             :             static_cast<uint16_t>(nPhotometric), nullptr);
     818         218 :         if (!bStandardColorInterp)
     819             :         {
     820          18 :             if (osMetadata.size() >= strlen("</GDALMetadata>") &&
     821          18 :                 osMetadata.substr(osMetadata.size() -
     822           9 :                                   strlen("</GDALMetadata>")) ==
     823             :                     "</GDALMetadata>")
     824             :             {
     825           9 :                 osMetadata.resize(osMetadata.size() -
     826             :                                   strlen("</GDALMetadata>"));
     827             :             }
     828             :             else
     829             :             {
     830           0 :                 CPLAssert(osMetadata.empty());
     831           0 :                 osMetadata = "<GDALMetadata>";
     832             :             }
     833          36 :             for (int i = 0; i < poBaseDS->GetRasterCount(); ++i)
     834             :             {
     835             :                 const GDALColorInterp eInterp =
     836          27 :                     poBaseDS->GetRasterBand(i + 1)->GetColorInterpretation();
     837             :                 osMetadata +=
     838             :                     CPLSPrintf("<Item sample=\"%d\" name=\"COLORINTERP\" "
     839             :                                "role=\"colorinterp\">",
     840          27 :                                i);
     841          27 :                 osMetadata += GDALGetColorInterpretationName(eInterp);
     842          27 :                 osMetadata += "</Item>";
     843             :             }
     844           9 :             osMetadata += "</GDALMetadata>";
     845             :         }
     846             :     }
     847             : 
     848             :     /* -------------------------------------------------------------------- */
     849             :     /*      Loop, creating overviews.                                       */
     850             :     /* -------------------------------------------------------------------- */
     851         228 :     int nOvrBlockXSize = 0;
     852         228 :     int nOvrBlockYSize = 0;
     853         228 :     GTIFFGetOverviewBlockSize(papoBandList[0], &nOvrBlockXSize,
     854             :                               &nOvrBlockYSize);
     855             : 
     856         456 :     CPLString osNoData;  // don't move this in inner scope
     857         228 :     const char *pszNoData = nullptr;
     858         228 :     int bNoDataSet = FALSE;
     859         228 :     const double dfNoDataValue = papoBandList[0]->GetNoDataValue(&bNoDataSet);
     860         228 :     if (bNoDataSet)
     861             :     {
     862          12 :         osNoData = GTiffFormatGDALNoDataTagValue(dfNoDataValue);
     863          12 :         pszNoData = osNoData.c_str();
     864             :     }
     865             : 
     866         456 :     std::vector<uint16_t> anExtraSamples;
     867         256 :     for (int i = GTIFFGetMaxColorChannels(nPhotometric) + 1; i <= nBands; i++)
     868             :     {
     869          28 :         if (papoBandList[i - 1]->GetColorInterpretation() == GCI_AlphaBand)
     870             :         {
     871          18 :             anExtraSamples.push_back(GTiffGetAlphaValue(
     872             :                 GetOptionValue("ALPHA", "GTIFF_ALPHA"), DEFAULT_ALPHA_TYPE));
     873             :         }
     874             :         else
     875             :         {
     876          10 :             anExtraSamples.push_back(EXTRASAMPLE_UNSPECIFIED);
     877             :         }
     878             :     }
     879             : 
     880         228 :     const uint32_t *panLercAddCompressionAndVersion = nullptr;
     881         228 :     uint32_t anLercAddCompressionAndVersion[2] = {LERC_VERSION_2_4,
     882             :                                                   LERC_ADD_COMPRESSION_NONE};
     883         228 :     if (pszCompress && EQUAL(pszCompress, "LERC_DEFLATE"))
     884             :     {
     885           5 :         anLercAddCompressionAndVersion[1] = LERC_ADD_COMPRESSION_DEFLATE;
     886           5 :         panLercAddCompressionAndVersion = anLercAddCompressionAndVersion;
     887             :     }
     888         223 :     else if (pszCompress && EQUAL(pszCompress, "LERC_ZSTD"))
     889             :     {
     890           5 :         anLercAddCompressionAndVersion[1] = LERC_ADD_COMPRESSION_ZSTD;
     891           5 :         panLercAddCompressionAndVersion = anLercAddCompressionAndVersion;
     892             :     }
     893             : 
     894         574 :     for (iOverview = 0; iOverview < nOverviews; iOverview++)
     895             :     {
     896         347 :         const int nOXSize =
     897         347 :             panOverviewList ? DIV_ROUND_UP(nXSize, panOverviewList[iOverview]) :
     898             :                             // cppcheck-suppress nullPointer
     899         104 :                 pasOverviewSize[iOverview].first;
     900         347 :         const int nOYSize =
     901         347 :             panOverviewList ? DIV_ROUND_UP(nYSize, panOverviewList[iOverview]) :
     902             :                             // cppcheck-suppress nullPointer
     903         104 :                 pasOverviewSize[iOverview].second;
     904             : 
     905         347 :         const int nTileXCount = DIV_ROUND_UP(nOXSize, nOvrBlockXSize);
     906         347 :         const int nTileYCount = DIV_ROUND_UP(nOYSize, nOvrBlockYSize);
     907             :         // libtiff implementation limitation
     908         347 :         if (nTileXCount > INT_MAX / (bCreateBigTIFF ? 8 : 4) / nTileYCount)
     909             :         {
     910           1 :             CPLError(CE_Failure, CPLE_NotSupported,
     911             :                      "File too large regarding tile size. This would result "
     912             :                      "in a file with tile arrays larger than 2GB");
     913           1 :             XTIFFClose(hOTIFF);
     914           1 :             VSIFCloseL(fpL);
     915           1 :             return CE_Failure;
     916             :         }
     917             : 
     918        1038 :         if (GTIFFWriteDirectory(
     919             :                 hOTIFF, FILETYPE_REDUCEDIMAGE, nOXSize, nOYSize, nBitsPerPixel,
     920             :                 nPlanarConfig, nBands, nOvrBlockXSize, nOvrBlockYSize, TRUE,
     921             :                 nCompression, nPhotometric, nSampleFormat, nPredictor, panRed,
     922         346 :                 panGreen, panBlue, static_cast<int>(anExtraSamples.size()),
     923         391 :                 anExtraSamples.empty() ? nullptr : anExtraSamples.data(),
     924             :                 osMetadata,
     925             :                 GetOptionValue("JPEG_QUALITY", "JPEG_QUALITY_OVERVIEW"),
     926             :                 GetOptionValue("JPEG_TABLESMODE", "JPEG_TABLESMODE_OVERVIEW"),
     927         346 :                 pszNoData, panLercAddCompressionAndVersion, false) == 0)
     928             :         {
     929           0 :             XTIFFClose(hOTIFF);
     930           0 :             VSIFCloseL(fpL);
     931           0 :             return CE_Failure;
     932             :         }
     933             :     }
     934             : 
     935         227 :     if (panRed)
     936             :     {
     937           5 :         CPLFree(panRed);
     938           5 :         CPLFree(panGreen);
     939           5 :         CPLFree(panBlue);
     940           5 :         panRed = nullptr;
     941           5 :         panGreen = nullptr;
     942           5 :         panBlue = nullptr;
     943             :     }
     944             : 
     945         227 :     XTIFFClose(hOTIFF);
     946         227 :     if (VSIFCloseL(fpL) != 0)
     947           0 :         return CE_Failure;
     948         227 :     fpL = nullptr;
     949             : 
     950             :     /* -------------------------------------------------------------------- */
     951             :     /*      Open the overview dataset so that we can get at the overview    */
     952             :     /*      bands.                                                          */
     953             :     /* -------------------------------------------------------------------- */
     954         454 :     CPLStringList aosOpenOptions;
     955             :     aosOpenOptions.SetNameValue("NUM_THREADS",
     956         227 :                                 CSLFetchNameValue(papszOptions, "NUM_THREADS"));
     957             :     aosOpenOptions.SetNameValue(
     958         227 :         "SPARSE_OK", GetOptionValue("SPARSE_OK", "SPARSE_OK_OVERVIEW"));
     959             :     aosOpenOptions.SetNameValue(
     960             :         "@MASK_OVERVIEW_DATASET",
     961         227 :         CSLFetchNameValue(papszOptions, "MASK_OVERVIEW_DATASET"));
     962             :     GDALDataset *hODS =
     963         227 :         GDALDataset::Open(pszFilename, GDAL_OF_RASTER | GDAL_OF_UPDATE, nullptr,
     964         227 :                           aosOpenOptions.List());
     965         227 :     if (hODS == nullptr)
     966           0 :         return CE_Failure;
     967             : 
     968             :     /* -------------------------------------------------------------------- */
     969             :     /*      Do we need to set the jpeg quality?                             */
     970             :     /* -------------------------------------------------------------------- */
     971         227 :     TIFF *hTIFF = static_cast<TIFF *>(hODS->GetInternalHandle(nullptr));
     972             : 
     973             :     const char *pszJPEGQuality =
     974         227 :         GetOptionValue("JPEG_QUALITY", "JPEG_QUALITY_OVERVIEW");
     975         227 :     if (nCompression == COMPRESSION_JPEG && pszJPEGQuality != nullptr)
     976             :     {
     977           4 :         const int nJpegQuality = atoi(pszJPEGQuality);
     978           4 :         TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, nJpegQuality);
     979           4 :         GTIFFSetJpegQuality(GDALDataset::ToHandle(hODS), nJpegQuality);
     980             :     }
     981             : 
     982             :     const char *pszWebpLevel =
     983         227 :         GetOptionValue("WEBP_LEVEL", "WEBP_LEVEL_OVERVIEW");
     984         227 :     if (nCompression == COMPRESSION_WEBP && pszWebpLevel != nullptr)
     985             :     {
     986           3 :         const int nWebpLevel = atoi(pszWebpLevel);
     987           3 :         if (nWebpLevel >= 1)
     988             :         {
     989           3 :             TIFFSetField(hTIFF, TIFFTAG_WEBP_LEVEL, nWebpLevel);
     990           3 :             GTIFFSetWebPLevel(GDALDataset::ToHandle(hODS), nWebpLevel);
     991             :         }
     992             :     }
     993             : 
     994             :     const char *pszWebpLossless =
     995         227 :         GetOptionValue("WEBP_LOSSLESS", "WEBP_LOSSLESS_OVERVIEW");
     996         227 :     if (nCompression == COMPRESSION_WEBP && pszWebpLossless != nullptr)
     997             :     {
     998           1 :         const bool bWebpLossless = CPLTestBool(pszWebpLossless);
     999           1 :         TIFFSetField(hTIFF, TIFFTAG_WEBP_LOSSLESS,
    1000             :                      static_cast<int>(bWebpLossless));
    1001           1 :         GTIFFSetWebPLossless(GDALDataset::ToHandle(hODS), bWebpLossless);
    1002             :     }
    1003             : 
    1004             :     const char *pszJPEGTablesMode =
    1005         227 :         GetOptionValue("JPEG_TABLESMODE", "JPEG_TABLESMODE_OVERVIEW");
    1006         227 :     if (nCompression == COMPRESSION_JPEG && pszJPEGTablesMode != nullptr)
    1007             :     {
    1008           0 :         const int nJpegTablesMode = atoi(pszJPEGTablesMode);
    1009           0 :         TIFFSetField(hTIFF, TIFFTAG_JPEGTABLESMODE, nJpegTablesMode);
    1010           0 :         GTIFFSetJpegTablesMode(GDALDataset::ToHandle(hODS), nJpegTablesMode);
    1011             :     }
    1012             : 
    1013         227 :     const char *pszZLevel = GetOptionValue("ZLEVEL", "ZLEVEL_OVERVIEW");
    1014         227 :     if ((nCompression == COMPRESSION_DEFLATE ||
    1015         227 :          anLercAddCompressionAndVersion[1] == LERC_ADD_COMPRESSION_DEFLATE) &&
    1016             :         pszZLevel != nullptr)
    1017             :     {
    1018           2 :         const int nZLevel = atoi(pszZLevel);
    1019           2 :         if (nZLevel >= 1)
    1020             :         {
    1021           2 :             TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, nZLevel);
    1022           2 :             GTIFFSetZLevel(GDALDataset::ToHandle(hODS), nZLevel);
    1023             :         }
    1024             :     }
    1025             : 
    1026             :     const char *pszZSTDLevel =
    1027         227 :         GetOptionValue("ZSTD_LEVEL", "ZSTD_LEVEL_OVERVIEW");
    1028         227 :     if ((nCompression == COMPRESSION_ZSTD ||
    1029         227 :          anLercAddCompressionAndVersion[1] == LERC_ADD_COMPRESSION_ZSTD) &&
    1030             :         pszZSTDLevel != nullptr)
    1031             :     {
    1032           2 :         const int nZSTDLevel = atoi(pszZSTDLevel);
    1033           2 :         if (nZSTDLevel >= 1)
    1034             :         {
    1035           2 :             TIFFSetField(hTIFF, TIFFTAG_ZSTD_LEVEL, nZSTDLevel);
    1036           2 :             GTIFFSetZSTDLevel(GDALDataset::ToHandle(hODS), nZSTDLevel);
    1037             :         }
    1038             :     }
    1039             : 
    1040             :     const char *pszMaxZError =
    1041         227 :         GetOptionValue("MAX_Z_ERROR", "MAX_Z_ERROR_OVERVIEW");
    1042         227 :     if (nCompression == COMPRESSION_LERC && pszMaxZError != nullptr)
    1043             :     {
    1044          10 :         const double dfMaxZError = CPLAtof(pszMaxZError);
    1045          10 :         if (dfMaxZError >= 0)
    1046             :         {
    1047          10 :             TIFFSetField(hTIFF, TIFFTAG_LERC_MAXZERROR, dfMaxZError);
    1048          10 :             GTIFFSetMaxZError(GDALDataset::ToHandle(hODS), dfMaxZError);
    1049             :         }
    1050             :     }
    1051             : 
    1052             : #if HAVE_JXL
    1053         227 :     if (nCompression == COMPRESSION_JXL ||
    1054             :         nCompression == COMPRESSION_JXL_DNG_1_7)
    1055             :     {
    1056           5 :         if (const char *pszJXLLossLess =
    1057           5 :                 GetOptionValue("JXL_LOSSLESS", "JXL_LOSSLESS_OVERVIEW"))
    1058             :         {
    1059           5 :             const bool bJXLLossless = CPLTestBool(pszJXLLossLess);
    1060           5 :             TIFFSetField(hTIFF, TIFFTAG_JXL_LOSSYNESS,
    1061             :                          bJXLLossless ? JXL_LOSSLESS : JXL_LOSSY);
    1062           5 :             GTIFFSetJXLLossless(GDALDataset::ToHandle(hODS), bJXLLossless);
    1063             :         }
    1064           5 :         if (const char *pszJXLEffort =
    1065           5 :                 GetOptionValue("JXL_EFFORT", "JXL_EFFORT_OVERVIEW"))
    1066             :         {
    1067           0 :             const int nJXLEffort = atoi(pszJXLEffort);
    1068           0 :             TIFFSetField(hTIFF, TIFFTAG_JXL_EFFORT, nJXLEffort);
    1069           0 :             GTIFFSetJXLEffort(GDALDataset::ToHandle(hODS), nJXLEffort);
    1070             :         }
    1071           5 :         if (const char *pszJXLDistance =
    1072           5 :                 GetOptionValue("JXL_DISTANCE", "JXL_DISTANCE_OVERVIEW"))
    1073             :         {
    1074             :             const float fJXLDistance =
    1075           1 :                 static_cast<float>(CPLAtof(pszJXLDistance));
    1076           1 :             TIFFSetField(hTIFF, TIFFTAG_JXL_DISTANCE, fJXLDistance);
    1077           1 :             GTIFFSetJXLDistance(GDALDataset::ToHandle(hODS), fJXLDistance);
    1078             :         }
    1079           5 :         if (const char *pszJXLAlphaDistance = GetOptionValue(
    1080             :                 "JXL_ALPHA_DISTANCE", "JXL_ALPHA_DISTANCE_OVERVIEW"))
    1081             :         {
    1082             :             const float fJXLAlphaDistance =
    1083           1 :                 static_cast<float>(CPLAtof(pszJXLAlphaDistance));
    1084           1 :             TIFFSetField(hTIFF, TIFFTAG_JXL_ALPHA_DISTANCE, fJXLAlphaDistance);
    1085           1 :             GTIFFSetJXLAlphaDistance(GDALDataset::ToHandle(hODS),
    1086             :                                      fJXLAlphaDistance);
    1087             :         }
    1088             :     }
    1089             : #endif
    1090             : 
    1091             :     /* -------------------------------------------------------------------- */
    1092             :     /*      Loop writing overview data.                                     */
    1093             :     /* -------------------------------------------------------------------- */
    1094             : 
    1095         227 :     int *panOverviewListSorted = nullptr;
    1096         227 :     if (panOverviewList)
    1097             :     {
    1098             :         panOverviewListSorted =
    1099         178 :             static_cast<int *>(CPLMalloc(sizeof(int) * nOverviews));
    1100         178 :         memcpy(panOverviewListSorted, panOverviewList,
    1101         178 :                sizeof(int) * nOverviews);
    1102         178 :         std::sort(panOverviewListSorted, panOverviewListSorted + nOverviews);
    1103             :     }
    1104             : 
    1105         227 :     GTIFFSetThreadLocalInExternalOvr(true);
    1106             : 
    1107         227 :     CPLErr eErr = CE_None;
    1108             : 
    1109             :     // If we have an alpha band, we want it to be generated before downsampling
    1110             :     // other bands
    1111         227 :     bool bHasAlphaBand = false;
    1112         606 :     for (int iBand = 0; iBand < nBands; iBand++)
    1113             :     {
    1114         379 :         if (papoBandList[iBand]->GetColorInterpretation() == GCI_AlphaBand)
    1115          18 :             bHasAlphaBand = true;
    1116             :     }
    1117             : 
    1118         227 :     const auto poColorTable = papoBandList[0]->GetColorTable();
    1119         227 :     if (((((bSourceIsPixelInterleaved && bSourceIsJPEG2000) ||
    1120         104 :            (nCompression != COMPRESSION_NONE)) &&
    1121         227 :           nPlanarConfig == PLANARCONFIG_CONTIG) ||
    1122         112 :          bHasAlphaBand) &&
    1123         112 :         !GDALDataTypeIsComplex(papoBandList[0]->GetRasterDataType()) &&
    1124           1 :         (poColorTable == nullptr || STARTS_WITH_CI(pszResampling, "NEAR") ||
    1125         454 :          poColorTable->IsIdentity()) &&
    1126         112 :         (STARTS_WITH_CI(pszResampling, "NEAR") ||
    1127          77 :          EQUAL(pszResampling, "AVERAGE") || EQUAL(pszResampling, "RMS") ||
    1128          50 :          EQUAL(pszResampling, "GAUSS") || EQUAL(pszResampling, "CUBIC") ||
    1129          10 :          EQUAL(pszResampling, "CUBICSPLINE") ||
    1130          10 :          EQUAL(pszResampling, "LANCZOS") || EQUAL(pszResampling, "BILINEAR") ||
    1131           6 :          EQUAL(pszResampling, "MODE")))
    1132             :     {
    1133             :         // In the case of pixel interleaved compressed overviews, we want to
    1134             :         // generate the overviews for all the bands block by block, and not
    1135             :         // band after band, in order to write the block once and not loose
    1136             :         // space in the TIFF file.
    1137             :         GDALRasterBand ***papapoOverviewBands =
    1138         108 :             static_cast<GDALRasterBand ***>(CPLCalloc(sizeof(void *), nBands));
    1139         326 :         for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
    1140             :         {
    1141         218 :             GDALRasterBand *poSrcBand = papoBandList[iBand];
    1142         218 :             GDALRasterBand *poDstBand = hODS->GetRasterBand(iBand + 1);
    1143         436 :             papapoOverviewBands[iBand] = static_cast<GDALRasterBand **>(
    1144         218 :                 CPLCalloc(sizeof(void *), nOverviews));
    1145             : 
    1146         218 :             int bHasNoData = FALSE;
    1147         218 :             const double noDataValue = poSrcBand->GetNoDataValue(&bHasNoData);
    1148         218 :             if (bHasNoData)
    1149           9 :                 poDstBand->SetNoDataValue(noDataValue);
    1150             :             std::vector<bool> abDstOverviewAssigned(
    1151         436 :                 1 + poDstBand->GetOverviewCount());
    1152             : 
    1153         612 :             for (int i = 0; i < nOverviews && eErr == CE_None; i++)
    1154             :             {
    1155             :                 const bool bDegenerateOverview =
    1156         186 :                     panOverviewListSorted != nullptr &&
    1157         413 :                     (poSrcBand->GetXSize() >> panOverviewListSorted[i]) == 0 &&
    1158          19 :                     (poSrcBand->GetYSize() >> panOverviewListSorted[i]) == 0;
    1159             : 
    1160         736 :                 for (int j = -1;
    1161         736 :                      j < poDstBand->GetOverviewCount() && eErr == CE_None; j++)
    1162             :                 {
    1163         736 :                     if (abDstOverviewAssigned[1 + j])
    1164         336 :                         continue;
    1165             :                     GDALRasterBand *poOverview =
    1166         400 :                         (j < 0) ? poDstBand : poDstBand->GetOverview(j);
    1167         400 :                     if (poOverview == nullptr)
    1168             :                     {
    1169           0 :                         eErr = CE_Failure;
    1170           0 :                         continue;
    1171             :                     }
    1172             : 
    1173             :                     bool bMatch;
    1174         400 :                     if (panOverviewListSorted)
    1175             :                     {
    1176         192 :                         const int nOvFactor = GDALComputeOvFactor(
    1177             :                             poOverview->GetXSize(), poSrcBand->GetXSize(),
    1178             :                             poOverview->GetYSize(), poSrcBand->GetYSize());
    1179             : 
    1180         192 :                         bMatch = nOvFactor == panOverviewListSorted[i] ||
    1181          12 :                                  nOvFactor == GDALOvLevelAdjust2(
    1182           6 :                                                   panOverviewListSorted[i],
    1183             :                                                   poSrcBand->GetXSize(),
    1184             :                                                   poSrcBand->GetYSize())
    1185             :                                  // Deal with edge cases where overview levels
    1186             :                                  // lead to degenerate 1x1 overviews
    1187         198 :                                  || (bDegenerateOverview &&
    1188           0 :                                      poOverview->GetXSize() == 1 &&
    1189           0 :                                      poOverview->GetYSize() == 1);
    1190             :                     }
    1191             :                     else
    1192             :                     {
    1193         208 :                         bMatch = (
    1194             :                             // cppcheck-suppress nullPointer
    1195         208 :                             poOverview->GetXSize() ==
    1196         416 :                                 pasOverviewSize[i].first &&
    1197             :                             // cppcheck-suppress nullPointer
    1198         208 :                             poOverview->GetYSize() ==
    1199         208 :                                 pasOverviewSize[i].second);
    1200             :                     }
    1201         400 :                     if (bMatch)
    1202             :                     {
    1203         394 :                         abDstOverviewAssigned[j + 1] = true;
    1204         394 :                         papapoOverviewBands[iBand][i] = poOverview;
    1205         394 :                         if (bHasNoData)
    1206          14 :                             poOverview->SetNoDataValue(noDataValue);
    1207         394 :                         break;
    1208             :                     }
    1209             :                 }
    1210             : 
    1211         394 :                 CPLAssert(papapoOverviewBands[iBand][i] != nullptr);
    1212             :             }
    1213             :         }
    1214             : 
    1215             :         {
    1216             :             CPLConfigOptionSetter oSetter(
    1217             :                 "GDAL_NUM_THREADS",
    1218         216 :                 CSLFetchNameValue(papszOptions, "NUM_THREADS"), true);
    1219             : 
    1220         108 :             if (eErr == CE_None)
    1221         108 :                 eErr = GDALRegenerateOverviewsMultiBand(
    1222             :                     nBands, papoBandList, nOverviews, papapoOverviewBands,
    1223             :                     pszResampling, pfnProgress, pProgressData, papszOptions);
    1224             :         }
    1225             : 
    1226         326 :         for (int iBand = 0; iBand < nBands; iBand++)
    1227             :         {
    1228         218 :             CPLFree(papapoOverviewBands[iBand]);
    1229             :         }
    1230         108 :         CPLFree(papapoOverviewBands);
    1231             :     }
    1232             :     else
    1233             :     {
    1234             :         GDALRasterBand **papoOverviews = static_cast<GDALRasterBand **>(
    1235         119 :             CPLCalloc(sizeof(void *), knMaxOverviews));
    1236             : 
    1237         280 :         for (int iBand = 0; iBand < nBands && eErr == CE_None; iBand++)
    1238             :         {
    1239         161 :             GDALRasterBand *hSrcBand = papoBandList[iBand];
    1240         161 :             GDALRasterBand *hDstBand = hODS->GetRasterBand(iBand + 1);
    1241             : 
    1242         161 :             int bHasNoData = FALSE;
    1243         161 :             const double noDataValue = hSrcBand->GetNoDataValue(&bHasNoData);
    1244         161 :             if (bHasNoData)
    1245           9 :                 hDstBand->SetNoDataValue(noDataValue);
    1246             : 
    1247             :             // FIXME: this logic regenerates all overview bands, not only the
    1248             :             // ones requested.
    1249             : 
    1250         161 :             papoOverviews[0] = hDstBand;
    1251         161 :             int nDstOverviews = hDstBand->GetOverviewCount() + 1;
    1252         161 :             CPLAssert(nDstOverviews < knMaxOverviews);
    1253         161 :             nDstOverviews = std::min(knMaxOverviews, nDstOverviews);
    1254             : 
    1255             :             // TODO(schwehr): Convert to starting with i = 1 and remove +1.
    1256         238 :             for (int i = 0; i < nDstOverviews - 1 && eErr == CE_None; i++)
    1257             :             {
    1258          77 :                 papoOverviews[i + 1] = hDstBand->GetOverview(i);
    1259          77 :                 if (papoOverviews[i + 1] == nullptr)
    1260             :                 {
    1261           0 :                     eErr = CE_Failure;
    1262             :                 }
    1263             :                 else
    1264             :                 {
    1265          77 :                     if (bHasNoData)
    1266           1 :                         papoOverviews[i + 1]->SetNoDataValue(noDataValue);
    1267             :                 }
    1268             :             }
    1269             : 
    1270         322 :             void *pScaledProgressData = GDALCreateScaledProgress(
    1271         161 :                 iBand / static_cast<double>(nBands),
    1272         161 :                 (iBand + 1) / static_cast<double>(nBands), pfnProgress,
    1273             :                 pProgressData);
    1274             : 
    1275             :             {
    1276             :                 CPLConfigOptionSetter oSetter(
    1277             :                     "GDAL_NUM_THREADS",
    1278         322 :                     CSLFetchNameValue(papszOptions, "NUM_THREADS"), true);
    1279             : 
    1280         161 :                 if (eErr == CE_None)
    1281         161 :                     eErr = GDALRegenerateOverviewsEx(
    1282             :                         hSrcBand, nDstOverviews,
    1283             :                         reinterpret_cast<GDALRasterBandH *>(papoOverviews),
    1284             :                         pszResampling, GDALScaledProgress, pScaledProgressData,
    1285             :                         papszOptions);
    1286             :             }
    1287             : 
    1288         161 :             GDALDestroyScaledProgress(pScaledProgressData);
    1289             :         }
    1290             : 
    1291         119 :         CPLFree(papoOverviews);
    1292             :     }
    1293             : 
    1294             :     /* -------------------------------------------------------------------- */
    1295             :     /*      Cleanup                                                         */
    1296             :     /* -------------------------------------------------------------------- */
    1297         227 :     if (eErr == CE_None)
    1298         226 :         hODS->FlushCache(true);
    1299         227 :     delete hODS;
    1300             : 
    1301         227 :     GTIFFSetThreadLocalInExternalOvr(false);
    1302             : 
    1303         227 :     CPLFree(panOverviewListSorted);
    1304             : 
    1305         227 :     pfnProgress(1.0, nullptr, pProgressData);
    1306             : 
    1307         227 :     return eErr;
    1308             : }

Generated by: LCOV version 1.14