LCOV - code coverage report
Current view: top level - frmts/gtiff - geotiff.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 473 530 89.2 %
Date: 2025-10-21 22:35:35 Functions: 32 34 94.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  GDAL GeoTIFF support.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_port.h"  // Must be first.
      15             : 
      16             : #include "gtiff.h"
      17             : 
      18             : #include "tiff_common.h"
      19             : 
      20             : #include "cpl_conv.h"
      21             : #include "cpl_error.h"
      22             : #include "gdal.h"
      23             : #include "gdal_frmts.h"
      24             : #include "gdal_mdreader.h"  // RPC_xxx
      25             : #include "gdalsubdatasetinfo.h"
      26             : #include "gtiffdataset.h"
      27             : #include "tiffio.h"
      28             : #include "tif_jxl.h"
      29             : #include "xtiffio.h"
      30             : #include <cctype>
      31             : #include <cmath>
      32             : 
      33             : // Needed to expose WEBP_LOSSLESS option
      34             : #ifdef WEBP_SUPPORT
      35             : #include "webp/encode.h"
      36             : #endif
      37             : 
      38             : #ifdef LERC_SUPPORT
      39             : #include "Lerc_c_api.h"
      40             : #endif
      41             : 
      42             : #define STRINGIFY(x) #x
      43             : #define XSTRINGIFY(x) STRINGIFY(x)
      44             : 
      45             : static thread_local bool bThreadLocalInExternalOvr = false;
      46             : 
      47             : static thread_local int gnThreadLocalLibtiffError = 0;
      48             : 
      49     4299440 : int &GTIFFGetThreadLocalLibtiffError()
      50             : {
      51     4299440 :     return gnThreadLocalLibtiffError;
      52             : }
      53             : 
      54             : /************************************************************************/
      55             : /*                         GTIFFSupportsPredictor()                     */
      56             : /************************************************************************/
      57             : 
      58       65260 : bool GTIFFSupportsPredictor(int nCompression)
      59             : {
      60       52031 :     return nCompression == COMPRESSION_LZW ||
      61      117291 :            nCompression == COMPRESSION_ADOBE_DEFLATE ||
      62       65260 :            nCompression == COMPRESSION_ZSTD;
      63             : }
      64             : 
      65             : /************************************************************************/
      66             : /*                     GTIFFSetThreadLocalInExternalOvr()               */
      67             : /************************************************************************/
      68             : 
      69         422 : void GTIFFSetThreadLocalInExternalOvr(bool b)
      70             : {
      71         422 :     bThreadLocalInExternalOvr = b;
      72         422 : }
      73             : 
      74             : /************************************************************************/
      75             : /*                     GTIFFGetOverviewBlockSize()                      */
      76             : /************************************************************************/
      77             : 
      78         564 : void GTIFFGetOverviewBlockSize(GDALRasterBandH hBand, int *pnBlockXSize,
      79             :                                int *pnBlockYSize, CSLConstList papszOptions,
      80             :                                const char *pszOptionKey)
      81             : {
      82         564 :     const char *pszVal = nullptr;
      83         564 :     const char *pszValItem = nullptr;
      84         564 :     if (papszOptions && pszOptionKey)
      85             :     {
      86          57 :         pszVal = CSLFetchNameValue(papszOptions, pszOptionKey);
      87          57 :         if (pszVal)
      88           1 :             pszValItem = pszOptionKey;
      89             :     }
      90         564 :     if (!pszVal)
      91             :     {
      92         563 :         pszVal = CPLGetConfigOption("GDAL_TIFF_OVR_BLOCKSIZE", nullptr);
      93         563 :         if (pszVal)
      94           8 :             pszValItem = "GDAL_TIFF_OVR_BLOCKSIZE";
      95             :     }
      96         564 :     if (!pszVal)
      97             :     {
      98         555 :         GDALRasterBand *const poBand = GDALRasterBand::FromHandle(hBand);
      99         555 :         poBand->GetBlockSize(pnBlockXSize, pnBlockYSize);
     100         330 :         if (*pnBlockXSize != *pnBlockYSize || *pnBlockXSize < 64 ||
     101         885 :             *pnBlockXSize > 4096 || !CPLIsPowerOfTwo(*pnBlockXSize))
     102             :         {
     103         439 :             *pnBlockXSize = *pnBlockYSize = 128;
     104             :         }
     105             :     }
     106             :     else
     107             :     {
     108           9 :         int nOvrBlockSize = atoi(pszVal);
     109          18 :         if (nOvrBlockSize < 64 || nOvrBlockSize > 4096 ||
     110           9 :             !CPLIsPowerOfTwo(nOvrBlockSize))
     111             :         {
     112           0 :             CPLErrorOnce(CE_Warning, CPLE_NotSupported,
     113             :                          "Wrong value for %s : %s. "
     114             :                          "Should be a power of 2 between 64 and 4096. "
     115             :                          "Defaulting to 128",
     116             :                          pszValItem, pszVal);
     117           0 :             nOvrBlockSize = 128;
     118             :         }
     119             : 
     120           9 :         *pnBlockXSize = nOvrBlockSize;
     121           9 :         *pnBlockYSize = nOvrBlockSize;
     122             :     }
     123         564 : }
     124             : 
     125             : /************************************************************************/
     126             : /*                        GTIFFSetJpegQuality()                         */
     127             : /* Called by GTIFFBuildOverviews() to set the jpeg quality on the IFD   */
     128             : /* of the .ovr file.                                                    */
     129             : /************************************************************************/
     130             : 
     131           4 : void GTIFFSetJpegQuality(GDALDatasetH hGTIFFDS, int nJpegQuality)
     132             : {
     133           4 :     CPLAssert(
     134             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     135             : 
     136           4 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     137           4 :     poDS->m_nJpegQuality = static_cast<signed char>(nJpegQuality);
     138             : 
     139           4 :     poDS->ScanDirectories();
     140             : 
     141           7 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     142           3 :         poDS->m_papoOverviewDS[i]->m_nJpegQuality = poDS->m_nJpegQuality;
     143           4 : }
     144             : 
     145             : /************************************************************************/
     146             : /*                        GTIFFSetWebPLevel()                         */
     147             : /* Called by GTIFFBuildOverviews() to set the jpeg quality on the IFD   */
     148             : /* of the .ovr file.                                                    */
     149             : /************************************************************************/
     150             : 
     151           3 : void GTIFFSetWebPLevel(GDALDatasetH hGTIFFDS, int nWebpLevel)
     152             : {
     153           3 :     CPLAssert(
     154             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     155             : 
     156           3 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     157           3 :     poDS->m_nWebPLevel = static_cast<signed char>(nWebpLevel);
     158             : 
     159           3 :     poDS->ScanDirectories();
     160             : 
     161           6 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     162           3 :         poDS->m_papoOverviewDS[i]->m_nWebPLevel = poDS->m_nWebPLevel;
     163           3 : }
     164             : 
     165             : /************************************************************************/
     166             : /*                       GTIFFSetWebPLossless()                         */
     167             : /* Called by GTIFFBuildOverviews() to set webp lossless on the IFD      */
     168             : /* of the .ovr file.                                                    */
     169             : /************************************************************************/
     170             : 
     171           1 : void GTIFFSetWebPLossless(GDALDatasetH hGTIFFDS, bool bWebpLossless)
     172             : {
     173           1 :     CPLAssert(
     174             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     175             : 
     176           1 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     177           1 :     poDS->m_bWebPLossless = bWebpLossless;
     178             : 
     179           1 :     poDS->ScanDirectories();
     180             : 
     181           1 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     182           0 :         poDS->m_papoOverviewDS[i]->m_bWebPLossless = poDS->m_bWebPLossless;
     183           1 : }
     184             : 
     185             : /************************************************************************/
     186             : /*                     GTIFFSetJpegTablesMode()                         */
     187             : /* Called by GTIFFBuildOverviews() to set the jpeg tables mode on the   */
     188             : /* of the .ovr file.                                                    */
     189             : /************************************************************************/
     190             : 
     191           0 : void GTIFFSetJpegTablesMode(GDALDatasetH hGTIFFDS, int nJpegTablesMode)
     192             : {
     193           0 :     CPLAssert(
     194             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     195             : 
     196           0 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     197           0 :     poDS->m_nJpegTablesMode = static_cast<signed char>(nJpegTablesMode);
     198             : 
     199           0 :     poDS->ScanDirectories();
     200             : 
     201           0 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     202           0 :         poDS->m_papoOverviewDS[i]->m_nJpegTablesMode = poDS->m_nJpegTablesMode;
     203           0 : }
     204             : 
     205             : /************************************************************************/
     206             : /*                        GTIFFSetZLevel()                              */
     207             : /* Called by GTIFFBuildOverviews() to set the deflate level on the IFD  */
     208             : /* of the .ovr file.                                                    */
     209             : /************************************************************************/
     210             : 
     211           2 : void GTIFFSetZLevel(GDALDatasetH hGTIFFDS, int nZLevel)
     212             : {
     213           2 :     CPLAssert(
     214             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     215             : 
     216           2 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     217           2 :     poDS->m_nZLevel = static_cast<signed char>(nZLevel);
     218             : 
     219           2 :     poDS->ScanDirectories();
     220             : 
     221           4 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     222           2 :         poDS->m_papoOverviewDS[i]->m_nZLevel = poDS->m_nZLevel;
     223           2 : }
     224             : 
     225             : /************************************************************************/
     226             : /*                        GTIFFSetZSTDLevel()                           */
     227             : /* Called by GTIFFBuildOverviews() to set the ZSTD level on the IFD     */
     228             : /* of the .ovr file.                                                    */
     229             : /************************************************************************/
     230             : 
     231           2 : void GTIFFSetZSTDLevel(GDALDatasetH hGTIFFDS, int nZSTDLevel)
     232             : {
     233           2 :     CPLAssert(
     234             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     235             : 
     236           2 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     237           2 :     poDS->m_nZSTDLevel = static_cast<signed char>(nZSTDLevel);
     238             : 
     239           2 :     poDS->ScanDirectories();
     240             : 
     241           4 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     242           2 :         poDS->m_papoOverviewDS[i]->m_nZSTDLevel = poDS->m_nZSTDLevel;
     243           2 : }
     244             : 
     245             : /************************************************************************/
     246             : /*                        GTIFFSetMaxZError()                           */
     247             : /* Called by GTIFFBuildOverviews() to set the Lerc max error on the IFD */
     248             : /* of the .ovr file.                                                    */
     249             : /************************************************************************/
     250             : 
     251          10 : void GTIFFSetMaxZError(GDALDatasetH hGTIFFDS, double dfMaxZError)
     252             : {
     253          10 :     CPLAssert(
     254             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     255             : 
     256          10 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     257          10 :     poDS->m_dfMaxZError = dfMaxZError;
     258          10 :     poDS->m_dfMaxZErrorOverview = dfMaxZError;
     259             : 
     260          10 :     poDS->ScanDirectories();
     261             : 
     262          20 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     263             :     {
     264          10 :         poDS->m_papoOverviewDS[i]->m_dfMaxZError = poDS->m_dfMaxZError;
     265          10 :         poDS->m_papoOverviewDS[i]->m_dfMaxZErrorOverview =
     266          10 :             poDS->m_dfMaxZErrorOverview;
     267             :     }
     268          10 : }
     269             : 
     270             : #if HAVE_JXL
     271             : 
     272             : /************************************************************************/
     273             : /*                       GTIFFSetJXLLossless()                          */
     274             : /* Called by GTIFFBuildOverviews() to set the JXL lossyness on the IFD  */
     275             : /* of the .ovr file.                                                    */
     276             : /************************************************************************/
     277             : 
     278           5 : void GTIFFSetJXLLossless(GDALDatasetH hGTIFFDS, bool bIsLossless)
     279             : {
     280           5 :     CPLAssert(
     281             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     282             : 
     283           5 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     284           5 :     poDS->m_bJXLLossless = bIsLossless;
     285             : 
     286           5 :     poDS->ScanDirectories();
     287             : 
     288           5 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     289             :     {
     290           0 :         poDS->m_papoOverviewDS[i]->m_bJXLLossless = poDS->m_bJXLLossless;
     291             :     }
     292           5 : }
     293             : 
     294             : /************************************************************************/
     295             : /*                       GTIFFSetJXLEffort()                            */
     296             : /* Called by GTIFFBuildOverviews() to set the JXL effort on the IFD     */
     297             : /* of the .ovr file.                                                    */
     298             : /************************************************************************/
     299             : 
     300           0 : void GTIFFSetJXLEffort(GDALDatasetH hGTIFFDS, int nEffort)
     301             : {
     302           0 :     CPLAssert(
     303             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     304             : 
     305           0 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     306           0 :     poDS->m_nJXLEffort = nEffort;
     307             : 
     308           0 :     poDS->ScanDirectories();
     309             : 
     310           0 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     311             :     {
     312           0 :         poDS->m_papoOverviewDS[i]->m_nJXLEffort = poDS->m_nJXLEffort;
     313             :     }
     314           0 : }
     315             : 
     316             : /************************************************************************/
     317             : /*                       GTIFFSetJXLDistance()                          */
     318             : /* Called by GTIFFBuildOverviews() to set the JXL distance on the IFD   */
     319             : /* of the .ovr file.                                                    */
     320             : /************************************************************************/
     321             : 
     322           1 : void GTIFFSetJXLDistance(GDALDatasetH hGTIFFDS, float fDistance)
     323             : {
     324           1 :     CPLAssert(
     325             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     326             : 
     327           1 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     328           1 :     poDS->m_fJXLDistance = fDistance;
     329             : 
     330           1 :     poDS->ScanDirectories();
     331             : 
     332           1 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     333             :     {
     334           0 :         poDS->m_papoOverviewDS[i]->m_fJXLDistance = poDS->m_fJXLDistance;
     335             :     }
     336           1 : }
     337             : 
     338             : /************************************************************************/
     339             : /*                     GTIFFSetJXLAlphaDistance()                       */
     340             : /* Called by GTIFFBuildOverviews() to set the JXL alpha distance on the */
     341             : /* IFD of the .ovr file.                                                */
     342             : /************************************************************************/
     343             : 
     344           1 : void GTIFFSetJXLAlphaDistance(GDALDatasetH hGTIFFDS, float fAlphaDistance)
     345             : {
     346           1 :     CPLAssert(
     347             :         EQUAL(GDALGetDriverShortName(GDALGetDatasetDriver(hGTIFFDS)), "GTIFF"));
     348             : 
     349           1 :     GTiffDataset *const poDS = static_cast<GTiffDataset *>(hGTIFFDS);
     350           1 :     poDS->m_fJXLAlphaDistance = fAlphaDistance;
     351             : 
     352           1 :     poDS->ScanDirectories();
     353             : 
     354           1 :     for (int i = 0; i < poDS->m_nOverviewCount; ++i)
     355             :     {
     356           0 :         poDS->m_papoOverviewDS[i]->m_fJXLAlphaDistance =
     357           0 :             poDS->m_fJXLAlphaDistance;
     358             :     }
     359           1 : }
     360             : 
     361             : #endif  // HAVE_JXL
     362             : 
     363             : /************************************************************************/
     364             : /*                         GTiffGetAlphaValue()                         */
     365             : /************************************************************************/
     366             : 
     367        2637 : uint16_t GTiffGetAlphaValue(const char *pszValue, uint16_t nDefault)
     368             : {
     369        2637 :     if (pszValue == nullptr)
     370        2613 :         return nDefault;
     371          24 :     if (EQUAL(pszValue, "YES"))
     372          14 :         return DEFAULT_ALPHA_TYPE;
     373          10 :     if (EQUAL(pszValue, "PREMULTIPLIED"))
     374           5 :         return EXTRASAMPLE_ASSOCALPHA;
     375           5 :     if (EQUAL(pszValue, "NON-PREMULTIPLIED"))
     376           0 :         return EXTRASAMPLE_UNASSALPHA;
     377           5 :     if (EQUAL(pszValue, "NO") || EQUAL(pszValue, "UNSPECIFIED"))
     378           5 :         return EXTRASAMPLE_UNSPECIFIED;
     379             : 
     380           0 :     return nDefault;
     381             : }
     382             : 
     383             : /************************************************************************/
     384             : /*                 GTIFFIsStandardColorInterpretation()                 */
     385             : /************************************************************************/
     386             : 
     387        7966 : bool GTIFFIsStandardColorInterpretation(GDALDatasetH hSrcDS,
     388             :                                         uint16_t nPhotometric,
     389             :                                         CSLConstList papszCreationOptions)
     390             : {
     391        7966 :     GDALDataset *poSrcDS = GDALDataset::FromHandle(hSrcDS);
     392        7966 :     bool bStandardColorInterp = true;
     393        7966 :     if (nPhotometric == PHOTOMETRIC_MINISBLACK)
     394             :     {
     395      308770 :         for (int i = 0; i < poSrcDS->GetRasterCount(); ++i)
     396             :         {
     397             :             const GDALColorInterp eInterp =
     398      302545 :                 poSrcDS->GetRasterBand(i + 1)->GetColorInterpretation();
     399      302545 :             if (!(eInterp == GCI_GrayIndex || eInterp == GCI_Undefined ||
     400         106 :                   (i > 0 && eInterp == GCI_AlphaBand)))
     401             :             {
     402          43 :                 bStandardColorInterp = false;
     403          43 :                 break;
     404             :             }
     405             :         }
     406             :     }
     407        1698 :     else if (nPhotometric == PHOTOMETRIC_PALETTE)
     408             :     {
     409          53 :         bStandardColorInterp =
     410          53 :             poSrcDS->GetRasterBand(1)->GetColorInterpretation() ==
     411             :             GCI_PaletteIndex;
     412             :     }
     413        1645 :     else if (nPhotometric == PHOTOMETRIC_RGB)
     414             :     {
     415        1575 :         int iStart = 0;
     416        1575 :         if (EQUAL(CSLFetchNameValueDef(papszCreationOptions, "PHOTOMETRIC", ""),
     417             :                   "RGB"))
     418             :         {
     419          51 :             iStart = 3;
     420          73 :             if (poSrcDS->GetRasterCount() == 4 &&
     421          22 :                 CSLFetchNameValue(papszCreationOptions, "ALPHA") != nullptr)
     422             :             {
     423           5 :                 iStart = 4;
     424             :             }
     425             :         }
     426        6263 :         for (int i = iStart; i < poSrcDS->GetRasterCount(); ++i)
     427             :         {
     428             :             const GDALColorInterp eInterp =
     429        4733 :                 poSrcDS->GetRasterBand(i + 1)->GetColorInterpretation();
     430        5026 :             if (!((i == 0 && eInterp == GCI_RedBand) ||
     431        3253 :                   (i == 1 && eInterp == GCI_GreenBand) ||
     432        1480 :                   (i == 2 && eInterp == GCI_BlueBand) ||
     433         249 :                   (i >= 3 &&
     434         206 :                    (eInterp == GCI_Undefined || eInterp == GCI_AlphaBand))))
     435             :             {
     436          45 :                 bStandardColorInterp = false;
     437          45 :                 break;
     438             :             }
     439             :         }
     440             :     }
     441         131 :     else if (nPhotometric == PHOTOMETRIC_YCBCR &&
     442          61 :              poSrcDS->GetRasterCount() == 3)
     443             :     {
     444             :         // do nothing
     445             :     }
     446             :     else
     447             :     {
     448           9 :         bStandardColorInterp = false;
     449             :     }
     450        7966 :     return bStandardColorInterp;
     451             : }
     452             : 
     453             : /************************************************************************/
     454             : /*                     GTiffDatasetWriteRPCTag()                        */
     455             : /*                                                                      */
     456             : /*      Format a TAG according to:                                      */
     457             : /*                                                                      */
     458             : /*      http://geotiff.maptools.org/rpc_prop.html                       */
     459             : /************************************************************************/
     460             : 
     461          12 : void GTiffDatasetWriteRPCTag(TIFF *hTIFF, char **papszRPCMD)
     462             : 
     463             : {
     464             :     GDALRPCInfoV2 sRPC;
     465             : 
     466          12 :     if (!GDALExtractRPCInfoV2(papszRPCMD, &sRPC))
     467           0 :         return;
     468             : 
     469          12 :     double adfRPCTag[92] = {};
     470          12 :     adfRPCTag[0] = sRPC.dfERR_BIAS;  // Error Bias
     471          12 :     adfRPCTag[1] = sRPC.dfERR_RAND;  // Error Random
     472             : 
     473          12 :     adfRPCTag[2] = sRPC.dfLINE_OFF;
     474          12 :     adfRPCTag[3] = sRPC.dfSAMP_OFF;
     475          12 :     adfRPCTag[4] = sRPC.dfLAT_OFF;
     476          12 :     adfRPCTag[5] = sRPC.dfLONG_OFF;
     477          12 :     adfRPCTag[6] = sRPC.dfHEIGHT_OFF;
     478          12 :     adfRPCTag[7] = sRPC.dfLINE_SCALE;
     479          12 :     adfRPCTag[8] = sRPC.dfSAMP_SCALE;
     480          12 :     adfRPCTag[9] = sRPC.dfLAT_SCALE;
     481          12 :     adfRPCTag[10] = sRPC.dfLONG_SCALE;
     482          12 :     adfRPCTag[11] = sRPC.dfHEIGHT_SCALE;
     483             : 
     484          12 :     memcpy(adfRPCTag + 12, sRPC.adfLINE_NUM_COEFF, sizeof(double) * 20);
     485          12 :     memcpy(adfRPCTag + 32, sRPC.adfLINE_DEN_COEFF, sizeof(double) * 20);
     486          12 :     memcpy(adfRPCTag + 52, sRPC.adfSAMP_NUM_COEFF, sizeof(double) * 20);
     487          12 :     memcpy(adfRPCTag + 72, sRPC.adfSAMP_DEN_COEFF, sizeof(double) * 20);
     488             : 
     489          12 :     TIFFSetField(hTIFF, TIFFTAG_RPCCOEFFICIENT, 92, adfRPCTag);
     490             : }
     491             : 
     492             : /************************************************************************/
     493             : /*                             ReadRPCTag()                             */
     494             : /*                                                                      */
     495             : /*      Format a TAG according to:                                      */
     496             : /*                                                                      */
     497             : /*      http://geotiff.maptools.org/rpc_prop.html                       */
     498             : /************************************************************************/
     499             : 
     500        5240 : char **GTiffDatasetReadRPCTag(TIFF *hTIFF)
     501             : 
     502             : {
     503        5240 :     double *padfRPCTag = nullptr;
     504             :     uint16_t nCount;
     505             : 
     506        5274 :     if (!TIFFGetField(hTIFF, TIFFTAG_RPCCOEFFICIENT, &nCount, &padfRPCTag) ||
     507          34 :         nCount != 92)
     508        5206 :         return nullptr;
     509             : 
     510          34 :     return gdal::tiff_common::TIFFRPCTagToRPCMetadata(padfRPCTag).StealList();
     511             : }
     512             : 
     513             : /************************************************************************/
     514             : /*                  GTiffFormatGDALNoDataTagValue()                     */
     515             : /************************************************************************/
     516             : 
     517         506 : CPLString GTiffFormatGDALNoDataTagValue(double dfNoData)
     518             : {
     519         506 :     CPLString osVal;
     520         506 :     if (std::isnan(dfNoData))
     521          11 :         osVal = "nan";
     522             :     else
     523         495 :         osVal.Printf("%.17g", dfNoData);
     524         506 :     return osVal;
     525             : }
     526             : 
     527             : /************************************************************************/
     528             : /*                       GTIFFUpdatePhotometric()                      */
     529             : /************************************************************************/
     530             : 
     531         548 : bool GTIFFUpdatePhotometric(const char *pszPhotometric,
     532             :                             const char *pszOptionKey, int nCompression,
     533             :                             const char *pszInterleave, int nBands,
     534             :                             uint16_t &nPhotometric, uint16_t &nPlanarConfig)
     535             : {
     536         548 :     if (pszPhotometric != nullptr && pszPhotometric[0] != '\0')
     537             :     {
     538          17 :         if (EQUAL(pszPhotometric, "MINISBLACK"))
     539           0 :             nPhotometric = PHOTOMETRIC_MINISBLACK;
     540          17 :         else if (EQUAL(pszPhotometric, "MINISWHITE"))
     541           0 :             nPhotometric = PHOTOMETRIC_MINISWHITE;
     542          17 :         else if (EQUAL(pszPhotometric, "RGB"))
     543             :         {
     544           0 :             nPhotometric = PHOTOMETRIC_RGB;
     545             :         }
     546          17 :         else if (EQUAL(pszPhotometric, "CMYK"))
     547             :         {
     548           0 :             nPhotometric = PHOTOMETRIC_SEPARATED;
     549             :         }
     550          17 :         else if (EQUAL(pszPhotometric, "YCBCR"))
     551             :         {
     552          17 :             nPhotometric = PHOTOMETRIC_YCBCR;
     553             : 
     554             :             // Because of subsampling, setting YCBCR without JPEG compression
     555             :             // leads to a crash currently. Would need to make
     556             :             // GTiffRasterBand::IWriteBlock() aware of subsampling so that it
     557             :             // doesn't overrun buffer size returned by libtiff.
     558          17 :             if (nCompression != COMPRESSION_JPEG)
     559             :             {
     560           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     561             :                          "Currently, %s=YCBCR requires JPEG compression",
     562             :                          pszOptionKey);
     563           0 :                 return false;
     564             :             }
     565             : 
     566          17 :             if (pszInterleave != nullptr && pszInterleave[0] != '\0' &&
     567           2 :                 nPlanarConfig == PLANARCONFIG_SEPARATE)
     568             :             {
     569           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     570             :                          "%s=YCBCR requires PIXEL interleaving", pszOptionKey);
     571           0 :                 return false;
     572             :             }
     573             :             else
     574             :             {
     575          17 :                 nPlanarConfig = PLANARCONFIG_CONTIG;
     576             :             }
     577             : 
     578             :             // YCBCR strictly requires 3 bands. Not less, not more
     579             :             // Issue an explicit error message as libtiff one is a bit cryptic:
     580             :             // JPEGLib:Bogus input colorspace.
     581          17 :             if (nBands != 3)
     582             :             {
     583           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     584             :                          "%s=YCBCR requires a source raster "
     585             :                          "with only 3 bands (RGB)",
     586             :                          pszOptionKey);
     587           0 :                 return false;
     588             :             }
     589             :         }
     590           0 :         else if (EQUAL(pszPhotometric, "CIELAB"))
     591             :         {
     592           0 :             nPhotometric = PHOTOMETRIC_CIELAB;
     593             :         }
     594           0 :         else if (EQUAL(pszPhotometric, "ICCLAB"))
     595             :         {
     596           0 :             nPhotometric = PHOTOMETRIC_ICCLAB;
     597             :         }
     598           0 :         else if (EQUAL(pszPhotometric, "ITULAB"))
     599             :         {
     600           0 :             nPhotometric = PHOTOMETRIC_ITULAB;
     601             :         }
     602             :         else
     603             :         {
     604           0 :             CPLError(CE_Warning, CPLE_IllegalArg,
     605             :                      "%s=%s value not recognised, ignoring.", pszOptionKey,
     606             :                      pszPhotometric);
     607             :         }
     608             :     }
     609         548 :     return true;
     610             : }
     611             : 
     612             : /************************************************************************/
     613             : /*                      GTiffWriteJPEGTables()                          */
     614             : /*                                                                      */
     615             : /*      Sets the TIFFTAG_JPEGTABLES (and TIFFTAG_REFERENCEBLACKWHITE)   */
     616             : /*      tags immediately, instead of relying on the TIFF JPEG codec     */
     617             : /*      to write them when it starts compressing imagery. This avoids   */
     618             : /*      an IFD rewrite at the end of the file.                          */
     619             : /*      Must be used after having set TIFFTAG_SAMPLESPERPIXEL,          */
     620             : /*      TIFFTAG_BITSPERSAMPLE.                                          */
     621             : /************************************************************************/
     622             : 
     623        1069 : void GTiffWriteJPEGTables(TIFF *hTIFF, const char *pszPhotometric,
     624             :                           const char *pszJPEGQuality,
     625             :                           const char *pszJPEGTablesMode)
     626             : {
     627             :     // This trick
     628             :     // creates a temporary in-memory file and fetches its JPEG tables so that
     629             :     // we can directly set them, before tif_jpeg.c compute them at the first
     630             :     // strip/tile writing, which is too late, since we have already crystallized
     631             :     // the directory. This way we avoid a directory rewriting.
     632        1069 :     uint16_t nBands = 0;
     633        1069 :     if (!TIFFGetField(hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nBands))
     634           0 :         nBands = 1;
     635             : 
     636        1069 :     uint16_t l_nBitsPerSample = 0;
     637        1069 :     if (!TIFFGetField(hTIFF, TIFFTAG_BITSPERSAMPLE, &(l_nBitsPerSample)))
     638           0 :         l_nBitsPerSample = 1;
     639             : 
     640             :     const CPLString osTmpFilenameIn(
     641        2138 :         VSIMemGenerateHiddenFilename("gtiffdataset_jpg_tmp"));
     642        1069 :     VSILFILE *fpTmp = nullptr;
     643        2138 :     CPLString osTmp;
     644        1069 :     char **papszLocalParameters = nullptr;
     645        1069 :     const int nInMemImageWidth = 16;
     646        1069 :     const int nInMemImageHeight = 16;
     647             :     papszLocalParameters =
     648        1069 :         CSLSetNameValue(papszLocalParameters, "COMPRESS", "JPEG");
     649             :     papszLocalParameters =
     650        1069 :         CSLSetNameValue(papszLocalParameters, "JPEG_QUALITY", pszJPEGQuality);
     651        1069 :     if (nBands <= 4)
     652             :     {
     653        1069 :         papszLocalParameters = CSLSetNameValue(papszLocalParameters,
     654             :                                                "PHOTOMETRIC", pszPhotometric);
     655             :     }
     656        1069 :     papszLocalParameters = CSLSetNameValue(papszLocalParameters, "BLOCKYSIZE",
     657             :                                            CPLSPrintf("%u", nInMemImageHeight));
     658        1069 :     papszLocalParameters = CSLSetNameValue(papszLocalParameters, "NBITS",
     659             :                                            CPLSPrintf("%u", l_nBitsPerSample));
     660        1069 :     papszLocalParameters = CSLSetNameValue(papszLocalParameters,
     661             :                                            "JPEGTABLESMODE", pszJPEGTablesMode);
     662             :     papszLocalParameters =
     663        1069 :         CSLSetNameValue(papszLocalParameters, "WRITE_JPEGTABLE_TAG", "NO");
     664             : 
     665             :     bool bTileInterleaving;
     666             :     TIFF *hTIFFTmp =
     667        2138 :         GTiffDataset::CreateLL(osTmpFilenameIn, nInMemImageWidth,
     668        1069 :                                nInMemImageHeight, (nBands <= 4) ? nBands : 1,
     669        1069 :                                (l_nBitsPerSample <= 8) ? GDT_Byte : GDT_UInt16,
     670             :                                0.0, 0, papszLocalParameters, &fpTmp, osTmp,
     671             :                                /* bCreateCopy=*/false, bTileInterleaving);
     672        1069 :     CSLDestroy(papszLocalParameters);
     673        1069 :     if (hTIFFTmp)
     674             :     {
     675        1069 :         uint16_t l_nPhotometric = 0;
     676        1069 :         int nJpegTablesModeIn = 0;
     677        1069 :         TIFFGetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, &(l_nPhotometric));
     678        1069 :         TIFFGetField(hTIFFTmp, TIFFTAG_JPEGTABLESMODE, &nJpegTablesModeIn);
     679        1069 :         TIFFWriteCheck(hTIFFTmp, FALSE, "CreateLL");
     680        1069 :         TIFFWriteDirectory(hTIFFTmp);
     681        1069 :         TIFFSetDirectory(hTIFFTmp, 0);
     682             :         // Now, reset quality and jpegcolormode.
     683        1069 :         const int l_nJpegQuality = pszJPEGQuality ? atoi(pszJPEGQuality) : 0;
     684        1069 :         if (l_nJpegQuality > 0)
     685         967 :             TIFFSetField(hTIFFTmp, TIFFTAG_JPEGQUALITY, l_nJpegQuality);
     686        1453 :         if (l_nPhotometric == PHOTOMETRIC_YCBCR &&
     687         384 :             CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
     688             :         {
     689         384 :             TIFFSetField(hTIFFTmp, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
     690             :         }
     691        1069 :         if (nJpegTablesModeIn >= 0)
     692        1065 :             TIFFSetField(hTIFFTmp, TIFFTAG_JPEGTABLESMODE, nJpegTablesModeIn);
     693             : 
     694        1069 :         GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nInMemImageWidth) *
     695             :                                 nInMemImageHeight *
     696        1069 :                                 ((nBands <= 4) ? nBands : 1);
     697        1069 :         if (l_nBitsPerSample == 12)
     698         590 :             nBlockSize = (nBlockSize * 3) / 2;
     699        1069 :         std::vector<GByte> abyZeroData(nBlockSize, 0);
     700        1069 :         TIFFWriteEncodedStrip(hTIFFTmp, 0, &abyZeroData[0], nBlockSize);
     701             : 
     702        1069 :         uint32_t nJPEGTableSize = 0;
     703        1069 :         void *pJPEGTable = nullptr;
     704        1069 :         if (TIFFGetField(hTIFFTmp, TIFFTAG_JPEGTABLES, &nJPEGTableSize,
     705        1069 :                          &pJPEGTable))
     706        1066 :             TIFFSetField(hTIFF, TIFFTAG_JPEGTABLES, nJPEGTableSize, pJPEGTable);
     707             : 
     708        1069 :         float *ref = nullptr;
     709        1069 :         if (TIFFGetField(hTIFFTmp, TIFFTAG_REFERENCEBLACKWHITE, &ref))
     710         384 :             TIFFSetField(hTIFF, TIFFTAG_REFERENCEBLACKWHITE, ref);
     711             : 
     712        1069 :         XTIFFClose(hTIFFTmp);
     713        1069 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
     714             :     }
     715        1069 :     VSIUnlink(osTmpFilenameIn);
     716        1069 : }
     717             : 
     718             : #if !defined(SUPPORTS_LIBTIFF_OPEN_OPTIONS)
     719             : 
     720             : /************************************************************************/
     721             : /*                        GTiffWarningHandler()                         */
     722             : /************************************************************************/
     723             : static void GTiffWarningHandler(const char *module, const char *fmt, va_list ap)
     724             : {
     725             :     if (GTIFFGetThreadLocalLibtiffError() > 0)
     726             :     {
     727             :         GTIFFGetThreadLocalLibtiffError()++;
     728             :         if (GTIFFGetThreadLocalLibtiffError() > 10)
     729             :             return;
     730             :     }
     731             : 
     732             :     if (strstr(fmt, "nknown field") != nullptr)
     733             :         return;
     734             : 
     735             :     char *pszModFmt = gdal::tiff_common::PrepareTIFFErrorFormat(module, fmt);
     736             :     if (strstr(fmt, "does not end in null byte") != nullptr)
     737             :     {
     738             :         CPLString osMsg;
     739             :         osMsg.vPrintf(pszModFmt, ap);
     740             :         CPLDebug("GTiff", "%s", osMsg.c_str());
     741             :     }
     742             :     else
     743             :     {
     744             :         CPLErrorV(CE_Warning, CPLE_AppDefined, pszModFmt, ap);
     745             :     }
     746             :     CPLFree(pszModFmt);
     747             :     return;
     748             : }
     749             : 
     750             : /************************************************************************/
     751             : /*                         GTiffErrorHandler()                          */
     752             : /************************************************************************/
     753             : static void GTiffErrorHandler(const char *module, const char *fmt, va_list ap)
     754             : {
     755             :     if (GTIFFGetThreadLocalLibtiffError() > 0)
     756             :     {
     757             :         GTIFFGetThreadLocalLibtiffError()++;
     758             :         if (GTIFFGetThreadLocalLibtiffError() > 10)
     759             :             return;
     760             :     }
     761             : 
     762             :     if (strcmp(fmt, "Maximum TIFF file size exceeded") == 0)
     763             :     {
     764             :         if (bThreadLocalInExternalOvr)
     765             :             fmt = "Maximum TIFF file size exceeded. "
     766             :                   "Use --config BIGTIFF_OVERVIEW YES configuration option.";
     767             :         else
     768             :             fmt = "Maximum TIFF file size exceeded. "
     769             :                   "Use BIGTIFF=YES creation option.";
     770             :     }
     771             : 
     772             :     char *pszModFmt = gdal::tiff_common::PrepareTIFFErrorFormat(module, fmt);
     773             :     CPLErrorV(CE_Failure, CPLE_AppDefined, pszModFmt, ap);
     774             :     CPLFree(pszModFmt);
     775             :     return;
     776             : }
     777             : #else
     778             : 
     779             : /************************************************************************/
     780             : /*                      GTiffWarningHandlerExt()                        */
     781             : /************************************************************************/
     782             : extern int GTiffWarningHandlerExt(TIFF *tif, void *user_data,
     783             :                                   const char *module, const char *fmt,
     784             :                                   va_list ap);
     785             : 
     786         326 : int GTiffWarningHandlerExt(TIFF *tif, void *user_data, const char *module,
     787             :                            const char *fmt, va_list ap)
     788             : {
     789             :     (void)tif;
     790             :     (void)user_data;
     791         326 :     auto &nLibtiffErrors = GTIFFGetThreadLocalLibtiffError();
     792             :     // cppcheck-suppress knownConditionTrueFalse
     793         326 :     if (nLibtiffErrors > 0)
     794             :     {
     795         217 :         nLibtiffErrors++;
     796             :         // cppcheck-suppress knownConditionTrueFalse
     797         217 :         if (nLibtiffErrors > 10)
     798           0 :             return 1;
     799             :     }
     800             : 
     801         326 :     if (strstr(fmt, "nknown field") != nullptr)
     802           0 :         return 1;
     803             : 
     804         326 :     char *pszModFmt = gdal::tiff_common::PrepareTIFFErrorFormat(module, fmt);
     805         326 :     if (strstr(fmt, "does not end in null byte") != nullptr)
     806             :     {
     807           2 :         CPLString osMsg;
     808           1 :         osMsg.vPrintf(pszModFmt, ap);
     809           1 :         CPLDebug("GTiff", "%s", osMsg.c_str());
     810             :     }
     811             :     else
     812             :     {
     813         325 :         CPLErrorV(CE_Warning, CPLE_AppDefined, pszModFmt, ap);
     814             :     }
     815         326 :     CPLFree(pszModFmt);
     816         326 :     return 1;
     817             : }
     818             : 
     819             : /************************************************************************/
     820             : /*                       GTiffErrorHandlerExt()                         */
     821             : /************************************************************************/
     822             : extern int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
     823             :                                 const char *fmt, va_list ap);
     824             : 
     825         248 : int GTiffErrorHandlerExt(TIFF *tif, void *user_data, const char *module,
     826             :                          const char *fmt, va_list ap)
     827             : {
     828             :     (void)tif;
     829             :     (void)user_data;
     830         248 :     auto &nLibtiffErrors = GTIFFGetThreadLocalLibtiffError();
     831             :     // cppcheck-suppress knownConditionTrueFalse
     832         248 :     if (nLibtiffErrors > 0)
     833             :     {
     834         110 :         nLibtiffErrors++;
     835             :         // cppcheck-suppress knownConditionTrueFalse
     836         110 :         if (nLibtiffErrors > 10)
     837           0 :             return 1;
     838             :     }
     839             : 
     840         248 :     if (strcmp(fmt, "Maximum TIFF file size exceeded") == 0)
     841             :     {
     842           0 :         if (bThreadLocalInExternalOvr)
     843           0 :             fmt = "Maximum TIFF file size exceeded. "
     844             :                   "Use --config BIGTIFF_OVERVIEW YES configuration option.";
     845             :         else
     846           0 :             fmt = "Maximum TIFF file size exceeded. "
     847             :                   "Use BIGTIFF=YES creation option.";
     848             :     }
     849             : 
     850         248 :     char *pszModFmt = gdal::tiff_common::PrepareTIFFErrorFormat(module, fmt);
     851         248 :     CPLErrorV(CE_Failure, CPLE_AppDefined, pszModFmt, ap);
     852         248 :     CPLFree(pszModFmt);
     853         248 :     return 1;
     854             : }
     855             : 
     856             : #endif
     857             : 
     858             : /************************************************************************/
     859             : /*                          GTiffTagExtender()                          */
     860             : /*                                                                      */
     861             : /*      Install tags specially known to GDAL.                           */
     862             : /************************************************************************/
     863             : 
     864             : static TIFFExtendProc _ParentExtender = nullptr;
     865             : 
     866      134012 : static void GTiffTagExtender(TIFF *tif)
     867             : 
     868             : {
     869      134012 :     const TIFFFieldInfo xtiffFieldInfo[] = {
     870             :         {TIFFTAG_GDAL_METADATA, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE,
     871             :          const_cast<char *>("GDALMetadata")},
     872             :         {TIFFTAG_GDAL_NODATA, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE,
     873             :          const_cast<char *>("GDALNoDataValue")},
     874             :         {TIFFTAG_RPCCOEFFICIENT, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE,
     875             :          const_cast<char *>("RPCCoefficient")},
     876             :         {TIFFTAG_TIFF_RSID, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE,
     877             :          const_cast<char *>("TIFF_RSID")},
     878             :         {TIFFTAG_GEO_METADATA, TIFF_VARIABLE2, TIFF_VARIABLE2, TIFF_BYTE,
     879             :          FIELD_CUSTOM, TRUE, TRUE, const_cast<char *>("GEO_METADATA")}};
     880             : 
     881      134012 :     if (_ParentExtender)
     882           0 :         (*_ParentExtender)(tif);
     883             : 
     884      134012 :     TIFFMergeFieldInfo(tif, xtiffFieldInfo,
     885             :                        sizeof(xtiffFieldInfo) / sizeof(xtiffFieldInfo[0]));
     886      134006 : }
     887             : 
     888             : /************************************************************************/
     889             : /*                          GTiffOneTimeInit()                          */
     890             : /*                                                                      */
     891             : /*      This is stuff that is initialized for the TIFF library just     */
     892             : /*      once.  We deliberately defer the initialization till the        */
     893             : /*      first time we are likely to call into libtiff to avoid          */
     894             : /*      unnecessary paging in of the library for GDAL apps that         */
     895             : /*      don't use it.                                                   */
     896             : /************************************************************************/
     897             : 
     898             : static std::mutex oDeleteMutex;
     899             : #ifdef HAVE_JXL
     900             : static TIFFCodec *pJXLCodec = nullptr;
     901             : static TIFFCodec *pJXLCodecDNG17 = nullptr;
     902             : #endif
     903             : 
     904       34236 : void GTiffOneTimeInit()
     905             : 
     906             : {
     907       34236 :     std::lock_guard<std::mutex> oLock(oDeleteMutex);
     908             : 
     909             :     static bool bOneTimeInitDone = false;
     910       34236 :     if (bOneTimeInitDone)
     911       33561 :         return;
     912             : 
     913         675 :     bOneTimeInitDone = true;
     914             : 
     915             : #ifdef HAVE_JXL
     916         675 :     if (pJXLCodec == nullptr)
     917             :     {
     918         675 :         pJXLCodec = TIFFRegisterCODEC(COMPRESSION_JXL, "JXL", TIFFInitJXL);
     919         675 :         pJXLCodecDNG17 =
     920         675 :             TIFFRegisterCODEC(COMPRESSION_JXL_DNG_1_7, "JXL", TIFFInitJXL);
     921             :     }
     922             : #endif
     923             : 
     924         675 :     _ParentExtender = TIFFSetTagExtender(GTiffTagExtender);
     925             : 
     926             : #if !defined(SUPPORTS_LIBTIFF_OPEN_OPTIONS)
     927             :     TIFFSetWarningHandler(GTiffWarningHandler);
     928             :     TIFFSetErrorHandler(GTiffErrorHandler);
     929             : #endif
     930             : 
     931         675 :     LibgeotiffOneTimeInit();
     932             : }
     933             : 
     934             : /************************************************************************/
     935             : /*                        GDALDeregister_GTiff()                        */
     936             : /************************************************************************/
     937             : 
     938        1124 : static void GDALDeregister_GTiff(GDALDriver *)
     939             : 
     940             : {
     941             : #ifdef HAVE_JXL
     942        1124 :     if (pJXLCodec)
     943         434 :         TIFFUnRegisterCODEC(pJXLCodec);
     944        1124 :     pJXLCodec = nullptr;
     945        1124 :     if (pJXLCodecDNG17)
     946         434 :         TIFFUnRegisterCODEC(pJXLCodecDNG17);
     947        1124 :     pJXLCodecDNG17 = nullptr;
     948             : #endif
     949        1124 : }
     950             : 
     951             : #define COMPRESSION_ENTRY(x, bWriteSupported)                                  \
     952             :     {                                                                          \
     953             :         COMPRESSION_##x, STRINGIFY(x), bWriteSupported                         \
     954             :     }
     955             : 
     956             : static const struct
     957             : {
     958             :     int nCode;
     959             :     const char *pszText;
     960             :     bool bWriteSupported;
     961             : } asCompressionNames[] = {
     962             :     // Compression methods in read/write mode
     963             :     COMPRESSION_ENTRY(NONE, true),
     964             :     COMPRESSION_ENTRY(CCITTRLE, true),
     965             :     COMPRESSION_ENTRY(CCITTFAX3, true),
     966             :     {COMPRESSION_CCITTFAX3, "FAX3", true},  // alternate name for write side
     967             :     COMPRESSION_ENTRY(CCITTFAX4, true),
     968             :     {COMPRESSION_CCITTFAX4, "FAX4", true},  // alternate name for write side
     969             :     COMPRESSION_ENTRY(LZW, true),
     970             :     COMPRESSION_ENTRY(JPEG, true),
     971             :     COMPRESSION_ENTRY(PACKBITS, true),
     972             :     {COMPRESSION_ADOBE_DEFLATE, "DEFLATE",
     973             :      true},  // manual entry since we want the user friendly name to be DEFLATE
     974             :     {COMPRESSION_ADOBE_DEFLATE, "ZIP", true},  // alternate name for write side
     975             :     COMPRESSION_ENTRY(LZMA, true),
     976             :     COMPRESSION_ENTRY(ZSTD, true),
     977             :     COMPRESSION_ENTRY(LERC, true),
     978             :     {COMPRESSION_LERC, "LERC_DEFLATE", true},
     979             :     {COMPRESSION_LERC, "LERC_ZSTD", true},
     980             :     COMPRESSION_ENTRY(WEBP, true),
     981             :     // COMPRESSION_JXL_DNG_1_7 must be *before* COMPRESSION_JXL
     982             :     {COMPRESSION_JXL_DNG_1_7, "JXL", true},
     983             :     {COMPRESSION_JXL, "JXL",
     984             :      true},  // deprecated. No longer used for writing since GDAL 3.11
     985             : 
     986             :     // Compression methods in read-only
     987             :     COMPRESSION_ENTRY(OJPEG, false),
     988             :     COMPRESSION_ENTRY(NEXT, false),
     989             :     COMPRESSION_ENTRY(CCITTRLEW, false),
     990             :     COMPRESSION_ENTRY(THUNDERSCAN, false),
     991             :     COMPRESSION_ENTRY(PIXARFILM, false),
     992             :     COMPRESSION_ENTRY(PIXARLOG, false),
     993             :     COMPRESSION_ENTRY(DEFLATE, false),  // COMPRESSION_DEFLATE is deprecated
     994             :     COMPRESSION_ENTRY(DCS, false),
     995             :     COMPRESSION_ENTRY(JBIG, false),
     996             :     COMPRESSION_ENTRY(SGILOG, false),
     997             :     COMPRESSION_ENTRY(SGILOG24, false),
     998             :     COMPRESSION_ENTRY(JP2000, false),
     999             : };
    1000             : 
    1001             : /************************************************************************/
    1002             : /*                    GTIFFGetCompressionMethodName()                   */
    1003             : /************************************************************************/
    1004             : 
    1005        3711 : const char *GTIFFGetCompressionMethodName(int nCompressionCode)
    1006             : {
    1007       44040 :     for (const auto &entry : asCompressionNames)
    1008             :     {
    1009       44038 :         if (entry.nCode == nCompressionCode)
    1010             :         {
    1011        3709 :             return entry.pszText;
    1012             :         }
    1013             :     }
    1014           2 :     return nullptr;
    1015             : }
    1016             : 
    1017             : /************************************************************************/
    1018             : /*                   GTIFFGetCompressionMethod()                        */
    1019             : /************************************************************************/
    1020             : 
    1021        3400 : int GTIFFGetCompressionMethod(const char *pszValue, const char *pszVariableName)
    1022             : {
    1023        3400 :     int nCompression = COMPRESSION_NONE;
    1024        3400 :     bool bFoundMatch = false;
    1025       29681 :     for (const auto &entry : asCompressionNames)
    1026             :     {
    1027       29679 :         if (entry.bWriteSupported && EQUAL(entry.pszText, pszValue))
    1028             :         {
    1029        3398 :             bFoundMatch = true;
    1030        3398 :             nCompression = entry.nCode;
    1031        3398 :             break;
    1032             :         }
    1033             :     }
    1034             : 
    1035        3400 :     if (!bFoundMatch)
    1036             :     {
    1037           2 :         CPLError(CE_Warning, CPLE_IllegalArg,
    1038             :                  "%s=%s value not recognised, ignoring.", pszVariableName,
    1039             :                  pszValue);
    1040             :     }
    1041             : 
    1042        6796 :     if (nCompression != COMPRESSION_NONE &&
    1043        3396 :         !TIFFIsCODECConfigured(static_cast<uint16_t>(nCompression)))
    1044             :     {
    1045           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1046             :                  "Cannot create TIFF file due to missing codec for %s.",
    1047             :                  pszValue);
    1048           0 :         return -1;
    1049             :     }
    1050             : 
    1051        3400 :     return nCompression;
    1052             : }
    1053             : 
    1054             : /************************************************************************/
    1055             : /*                     GTiffGetCompressValues()                         */
    1056             : /************************************************************************/
    1057             : 
    1058        3510 : CPLString GTiffGetCompressValues(bool &bHasLZW, bool &bHasDEFLATE,
    1059             :                                  bool &bHasLZMA, bool &bHasZSTD, bool &bHasJPEG,
    1060             :                                  bool &bHasWebP, bool &bHasLERC, bool bForCOG)
    1061             : {
    1062        3510 :     bHasLZW = false;
    1063        3510 :     bHasDEFLATE = false;
    1064        3510 :     bHasLZMA = false;
    1065        3510 :     bHasZSTD = false;
    1066        3510 :     bHasJPEG = false;
    1067        3510 :     bHasWebP = false;
    1068        3510 :     bHasLERC = false;
    1069             : 
    1070             :     /* -------------------------------------------------------------------- */
    1071             :     /*      Determine which compression codecs are available that we        */
    1072             :     /*      want to advertise.  If we are using an old libtiff we won't     */
    1073             :     /*      be able to find out so we just assume all are available.        */
    1074             :     /* -------------------------------------------------------------------- */
    1075        3510 :     CPLString osCompressValues = "       <Value>NONE</Value>";
    1076             : 
    1077        3510 :     TIFFCodec *codecs = TIFFGetConfiguredCODECs();
    1078             : 
    1079       73710 :     for (TIFFCodec *c = codecs; c->name; ++c)
    1080             :     {
    1081       70200 :         if (c->scheme == COMPRESSION_PACKBITS && !bForCOG)
    1082             :         {
    1083        1755 :             osCompressValues += "       <Value>PACKBITS</Value>";
    1084             :         }
    1085       68445 :         else if (c->scheme == COMPRESSION_JPEG)
    1086             :         {
    1087        3510 :             bHasJPEG = true;
    1088        3510 :             osCompressValues += "       <Value>JPEG</Value>";
    1089             :         }
    1090       64935 :         else if (c->scheme == COMPRESSION_LZW)
    1091             :         {
    1092        3510 :             bHasLZW = true;
    1093        3510 :             osCompressValues += "       <Value>LZW</Value>";
    1094             :         }
    1095       61425 :         else if (c->scheme == COMPRESSION_ADOBE_DEFLATE)
    1096             :         {
    1097        3510 :             bHasDEFLATE = true;
    1098        3510 :             osCompressValues += "       <Value>DEFLATE</Value>";
    1099             :         }
    1100       57915 :         else if (c->scheme == COMPRESSION_CCITTRLE && !bForCOG)
    1101             :         {
    1102        1755 :             osCompressValues += "       <Value>CCITTRLE</Value>";
    1103             :         }
    1104       56160 :         else if (c->scheme == COMPRESSION_CCITTFAX3 && !bForCOG)
    1105             :         {
    1106        1755 :             osCompressValues += "       <Value>CCITTFAX3</Value>";
    1107             :         }
    1108       54405 :         else if (c->scheme == COMPRESSION_CCITTFAX4 && !bForCOG)
    1109             :         {
    1110        1755 :             osCompressValues += "       <Value>CCITTFAX4</Value>";
    1111             :         }
    1112       52650 :         else if (c->scheme == COMPRESSION_LZMA)
    1113             :         {
    1114        3510 :             bHasLZMA = true;
    1115        3510 :             osCompressValues += "       <Value>LZMA</Value>";
    1116             :         }
    1117       49140 :         else if (c->scheme == COMPRESSION_ZSTD)
    1118             :         {
    1119        3510 :             bHasZSTD = true;
    1120        3510 :             osCompressValues += "       <Value>ZSTD</Value>";
    1121             :         }
    1122       45630 :         else if (c->scheme == COMPRESSION_WEBP)
    1123             :         {
    1124        3510 :             bHasWebP = true;
    1125        3510 :             osCompressValues += "       <Value>WEBP</Value>";
    1126             :         }
    1127       42120 :         else if (c->scheme == COMPRESSION_LERC)
    1128             :         {
    1129        3510 :             bHasLERC = true;
    1130             :         }
    1131             :     }
    1132        3510 :     if (bHasLERC)
    1133             :     {
    1134             :         osCompressValues += "       <Value>LERC</Value>"
    1135        3510 :                             "       <Value>LERC_DEFLATE</Value>";
    1136        3510 :         if (bHasZSTD)
    1137             :         {
    1138        3510 :             osCompressValues += "       <Value>LERC_ZSTD</Value>";
    1139             :         }
    1140             :     }
    1141             : #ifdef HAVE_JXL
    1142        3510 :     osCompressValues += "       <Value>JXL</Value>";
    1143             : #endif
    1144        3510 :     _TIFFfree(codecs);
    1145             : 
    1146        3510 :     return osCompressValues;
    1147             : }
    1148             : 
    1149             : /************************************************************************/
    1150             : /*                    OGRGTiffDriverGetSubdatasetInfo()                 */
    1151             : /************************************************************************/
    1152             : 
    1153             : struct GTiffDriverSubdatasetInfo final : public GDALSubdatasetInfo
    1154             : {
    1155             :   public:
    1156           7 :     explicit GTiffDriverSubdatasetInfo(const std::string &fileName)
    1157           7 :         : GDALSubdatasetInfo(fileName)
    1158             :     {
    1159           7 :     }
    1160             : 
    1161             :     // GDALSubdatasetInfo interface
    1162             :   private:
    1163             :     void parseFileName() override;
    1164             : };
    1165             : 
    1166           7 : void GTiffDriverSubdatasetInfo::parseFileName()
    1167             : {
    1168           7 :     if (!STARTS_WITH_CI(m_fileName.c_str(), "GTIFF_DIR:"))
    1169             :     {
    1170           0 :         return;
    1171             :     }
    1172             : 
    1173           7 :     CPLStringList aosParts{CSLTokenizeString2(m_fileName.c_str(), ":", 0)};
    1174           7 :     const int iPartsCount{CSLCount(aosParts)};
    1175             : 
    1176           7 :     if (iPartsCount == 3 || iPartsCount == 4)
    1177             :     {
    1178             : 
    1179           7 :         m_driverPrefixComponent = aosParts[0];
    1180             : 
    1181             :         const bool hasDriveLetter{
    1182           9 :             strlen(aosParts[2]) == 1 &&
    1183           2 :             std::isalpha(static_cast<unsigned char>(aosParts[2][0]))};
    1184             : 
    1185             :         // Check for drive letter
    1186           7 :         if (iPartsCount == 4)
    1187             :         {
    1188             :             // Invalid
    1189           2 :             if (!hasDriveLetter)
    1190             :             {
    1191           0 :                 return;
    1192             :             }
    1193           2 :             m_pathComponent = aosParts[2];
    1194           2 :             m_pathComponent.append(":");
    1195           2 :             m_pathComponent.append(aosParts[3]);
    1196             :         }
    1197             :         else  // count is 3
    1198             :         {
    1199           5 :             if (hasDriveLetter)
    1200             :             {
    1201           0 :                 return;
    1202             :             }
    1203           5 :             m_pathComponent = aosParts[2];
    1204             :         }
    1205             : 
    1206           7 :         m_subdatasetComponent = aosParts[1];
    1207             :     }
    1208             : }
    1209             : 
    1210        2787 : static GDALSubdatasetInfo *GTiffDriverGetSubdatasetInfo(const char *pszFileName)
    1211             : {
    1212        2787 :     if (STARTS_WITH_CI(pszFileName, "GTIFF_DIR:"))
    1213             :     {
    1214             :         std::unique_ptr<GDALSubdatasetInfo> info =
    1215           7 :             std::make_unique<GTiffDriverSubdatasetInfo>(pszFileName);
    1216          21 :         if (!info->GetSubdatasetComponent().empty() &&
    1217          14 :             !info->GetPathComponent().empty())
    1218             :         {
    1219           7 :             return info.release();
    1220             :         }
    1221             :     }
    1222        2780 :     return nullptr;
    1223             : }
    1224             : 
    1225             : /************************************************************************/
    1226             : /*                          GDALRegister_GTiff()                        */
    1227             : /************************************************************************/
    1228             : 
    1229        2038 : void GDALRegister_GTiff()
    1230             : 
    1231             : {
    1232        2038 :     if (GDALGetDriverByName("GTiff") != nullptr)
    1233         283 :         return;
    1234             : 
    1235        3510 :     CPLString osOptions;
    1236             : 
    1237        1755 :     bool bHasLZW = false;
    1238        1755 :     bool bHasDEFLATE = false;
    1239        1755 :     bool bHasLZMA = false;
    1240        1755 :     bool bHasZSTD = false;
    1241        1755 :     bool bHasJPEG = false;
    1242        1755 :     bool bHasWebP = false;
    1243        1755 :     bool bHasLERC = false;
    1244             :     CPLString osCompressValues(GTiffGetCompressValues(
    1245             :         bHasLZW, bHasDEFLATE, bHasLZMA, bHasZSTD, bHasJPEG, bHasWebP, bHasLERC,
    1246        3510 :         false /* bForCOG */));
    1247             : 
    1248        1755 :     GDALDriver *poDriver = new GDALDriver();
    1249             : 
    1250             :     /* -------------------------------------------------------------------- */
    1251             :     /*      Build full creation option list.                                */
    1252             :     /* -------------------------------------------------------------------- */
    1253             :     osOptions = "<CreationOptionList>"
    1254        1755 :                 "   <Option name='COMPRESS' type='string-select'>";
    1255        1755 :     osOptions += osCompressValues;
    1256        1755 :     osOptions += "   </Option>";
    1257        1755 :     if (bHasLZW || bHasDEFLATE || bHasZSTD)
    1258             :         osOptions += ""
    1259             :                      "   <Option name='PREDICTOR' type='int' "
    1260             :                      "description='Predictor Type (1=default, 2=horizontal "
    1261             :                      "differencing, 3=floating point prediction)' "
    1262        1755 :                      "default='1'/>";
    1263             :     osOptions +=
    1264             :         ""
    1265             :         "   <Option name='DISCARD_LSB' type='string' description='Number of "
    1266             :         "least-significant bits to set to clear as a single value or "
    1267        1755 :         "comma-separated list of values for per-band values'/>";
    1268        1755 :     if (bHasJPEG)
    1269             :     {
    1270             :         osOptions +=
    1271             :             ""
    1272             :             "   <Option name='JPEG_QUALITY' type='int' description='JPEG "
    1273             :             "quality 1-100' min='1' max='100' default='75'/>"
    1274             :             "   <Option name='JPEGTABLESMODE' type='int' description='Content "
    1275             :             "of JPEGTABLES tag. 0=no JPEGTABLES tag, 1=Quantization tables "
    1276        1755 :             "only, 2=Huffman tables only, 3=Both' default='1'/>";
    1277             : #ifdef JPEG_DIRECT_COPY
    1278             :         osOptions +=
    1279             :             ""
    1280             :             "   <Option name='JPEG_DIRECT_COPY' type='boolean' description='To "
    1281             :             "copy without any decompression/recompression a JPEG source file' "
    1282             :             "default='NO'/>";
    1283             : #endif
    1284             :     }
    1285        1755 :     if (bHasDEFLATE)
    1286             :     {
    1287             : #ifdef LIBDEFLATE_SUPPORT
    1288             :         osOptions += ""
    1289             :                      "   <Option name='ZLEVEL' type='int' description='DEFLATE "
    1290        1755 :                      "compression level 1-12' min='1' max='12' default='6'/>";
    1291             : #else
    1292             :         osOptions += ""
    1293             :                      "   <Option name='ZLEVEL' type='int' description='DEFLATE "
    1294             :                      "compression level 1-9' min='1' max='9' default='6'/>";
    1295             : #endif
    1296             :     }
    1297        1755 :     if (bHasLZMA)
    1298             :         osOptions +=
    1299             :             ""
    1300             :             "   <Option name='LZMA_PRESET' type='int' description='LZMA "
    1301        1755 :             "compression level 0(fast)-9(slow)' min='0' max='9' default='6'/>";
    1302        1755 :     if (bHasZSTD)
    1303             :         osOptions +=
    1304             :             ""
    1305             :             "   <Option name='ZSTD_LEVEL' type='int' description='ZSTD "
    1306             :             "compression level 1(fast)-22(slow)' min='1' max='22' "
    1307        1755 :             "default='9'/>";
    1308        1755 :     if (bHasLERC)
    1309             :     {
    1310             :         osOptions +=
    1311             :             ""
    1312             :             "   <Option name='MAX_Z_ERROR' type='float' description='Maximum "
    1313             :             "error for LERC compression' default='0'/>"
    1314             :             "   <Option name='MAX_Z_ERROR_OVERVIEW' type='float' "
    1315             :             "description='Maximum error for LERC compression in overviews' "
    1316        1755 :             "default='0'/>";
    1317             :     }
    1318        1755 :     if (bHasWebP)
    1319             :     {
    1320             : #ifndef DEFAULT_WEBP_LEVEL
    1321             : #error "DEFAULT_WEBP_LEVEL should be defined"
    1322             : #endif
    1323             :         osOptions +=
    1324             :             ""
    1325             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
    1326             :             "   <Option name='WEBP_LOSSLESS' type='boolean' "
    1327             :             "description='Whether lossless compression should be used' "
    1328             :             "default='FALSE'/>"
    1329             : #endif
    1330             :             "   <Option name='WEBP_LEVEL' type='int' description='WEBP quality "
    1331             :             "level. Low values result in higher compression ratios' "
    1332        1755 :             "default='" XSTRINGIFY(DEFAULT_WEBP_LEVEL) "'/>";
    1333             :     }
    1334             : #ifdef HAVE_JXL
    1335             :     osOptions +=
    1336             :         ""
    1337             :         "   <Option name='JXL_LOSSLESS' type='boolean' description='Whether "
    1338             :         "JPEGXL compression should be lossless' default='YES'/>"
    1339             :         "   <Option name='JXL_EFFORT' type='int' description='Level of effort "
    1340             :         "1(fast)-9(slow)' min='1' max='9' default='5'/>"
    1341             :         "   <Option name='JXL_DISTANCE' type='float' description='Distance "
    1342             :         "level for lossy compression (0=mathematically lossless, 1.0=visually "
    1343        1755 :         "lossless, usual range [0.5,3])' default='1.0' min='0.01' max='25.0'/>";
    1344             : #ifdef HAVE_JxlEncoderSetExtraChannelDistance
    1345             :     osOptions += "   <Option name='JXL_ALPHA_DISTANCE' type='float' "
    1346             :                  "description='Distance level for alpha channel "
    1347             :                  "(-1=same as non-alpha channels, "
    1348             :                  "0=mathematically lossless, 1.0=visually lossless, "
    1349        1755 :                  "usual range [0.5,3])' default='-1' min='-1' max='25.0'/>";
    1350             : #endif
    1351             : #endif
    1352             :     osOptions +=
    1353             :         ""
    1354             :         "   <Option name='NUM_THREADS' type='string' description='Number of "
    1355             :         "worker threads for compression. Can be set to ALL_CPUS' default='1'/>"
    1356             :         "   <Option name='NBITS' type='int' description='BITS for sub-byte "
    1357             :         "files (1-7), sub-uint16_t (9-15), sub-uint32_t (17-31), or float32 "
    1358             :         "(16)'/>"
    1359             :         "   <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
    1360             :         "       <Value>BAND</Value>"
    1361             :         "       <Value>PIXEL</Value>"
    1362             :         "   </Option>"
    1363             :         "   <Option name='TILED' type='boolean' description='Switch to tiled "
    1364             :         "format' default='NO'/>"
    1365             :         "   <Option name='TFW' type='boolean' description='Write out world "
    1366             :         "file'/>"
    1367             :         "   <Option name='RPB' type='boolean' description='Write out .RPB "
    1368             :         "(RPC) file'/>"
    1369             :         "   <Option name='RPCTXT' type='boolean' description='Write out "
    1370             :         "_RPC.TXT file'/>"
    1371             :         "   <Option name='BLOCKXSIZE' type='int' description='Tile Width' "
    1372             :         "default='256'/>"
    1373             :         "   <Option name='BLOCKYSIZE' type='int' description='Tile/Strip "
    1374             :         "Height'/>"
    1375             :         "   <Option name='PHOTOMETRIC' type='string-select'>"
    1376             :         "       <Value>MINISBLACK</Value>"
    1377             :         "       <Value>MINISWHITE</Value>"
    1378             :         "       <Value>PALETTE</Value>"
    1379             :         "       <Value>RGB</Value>"
    1380             :         "       <Value>CMYK</Value>"
    1381             :         "       <Value>YCBCR</Value>"
    1382             :         "       <Value>CIELAB</Value>"
    1383             :         "       <Value>ICCLAB</Value>"
    1384             :         "       <Value>ITULAB</Value>"
    1385             :         "   </Option>"
    1386             :         "   <Option name='SPARSE_OK' type='boolean' description='Should empty "
    1387             :         "blocks be omitted on disk?' default='FALSE'/>"
    1388             :         "   <Option name='ALPHA' type='string-select' description='Mark first "
    1389             :         "extrasample as being alpha'>"
    1390             :         "       <Value>NON-PREMULTIPLIED</Value>"
    1391             :         "       <Value>PREMULTIPLIED</Value>"
    1392             :         "       <Value>UNSPECIFIED</Value>"
    1393             :         "       <Value aliasOf='NON-PREMULTIPLIED'>YES</Value>"
    1394             :         "       <Value aliasOf='UNSPECIFIED'>NO</Value>"
    1395             :         "   </Option>"
    1396             :         "   <Option name='PROFILE' type='string-select' default='GDALGeoTIFF'>"
    1397             :         "       <Value>GDALGeoTIFF</Value>"
    1398             :         "       <Value>GeoTIFF</Value>"
    1399             :         "       <Value>BASELINE</Value>"
    1400             :         "   </Option>"
    1401             :         "   <Option name='PIXELTYPE' type='string-select' "
    1402             :         "description='(deprecated, use Int8 datatype)'>"
    1403             :         "       <Value>DEFAULT</Value>"
    1404             :         "       <Value>SIGNEDBYTE</Value>"
    1405             :         "   </Option>"
    1406             :         "   <Option name='BIGTIFF' type='string-select' description='Force "
    1407             :         "creation of BigTIFF file' default='IF_NEEDED'>"
    1408             :         "     <Value>YES</Value>"
    1409             :         "     <Value>NO</Value>"
    1410             :         "     <Value>IF_NEEDED</Value>"
    1411             :         "     <Value>IF_SAFER</Value>"
    1412             :         "   </Option>"
    1413             :         "   <Option name='ENDIANNESS' type='string-select' default='NATIVE' "
    1414             :         "description='Force endianness of created file. For DEBUG purpose "
    1415             :         "mostly'>"
    1416             :         "       <Value>NATIVE</Value>"
    1417             :         "       <Value>INVERTED</Value>"
    1418             :         "       <Value>LITTLE</Value>"
    1419             :         "       <Value>BIG</Value>"
    1420             :         "   </Option>"
    1421             :         "   <Option name='COPY_SRC_OVERVIEWS' type='boolean' default='NO' "
    1422             :         "description='Force copy of overviews of source dataset "
    1423             :         "(CreateCopy())'/>"
    1424             :         "   <Option name='SOURCE_ICC_PROFILE' type='string' description='ICC "
    1425             :         "profile'/>"
    1426             :         "   <Option name='SOURCE_PRIMARIES_RED' type='string' "
    1427             :         "description='x,y,1.0 (xyY) red chromaticity'/>"
    1428             :         "   <Option name='SOURCE_PRIMARIES_GREEN' type='string' "
    1429             :         "description='x,y,1.0 (xyY) green chromaticity'/>"
    1430             :         "   <Option name='SOURCE_PRIMARIES_BLUE' type='string' "
    1431             :         "description='x,y,1.0 (xyY) blue chromaticity'/>"
    1432             :         "   <Option name='SOURCE_WHITEPOINT' type='string' "
    1433             :         "description='x,y,1.0 (xyY) whitepoint'/>"
    1434             :         "   <Option name='TIFFTAG_TRANSFERFUNCTION_RED' type='string' "
    1435             :         "description='Transfer function for red'/>"
    1436             :         "   <Option name='TIFFTAG_TRANSFERFUNCTION_GREEN' type='string' "
    1437             :         "description='Transfer function for green'/>"
    1438             :         "   <Option name='TIFFTAG_TRANSFERFUNCTION_BLUE' type='string' "
    1439             :         "description='Transfer function for blue'/>"
    1440             :         "   <Option name='TIFFTAG_TRANSFERRANGE_BLACK' type='string' "
    1441             :         "description='Transfer range for black'/>"
    1442             :         "   <Option name='TIFFTAG_TRANSFERRANGE_WHITE' type='string' "
    1443             :         "description='Transfer range for white'/>"
    1444             :         "   <Option name='STREAMABLE_OUTPUT' type='boolean' default='NO' "
    1445             :         "description='Enforce a mode compatible with a streamable file'/>"
    1446             :         "   <Option name='GEOTIFF_KEYS_FLAVOR' type='string-select' "
    1447             :         "default='STANDARD' description='Which flavor of GeoTIFF keys must be "
    1448             :         "used'>"
    1449             :         "       <Value>STANDARD</Value>"
    1450             :         "       <Value>ESRI_PE</Value>"
    1451             :         "   </Option>"
    1452             : #if LIBGEOTIFF_VERSION >= 1600
    1453             :         "   <Option name='GEOTIFF_VERSION' type='string-select' default='AUTO' "
    1454             :         "description='Which version of GeoTIFF must be used'>"
    1455             :         "       <Value>AUTO</Value>"
    1456             :         "       <Value>1.0</Value>"
    1457             :         "       <Value>1.1</Value>"
    1458             :         "   </Option>"
    1459             : #endif
    1460             :         "   <Option name='COLOR_TABLE_MULTIPLIER' type='string-select' "
    1461             :         "description='Multiplication factor to apply to go from GDAL color "
    1462             :         "table to TIFF color table' "
    1463             :         "default='257'>"
    1464             :         "       <Value>1</Value>"
    1465             :         "       <Value>256</Value>"
    1466             :         "       <Value>257</Value>"
    1467             :         "   </Option>"
    1468        1755 :         "</CreationOptionList>";
    1469             : 
    1470        3510 :     std::string osOvrOptions;
    1471             :     osOvrOptions = "<OverviewCreationOptionList>"
    1472             :                    "   <Option name='LOCATION' type='string-select'>"
    1473             :                    "       <Value>INTERNAL</Value>"
    1474             :                    "       <Value>EXTERNAL</Value>"
    1475             :                    "       <Value>RRD</Value>"
    1476             :                    "   </Option>"
    1477        1755 :                    "   <Option name='COMPRESS' type='string-select'>";
    1478        1755 :     osOvrOptions += osCompressValues;
    1479             :     osOvrOptions +=
    1480             :         "   </Option>"
    1481             :         "   <Option name='BLOCKSIZE' type='int' "
    1482             :         "description='Tile size in pixels' min='64'/>"
    1483             :         "   <Option name='NUM_THREADS' type='string' description='Number of "
    1484        1755 :         "worker threads for compression. Can be set to ALL_CPUS' default='1'/>";
    1485        1755 :     if (bHasLZW || bHasDEFLATE || bHasZSTD)
    1486             :         osOvrOptions += "   <Option name='PREDICTOR' type='int' "
    1487             :                         "description='Predictor Type (1=default, 2=horizontal "
    1488             :                         "differencing, 3=floating point prediction)' "
    1489        1755 :                         "default='1'/>";
    1490        1755 :     if (bHasJPEG)
    1491             :     {
    1492             :         osOvrOptions +=
    1493             :             ""
    1494             :             "   <Option name='JPEG_QUALITY' type='int' description='JPEG "
    1495             :             "quality 1-100' min='1' max='100' default='75'/>"
    1496             :             "   <Option name='JPEGTABLESMODE' type='int' description='Content "
    1497             :             "of JPEGTABLES tag. 0=no JPEGTABLES tag, 1=Quantization tables "
    1498        1755 :             "only, 2=Huffman tables only, 3=Both' default='1'/>";
    1499             :     }
    1500        1755 :     if (bHasDEFLATE)
    1501             :     {
    1502             : #ifdef LIBDEFLATE_SUPPORT
    1503             :         osOvrOptions +=
    1504             :             ""
    1505             :             "   <Option name='ZLEVEL' type='int' description='DEFLATE "
    1506        1755 :             "compression level 1-12' min='1' max='12' default='6'/>";
    1507             : #else
    1508             :         osOvrOptions +=
    1509             :             ""
    1510             :             "   <Option name='ZLEVEL' type='int' description='DEFLATE "
    1511             :             "compression level 1-9' min='1' max='9' default='6'/>";
    1512             : #endif
    1513             :     }
    1514        1755 :     if (bHasZSTD)
    1515             :         osOvrOptions +=
    1516             :             ""
    1517             :             "   <Option name='ZSTD_LEVEL' type='int' description='ZSTD "
    1518             :             "compression level 1(fast)-22(slow)' min='1' max='22' "
    1519        1755 :             "default='9'/>";
    1520        1755 :     if (bHasLERC)
    1521             :     {
    1522             :         osOvrOptions +=
    1523             :             ""
    1524             :             "   <Option name='MAX_Z_ERROR' type='float' description='Maximum "
    1525        1755 :             "error for LERC compression' default='0'/>";
    1526             :     }
    1527        1755 :     if (bHasWebP)
    1528             :     {
    1529             :         osOvrOptions +=
    1530             :             ""
    1531             : #if WEBP_ENCODER_ABI_VERSION >= 0x0100
    1532             :             "   <Option name='WEBP_LOSSLESS' type='boolean' "
    1533             :             "description='Whether lossless compression should be used' "
    1534             :             "default='FALSE'/>"
    1535             : #endif
    1536             :             "   <Option name='WEBP_LEVEL' type='int' description='WEBP quality "
    1537             :             "level. Low values result in higher compression ratios' "
    1538        1755 :             "default='" XSTRINGIFY(DEFAULT_WEBP_LEVEL) "'/>";
    1539             :     }
    1540             : #ifdef HAVE_JXL
    1541             :     osOvrOptions +=
    1542             :         ""
    1543             :         "   <Option name='JXL_LOSSLESS' type='boolean' description='Whether "
    1544             :         "JPEGXL compression should be lossless' default='YES'/>"
    1545             :         "   <Option name='JXL_EFFORT' type='int' description='Level of effort "
    1546             :         "1(fast)-9(slow)' min='1' max='9' default='5'/>"
    1547             :         "   <Option name='JXL_DISTANCE' type='float' description='Distance "
    1548             :         "level for lossy compression (0=mathematically lossless, 1.0=visually "
    1549        1755 :         "lossless, usual range [0.5,3])' default='1.0' min='0.01' max='25.0'/>";
    1550             : #ifdef HAVE_JxlEncoderSetExtraChannelDistance
    1551             :     osOvrOptions += "   <Option name='JXL_ALPHA_DISTANCE' type='float' "
    1552             :                     "description='Distance level for alpha channel "
    1553             :                     "(-1=same as non-alpha channels, "
    1554             :                     "0=mathematically lossless, 1.0=visually lossless, "
    1555        1755 :                     "usual range [0.5,3])' default='-1' min='-1' max='25.0'/>";
    1556             : #endif
    1557             : #endif
    1558             :     osOvrOptions +=
    1559             :         "   <Option name='INTERLEAVE' type='string-select' default='PIXEL'>"
    1560             :         "       <Value>BAND</Value>"
    1561             :         "       <Value>PIXEL</Value>"
    1562             :         "   </Option>"
    1563             :         "   <Option name='PHOTOMETRIC' type='string-select'>"
    1564             :         "       <Value>MINISBLACK</Value>"
    1565             :         "       <Value>MINISWHITE</Value>"
    1566             :         "       <Value>PALETTE</Value>"
    1567             :         "       <Value>RGB</Value>"
    1568             :         "       <Value>CMYK</Value>"
    1569             :         "       <Value>YCBCR</Value>"
    1570             :         "       <Value>CIELAB</Value>"
    1571             :         "       <Value>ICCLAB</Value>"
    1572             :         "       <Value>ITULAB</Value>"
    1573             :         "   </Option>"
    1574             :         "   <Option name='BIGTIFF' type='string-select' description='Force "
    1575             :         "creation of BigTIFF file (only for external overview)' "
    1576             :         "default='IF_NEEDED'>"
    1577             :         "     <Value>YES</Value>"
    1578             :         "     <Value>NO</Value>"
    1579             :         "     <Value>IF_NEEDED</Value>"
    1580             :         "     <Value>IF_SAFER</Value>"
    1581             :         "   </Option>"
    1582             :         "   <Option name='ALPHA' type='string-select' description='Mark first "
    1583             :         "extrasample as being alpha'>"
    1584             :         "       <Value>NON-PREMULTIPLIED</Value>"
    1585             :         "       <Value>PREMULTIPLIED</Value>"
    1586             :         "       <Value>UNSPECIFIED</Value>"
    1587             :         "       <Value aliasOf='NON-PREMULTIPLIED'>YES</Value>"
    1588             :         "       <Value aliasOf='UNSPECIFIED'>NO</Value>"
    1589             :         "   </Option>"
    1590        1755 :         "</OverviewCreationOptionList>";
    1591             : 
    1592             :     /* -------------------------------------------------------------------- */
    1593             :     /*      Set the driver details.                                         */
    1594             :     /* -------------------------------------------------------------------- */
    1595        1755 :     poDriver->SetDescription("GTiff");
    1596        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
    1597        1755 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GeoTIFF");
    1598        1755 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/gtiff.html");
    1599        1755 :     poDriver->SetMetadataItem(GDAL_DMD_MIMETYPE, "image/tiff");
    1600        1755 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "tif");
    1601        1755 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "tif tiff");
    1602        1755 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONDATATYPES,
    1603             :                               "Byte Int8 UInt16 Int16 UInt32 Int32 Float32 "
    1604        1755 :                               "Float64 CInt16 CInt32 CFloat32 CFloat64");
    1605        1755 :     poDriver->SetMetadataItem(GDAL_DMD_CREATIONOPTIONLIST, osOptions);
    1606        1755 :     poDriver->SetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST,
    1607        1755 :                               osOvrOptions.c_str());
    1608        1755 :     poDriver->SetMetadataItem(
    1609             :         GDAL_DMD_OPENOPTIONLIST,
    1610             :         "<OpenOptionList>"
    1611             :         "   <Option name='NUM_THREADS' type='string' description='Number of "
    1612             :         "worker threads for compression. Can be set to ALL_CPUS' default='1'/>"
    1613             :         "   <Option name='GEOTIFF_KEYS_FLAVOR' type='string-select' "
    1614             :         "default='STANDARD' description='Which flavor of GeoTIFF keys must be "
    1615             :         "used (for writing)'>"
    1616             :         "       <Value>STANDARD</Value>"
    1617             :         "       <Value>ESRI_PE</Value>"
    1618             :         "   </Option>"
    1619             :         "   <Option name='GEOREF_SOURCES' type='string' description='Comma "
    1620             :         "separated list made with values "
    1621             :         "INTERNAL/TABFILE/WORLDFILE/PAM/XML/NONE "
    1622             :         "that describe the priority order for georeferencing' "
    1623             :         "default='PAM,INTERNAL,TABFILE,WORLDFILE,XML'/>"
    1624             :         "   <Option name='SPARSE_OK' type='boolean' description='Should empty "
    1625             :         "blocks be omitted on disk?' default='FALSE'/>"
    1626             :         "   <Option name='IGNORE_COG_LAYOUT_BREAK' type='boolean' "
    1627             :         "description='Allow update mode on files with COG structure' "
    1628             :         "default='FALSE'/>"
    1629             :         "   <Option name='COLOR_TABLE_MULTIPLIER' type='string-select' "
    1630             :         "description='Multiplication factor to apply to go from GDAL color "
    1631             :         "table to TIFF color table' "
    1632             :         "default='AUTO'>"
    1633             :         "       <Value>AUTO</Value>"
    1634             :         "       <Value>1</Value>"
    1635             :         "       <Value>256</Value>"
    1636             :         "       <Value>257</Value>"
    1637             :         "   </Option>"
    1638        1755 :         "</OpenOptionList>");
    1639        1755 :     poDriver->SetMetadataItem(GDAL_DMD_SUBDATASETS, "YES");
    1640        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_SUBDATASETS, "YES");
    1641        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    1642        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_CREATE_ONLY_VISIBLE_AT_CLOSE_TIME,
    1643        1755 :                               "YES");
    1644        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_CAN_READ_AFTER_DELETE, "YES");
    1645             : 
    1646        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
    1647        1755 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
    1648             :                               "GeoTransform SRS GCPs NoData "
    1649             :                               "ColorInterpretation RasterValues "
    1650        1755 :                               "DatasetMetadata BandMetadata");
    1651             : 
    1652             : #ifdef INTERNAL_LIBTIFF
    1653        1755 :     poDriver->SetMetadataItem("LIBTIFF", "INTERNAL");
    1654             : #else
    1655             :     poDriver->SetMetadataItem("LIBTIFF", TIFFLIB_VERSION_STR);
    1656             : #endif
    1657             : 
    1658        1755 :     poDriver->SetMetadataItem("LIBGEOTIFF", XSTRINGIFY(LIBGEOTIFF_VERSION));
    1659             : 
    1660             : #if defined(LERC_SUPPORT) && defined(LERC_VERSION_MAJOR)
    1661             :     poDriver->SetMetadataItem("LERC_VERSION_MAJOR",
    1662             :                               XSTRINGIFY(LERC_VERSION_MAJOR), "LERC");
    1663             :     poDriver->SetMetadataItem("LERC_VERSION_MINOR",
    1664             :                               XSTRINGIFY(LERC_VERSION_MINOR), "LERC");
    1665             :     poDriver->SetMetadataItem("LERC_VERSION_PATCH",
    1666             :                               XSTRINGIFY(LERC_VERSION_PATCH), "LERC");
    1667             : #endif
    1668             : 
    1669        1755 :     poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
    1670             : 
    1671        1755 :     poDriver->pfnOpen = GTiffDataset::Open;
    1672        1755 :     poDriver->pfnCreate = GTiffDataset::Create;
    1673        1755 :     poDriver->pfnCreateCopy = GTiffDataset::CreateCopy;
    1674        1755 :     poDriver->pfnUnloadDriver = GDALDeregister_GTiff;
    1675        1755 :     poDriver->pfnIdentify = GTiffDataset::Identify;
    1676        1755 :     poDriver->pfnGetSubdatasetInfoFunc = GTiffDriverGetSubdatasetInfo;
    1677             : 
    1678        1755 :     GetGDALDriverManager()->RegisterDriver(poDriver);
    1679             : }

Generated by: LCOV version 1.14