Coverage Report

Created: 2025-06-13 06:29

/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