/src/gdal/gcore/tiff_common.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: GDAL Core |
4 | | * Purpose: Common code shared between the GTiff and libertiff drivers |
5 | | * Author: Even Rouault <even dot rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2024, Even Rouault <even dot rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #include "tiff_common.h" |
14 | | |
15 | | #include <algorithm> |
16 | | |
17 | | #include "gdal_mdreader.h" |
18 | | |
19 | | namespace gdal |
20 | | { |
21 | | namespace tiff_common |
22 | | { |
23 | | |
24 | | /************************************************************************/ |
25 | | /* PrepareTIFFErrorFormat() */ |
26 | | /* */ |
27 | | /* sometimes the "module" has stuff in it that has special */ |
28 | | /* meaning in a printf() style format, so we try to escape it. */ |
29 | | /* For now we hope the only thing we have to escape is %'s. */ |
30 | | /************************************************************************/ |
31 | | |
32 | | char *PrepareTIFFErrorFormat(const char *module, const char *fmt) |
33 | | |
34 | 0 | { |
35 | 0 | const size_t nModuleSize = strlen(module); |
36 | 0 | const size_t nModFmtSize = nModuleSize * 2 + strlen(fmt) + 2; |
37 | 0 | char *pszModFmt = static_cast<char *>(CPLMalloc(nModFmtSize)); |
38 | |
|
39 | 0 | size_t iOut = 0; // Used after for. |
40 | |
|
41 | 0 | for (size_t iIn = 0; iIn < nModuleSize; ++iIn) |
42 | 0 | { |
43 | 0 | if (module[iIn] == '%') |
44 | 0 | { |
45 | 0 | CPLAssert(iOut < nModFmtSize - 2); |
46 | 0 | pszModFmt[iOut++] = '%'; |
47 | 0 | pszModFmt[iOut++] = '%'; |
48 | 0 | } |
49 | 0 | else |
50 | 0 | { |
51 | 0 | CPLAssert(iOut < nModFmtSize - 1); |
52 | 0 | pszModFmt[iOut++] = module[iIn]; |
53 | 0 | } |
54 | 0 | } |
55 | 0 | CPLAssert(iOut < nModFmtSize); |
56 | 0 | pszModFmt[iOut] = '\0'; |
57 | 0 | strcat(pszModFmt, ":"); |
58 | 0 | strcat(pszModFmt, fmt); |
59 | |
|
60 | 0 | return pszModFmt; |
61 | 0 | } |
62 | | |
63 | | /************************************************************************/ |
64 | | /* TIFFColorMapTagToColorTable() */ |
65 | | /************************************************************************/ |
66 | | |
67 | | std::unique_ptr<GDALColorTable> TIFFColorMapTagToColorTable( |
68 | | const unsigned short *panRed, const unsigned short *panGreen, |
69 | | const unsigned short *panBlue, int nColorCount, int &nColorTableMultiplier, |
70 | | int nDefaultColorTableMultiplier, bool bNoDataSet, double dfNoDataValue) |
71 | 0 | { |
72 | 0 | auto poColorTable = std::make_unique<GDALColorTable>(); |
73 | |
|
74 | 0 | if (nColorTableMultiplier == 0) |
75 | 0 | { |
76 | | // TIFF color maps are in the [0, 65535] range, so some remapping must |
77 | | // be done to get values in the [0, 255] range, but it is not clear |
78 | | // how to do that exactly. Since GDAL 2.3.0 we have standardized on |
79 | | // using a 257 multiplication factor (https://github.com/OSGeo/gdal/commit/eeec5b62e385d53e7f2edaba7b73c7c74bc2af39) |
80 | | // but other software uses 256 (cf https://github.com/OSGeo/gdal/issues/10310) |
81 | | // Do a first pass to check if all values are multiples of 256 or 257. |
82 | 0 | bool bFoundNonZeroEntry = false; |
83 | 0 | bool bAllValuesMultipleOf256 = true; |
84 | 0 | bool bAllValuesMultipleOf257 = true; |
85 | 0 | unsigned short nMaxColor = 0; |
86 | 0 | for (int iColor = 0; iColor < nColorCount; ++iColor) |
87 | 0 | { |
88 | 0 | if (panRed[iColor] > 0 || panGreen[iColor] > 0 || |
89 | 0 | panBlue[iColor] > 0) |
90 | 0 | { |
91 | 0 | bFoundNonZeroEntry = true; |
92 | 0 | } |
93 | 0 | if ((panRed[iColor] % 256) != 0 || (panGreen[iColor] % 256) != 0 || |
94 | 0 | (panBlue[iColor] % 256) != 0) |
95 | 0 | { |
96 | 0 | bAllValuesMultipleOf256 = false; |
97 | 0 | } |
98 | 0 | if ((panRed[iColor] % 257) != 0 || (panGreen[iColor] % 257) != 0 || |
99 | 0 | (panBlue[iColor] % 257) != 0) |
100 | 0 | { |
101 | 0 | bAllValuesMultipleOf257 = false; |
102 | 0 | } |
103 | |
|
104 | 0 | nMaxColor = std::max(nMaxColor, panRed[iColor]); |
105 | 0 | nMaxColor = std::max(nMaxColor, panGreen[iColor]); |
106 | 0 | nMaxColor = std::max(nMaxColor, panBlue[iColor]); |
107 | 0 | } |
108 | |
|
109 | 0 | if (nMaxColor > 0 && nMaxColor < 256) |
110 | 0 | { |
111 | | // Bug 1384 - Some TIFF files are generated with color map entry |
112 | | // values in range 0-255 instead of 0-65535 - try to handle these |
113 | | // gracefully. |
114 | 0 | nColorTableMultiplier = 1; |
115 | 0 | CPLDebug("GTiff", |
116 | 0 | "TIFF ColorTable seems to be improperly scaled with " |
117 | 0 | "values all in [0,255] range, fixing up."); |
118 | 0 | } |
119 | 0 | else |
120 | 0 | { |
121 | 0 | if (!bAllValuesMultipleOf256 && !bAllValuesMultipleOf257) |
122 | 0 | { |
123 | 0 | CPLDebug("GTiff", |
124 | 0 | "The color map contains entries which are not " |
125 | 0 | "multiple of 256 or 257, so we don't know for " |
126 | 0 | "sure how to remap them to [0, 255]. Default to " |
127 | 0 | "using a 257 multiplication factor"); |
128 | 0 | } |
129 | 0 | nColorTableMultiplier = |
130 | 0 | (bFoundNonZeroEntry && bAllValuesMultipleOf256) |
131 | 0 | ? 256 |
132 | 0 | : nDefaultColorTableMultiplier; |
133 | 0 | } |
134 | 0 | } |
135 | 0 | CPLAssert(nColorTableMultiplier > 0); |
136 | 0 | CPLAssert(nColorTableMultiplier <= 257); |
137 | 0 | for (int iColor = nColorCount - 1; iColor >= 0; iColor--) |
138 | 0 | { |
139 | 0 | const GDALColorEntry oEntry = { |
140 | 0 | static_cast<short>(panRed[iColor] / nColorTableMultiplier), |
141 | 0 | static_cast<short>(panGreen[iColor] / nColorTableMultiplier), |
142 | 0 | static_cast<short>(panBlue[iColor] / nColorTableMultiplier), |
143 | 0 | static_cast<short>( |
144 | 0 | bNoDataSet && static_cast<int>(dfNoDataValue) == iColor ? 0 |
145 | 0 | : 255)}; |
146 | |
|
147 | 0 | poColorTable->SetColorEntry(iColor, &oEntry); |
148 | 0 | } |
149 | |
|
150 | 0 | return poColorTable; |
151 | 0 | } |
152 | | |
153 | | /************************************************************************/ |
154 | | /* TIFFRPCTagToRPCMetadata() */ |
155 | | /************************************************************************/ |
156 | | |
157 | | CPLStringList TIFFRPCTagToRPCMetadata(const double adfRPC[92]) |
158 | 0 | { |
159 | 0 | CPLStringList asMD; |
160 | 0 | asMD.SetNameValue(RPC_ERR_BIAS, CPLOPrintf("%.15g", adfRPC[0])); |
161 | 0 | asMD.SetNameValue(RPC_ERR_RAND, CPLOPrintf("%.15g", adfRPC[1])); |
162 | 0 | asMD.SetNameValue(RPC_LINE_OFF, CPLOPrintf("%.15g", adfRPC[2])); |
163 | 0 | asMD.SetNameValue(RPC_SAMP_OFF, CPLOPrintf("%.15g", adfRPC[3])); |
164 | 0 | asMD.SetNameValue(RPC_LAT_OFF, CPLOPrintf("%.15g", adfRPC[4])); |
165 | 0 | asMD.SetNameValue(RPC_LONG_OFF, CPLOPrintf("%.15g", adfRPC[5])); |
166 | 0 | asMD.SetNameValue(RPC_HEIGHT_OFF, CPLOPrintf("%.15g", adfRPC[6])); |
167 | 0 | asMD.SetNameValue(RPC_LINE_SCALE, CPLOPrintf("%.15g", adfRPC[7])); |
168 | 0 | asMD.SetNameValue(RPC_SAMP_SCALE, CPLOPrintf("%.15g", adfRPC[8])); |
169 | 0 | asMD.SetNameValue(RPC_LAT_SCALE, CPLOPrintf("%.15g", adfRPC[9])); |
170 | 0 | asMD.SetNameValue(RPC_LONG_SCALE, CPLOPrintf("%.15g", adfRPC[10])); |
171 | 0 | asMD.SetNameValue(RPC_HEIGHT_SCALE, CPLOPrintf("%.15g", adfRPC[11])); |
172 | |
|
173 | 0 | CPLString osField; |
174 | 0 | CPLString osMultiField; |
175 | |
|
176 | 0 | for (int i = 0; i < 20; ++i) |
177 | 0 | { |
178 | 0 | osField.Printf("%.15g", adfRPC[12 + i]); |
179 | 0 | if (i > 0) |
180 | 0 | osMultiField += " "; |
181 | 0 | else |
182 | 0 | osMultiField = ""; |
183 | 0 | osMultiField += osField; |
184 | 0 | } |
185 | 0 | asMD.SetNameValue(RPC_LINE_NUM_COEFF, osMultiField); |
186 | |
|
187 | 0 | for (int i = 0; i < 20; ++i) |
188 | 0 | { |
189 | 0 | osField.Printf("%.15g", adfRPC[32 + i]); |
190 | 0 | if (i > 0) |
191 | 0 | osMultiField += " "; |
192 | 0 | else |
193 | 0 | osMultiField = ""; |
194 | 0 | osMultiField += osField; |
195 | 0 | } |
196 | 0 | asMD.SetNameValue(RPC_LINE_DEN_COEFF, osMultiField); |
197 | |
|
198 | 0 | for (int i = 0; i < 20; ++i) |
199 | 0 | { |
200 | 0 | osField.Printf("%.15g", adfRPC[52 + i]); |
201 | 0 | if (i > 0) |
202 | 0 | osMultiField += " "; |
203 | 0 | else |
204 | 0 | osMultiField = ""; |
205 | 0 | osMultiField += osField; |
206 | 0 | } |
207 | 0 | asMD.SetNameValue(RPC_SAMP_NUM_COEFF, osMultiField); |
208 | |
|
209 | 0 | for (int i = 0; i < 20; ++i) |
210 | 0 | { |
211 | 0 | osField.Printf("%.15g", adfRPC[72 + i]); |
212 | 0 | if (i > 0) |
213 | 0 | osMultiField += " "; |
214 | 0 | else |
215 | 0 | osMultiField = ""; |
216 | 0 | osMultiField += osField; |
217 | 0 | } |
218 | 0 | asMD.SetNameValue(RPC_SAMP_DEN_COEFF, osMultiField); |
219 | 0 | return asMD; |
220 | 0 | } |
221 | | |
222 | | } // namespace tiff_common |
223 | | } // namespace gdal |