Line data Source code
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 588 : char *PrepareTIFFErrorFormat(const char *module, const char *fmt)
33 :
34 : {
35 588 : const size_t nModuleSize = strlen(module);
36 588 : const size_t nModFmtSize = nModuleSize * 2 + strlen(fmt) + 2;
37 588 : char *pszModFmt = static_cast<char *>(CPLMalloc(nModFmtSize));
38 :
39 588 : size_t iOut = 0; // Used after for.
40 :
41 9737 : for (size_t iIn = 0; iIn < nModuleSize; ++iIn)
42 : {
43 9149 : if (module[iIn] == '%')
44 : {
45 0 : CPLAssert(iOut < nModFmtSize - 2);
46 0 : pszModFmt[iOut++] = '%';
47 0 : pszModFmt[iOut++] = '%';
48 : }
49 : else
50 : {
51 9149 : CPLAssert(iOut < nModFmtSize - 1);
52 9149 : pszModFmt[iOut++] = module[iIn];
53 : }
54 : }
55 588 : CPLAssert(iOut < nModFmtSize);
56 588 : pszModFmt[iOut] = '\0';
57 588 : strcat(pszModFmt, ":");
58 588 : strcat(pszModFmt, fmt);
59 :
60 588 : return pszModFmt;
61 : }
62 :
63 : /************************************************************************/
64 : /* TIFFColorMapTagToColorTable() */
65 : /************************************************************************/
66 :
67 150 : 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 : {
72 150 : auto poColorTable = std::make_unique<GDALColorTable>();
73 :
74 150 : if (nColorTableMultiplier == 0)
75 : {
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 139 : bool bFoundNonZeroEntry = false;
83 139 : bool bAllValuesMultipleOf256 = true;
84 139 : bool bAllValuesMultipleOf257 = true;
85 139 : unsigned short nMaxColor = 0;
86 293287 : for (int iColor = 0; iColor < nColorCount; ++iColor)
87 : {
88 293148 : if (panRed[iColor] > 0 || panGreen[iColor] > 0 ||
89 284833 : panBlue[iColor] > 0)
90 : {
91 8414 : bFoundNonZeroEntry = true;
92 : }
93 293148 : if ((panRed[iColor] % 256) != 0 || (panGreen[iColor] % 256) != 0 ||
94 284835 : (panBlue[iColor] % 256) != 0)
95 : {
96 8412 : bAllValuesMultipleOf256 = false;
97 : }
98 293148 : if ((panRed[iColor] % 257) != 0 || (panGreen[iColor] % 257) != 0 ||
99 293146 : (panBlue[iColor] % 257) != 0)
100 : {
101 2 : bAllValuesMultipleOf257 = false;
102 : }
103 :
104 293148 : nMaxColor = std::max(nMaxColor, panRed[iColor]);
105 293148 : nMaxColor = std::max(nMaxColor, panGreen[iColor]);
106 293148 : nMaxColor = std::max(nMaxColor, panBlue[iColor]);
107 : }
108 :
109 139 : if (nMaxColor > 0 && nMaxColor < 256)
110 : {
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 : "TIFF ColorTable seems to be improperly scaled with "
117 : "values all in [0,255] range, fixing up.");
118 : }
119 : else
120 : {
121 139 : if (!bAllValuesMultipleOf256 && !bAllValuesMultipleOf257)
122 : {
123 0 : CPLDebug("GTiff",
124 : "The color map contains entries which are not "
125 : "multiple of 256 or 257, so we don't know for "
126 : "sure how to remap them to [0, 255]. Default to "
127 : "using a 257 multiplication factor");
128 : }
129 139 : nColorTableMultiplier =
130 138 : (bFoundNonZeroEntry && bAllValuesMultipleOf256)
131 277 : ? 256
132 : : nDefaultColorTableMultiplier;
133 : }
134 : }
135 150 : CPLAssert(nColorTableMultiplier > 0);
136 150 : CPLAssert(nColorTableMultiplier <= 257);
137 360378 : for (int iColor = nColorCount - 1; iColor >= 0; iColor--)
138 : {
139 : const GDALColorEntry oEntry = {
140 360228 : static_cast<short>(panRed[iColor] / nColorTableMultiplier),
141 360228 : static_cast<short>(panGreen[iColor] / nColorTableMultiplier),
142 360228 : static_cast<short>(panBlue[iColor] / nColorTableMultiplier),
143 : static_cast<short>(
144 4096 : bNoDataSet && static_cast<int>(dfNoDataValue) == iColor ? 0
145 364324 : : 255)};
146 :
147 360228 : poColorTable->SetColorEntry(iColor, &oEntry);
148 : }
149 :
150 150 : return poColorTable;
151 : }
152 :
153 : /************************************************************************/
154 : /* TIFFRPCTagToRPCMetadata() */
155 : /************************************************************************/
156 :
157 38 : CPLStringList TIFFRPCTagToRPCMetadata(const double adfRPC[92])
158 : {
159 38 : CPLStringList asMD;
160 38 : asMD.SetNameValue(RPC_ERR_BIAS, CPLOPrintf("%.15g", adfRPC[0]));
161 38 : asMD.SetNameValue(RPC_ERR_RAND, CPLOPrintf("%.15g", adfRPC[1]));
162 38 : asMD.SetNameValue(RPC_LINE_OFF, CPLOPrintf("%.15g", adfRPC[2]));
163 38 : asMD.SetNameValue(RPC_SAMP_OFF, CPLOPrintf("%.15g", adfRPC[3]));
164 38 : asMD.SetNameValue(RPC_LAT_OFF, CPLOPrintf("%.15g", adfRPC[4]));
165 38 : asMD.SetNameValue(RPC_LONG_OFF, CPLOPrintf("%.15g", adfRPC[5]));
166 38 : asMD.SetNameValue(RPC_HEIGHT_OFF, CPLOPrintf("%.15g", adfRPC[6]));
167 38 : asMD.SetNameValue(RPC_LINE_SCALE, CPLOPrintf("%.15g", adfRPC[7]));
168 38 : asMD.SetNameValue(RPC_SAMP_SCALE, CPLOPrintf("%.15g", adfRPC[8]));
169 38 : asMD.SetNameValue(RPC_LAT_SCALE, CPLOPrintf("%.15g", adfRPC[9]));
170 38 : asMD.SetNameValue(RPC_LONG_SCALE, CPLOPrintf("%.15g", adfRPC[10]));
171 38 : asMD.SetNameValue(RPC_HEIGHT_SCALE, CPLOPrintf("%.15g", adfRPC[11]));
172 :
173 76 : CPLString osField;
174 76 : CPLString osMultiField;
175 :
176 798 : for (int i = 0; i < 20; ++i)
177 : {
178 760 : osField.Printf("%.15g", adfRPC[12 + i]);
179 760 : if (i > 0)
180 722 : osMultiField += " ";
181 : else
182 38 : osMultiField = "";
183 760 : osMultiField += osField;
184 : }
185 38 : asMD.SetNameValue(RPC_LINE_NUM_COEFF, osMultiField);
186 :
187 798 : for (int i = 0; i < 20; ++i)
188 : {
189 760 : osField.Printf("%.15g", adfRPC[32 + i]);
190 760 : if (i > 0)
191 722 : osMultiField += " ";
192 : else
193 38 : osMultiField = "";
194 760 : osMultiField += osField;
195 : }
196 38 : asMD.SetNameValue(RPC_LINE_DEN_COEFF, osMultiField);
197 :
198 798 : for (int i = 0; i < 20; ++i)
199 : {
200 760 : osField.Printf("%.15g", adfRPC[52 + i]);
201 760 : if (i > 0)
202 722 : osMultiField += " ";
203 : else
204 38 : osMultiField = "";
205 760 : osMultiField += osField;
206 : }
207 38 : asMD.SetNameValue(RPC_SAMP_NUM_COEFF, osMultiField);
208 :
209 798 : for (int i = 0; i < 20; ++i)
210 : {
211 760 : osField.Printf("%.15g", adfRPC[72 + i]);
212 760 : if (i > 0)
213 722 : osMultiField += " ";
214 : else
215 38 : osMultiField = "";
216 760 : osMultiField += osField;
217 : }
218 38 : asMD.SetNameValue(RPC_SAMP_DEN_COEFF, osMultiField);
219 76 : return asMD;
220 : }
221 :
222 : } // namespace tiff_common
223 : } // namespace gdal
|