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

Generated by: LCOV version 1.14