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

Generated by: LCOV version 1.14