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