Coverage Report

Created: 2025-11-16 06:25

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