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