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