Coverage Report

Created: 2025-12-31 06:48

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