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