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

Generated by: LCOV version 1.14