Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Color table implementation.
5 : * Author: Frank Warmerdam, warmerdam@pobox.com
6 : *
7 : **********************************************************************
8 : * Copyright (c) 2000, Frank Warmerdam
9 : * Copyright (c) 2009, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 :
30 : #include "cpl_port.h"
31 : #include "gdal_priv.h"
32 :
33 : #include <cstring>
34 : #include <exception>
35 : #include <memory>
36 : #include <vector>
37 :
38 : #include "cpl_error.h"
39 : #include "gdal.h"
40 :
41 : /************************************************************************/
42 : /* GDALColorTable() */
43 : /************************************************************************/
44 :
45 : /**
46 : * \brief Construct a new color table.
47 : *
48 : * This constructor is the same as the C GDALCreateColorTable() function.
49 : *
50 : * @param eInterpIn the interpretation to be applied to GDALColorEntry
51 : * values.
52 : */
53 :
54 1068 : GDALColorTable::GDALColorTable(GDALPaletteInterp eInterpIn) : eInterp(eInterpIn)
55 : {
56 1068 : }
57 :
58 : /************************************************************************/
59 : /* GDALCreateColorTable() */
60 : /************************************************************************/
61 :
62 : /**
63 : * \brief Construct a new color table.
64 : *
65 : * This function is the same as the C++ method GDALColorTable::GDALColorTable()
66 : */
67 52 : GDALColorTableH CPL_STDCALL GDALCreateColorTable(GDALPaletteInterp eInterp)
68 :
69 : {
70 52 : return GDALColorTable::ToHandle(new GDALColorTable(eInterp));
71 : }
72 :
73 : /************************************************************************/
74 : /* ~GDALColorTable() */
75 : /************************************************************************/
76 :
77 : /**
78 : * \brief Destructor.
79 : *
80 : * This destructor is the same as the C GDALDestroyColorTable() function.
81 : */
82 :
83 : GDALColorTable::~GDALColorTable() = default;
84 :
85 : /************************************************************************/
86 : /* GDALDestroyColorTable() */
87 : /************************************************************************/
88 :
89 : /**
90 : * \brief Destroys a color table.
91 : *
92 : * This function is the same as the C++ method GDALColorTable::~GDALColorTable()
93 : */
94 69 : void CPL_STDCALL GDALDestroyColorTable(GDALColorTableH hTable)
95 :
96 : {
97 69 : delete GDALColorTable::FromHandle(hTable);
98 69 : }
99 :
100 : /************************************************************************/
101 : /* GetColorEntry() */
102 : /************************************************************************/
103 :
104 : /**
105 : * \brief Fetch a color entry from table.
106 : *
107 : * This method is the same as the C function GDALGetColorEntry().
108 : *
109 : * @param i entry offset from zero to GetColorEntryCount()-1.
110 : *
111 : * @return pointer to internal color entry, or NULL if index is out of range.
112 : */
113 :
114 2091130 : const GDALColorEntry *GDALColorTable::GetColorEntry(int i) const
115 :
116 : {
117 2091130 : if (i < 0 || i >= static_cast<int>(aoEntries.size()))
118 0 : return nullptr;
119 :
120 2091130 : return &aoEntries[i];
121 : }
122 :
123 : /************************************************************************/
124 : /* GDALGetColorEntry() */
125 : /************************************************************************/
126 :
127 : /**
128 : * \brief Fetch a color entry from table.
129 : *
130 : * This function is the same as the C++ method GDALColorTable::GetColorEntry()
131 : */
132 5127 : const GDALColorEntry *CPL_STDCALL GDALGetColorEntry(GDALColorTableH hTable,
133 : int i)
134 :
135 : {
136 5127 : VALIDATE_POINTER1(hTable, "GDALGetColorEntry", nullptr);
137 :
138 5127 : return GDALColorTable::FromHandle(hTable)->GetColorEntry(i);
139 : }
140 :
141 : /************************************************************************/
142 : /* GetColorEntryAsRGB() */
143 : /************************************************************************/
144 :
145 : /**
146 : * \brief Fetch a table entry in RGB format.
147 : *
148 : * In theory this method should support translation of color palettes in
149 : * non-RGB color spaces into RGB on the fly, but currently it only works
150 : * on RGB color tables.
151 : *
152 : * This method is the same as the C function GDALGetColorEntryAsRGB().
153 : *
154 : * @param i entry offset from zero to GetColorEntryCount()-1.
155 : *
156 : * @param poEntry the existing GDALColorEntry to be overrwritten with the RGB
157 : * values.
158 : *
159 : * @return TRUE on success, or FALSE if the conversion isn't supported.
160 : */
161 :
162 95293 : int GDALColorTable::GetColorEntryAsRGB(int i, GDALColorEntry *poEntry) const
163 :
164 : {
165 95293 : if (eInterp != GPI_RGB || i < 0 || i >= static_cast<int>(aoEntries.size()))
166 0 : return FALSE;
167 :
168 95293 : *poEntry = aoEntries[i];
169 95293 : return TRUE;
170 : }
171 :
172 : /************************************************************************/
173 : /* GDALGetColorEntryAsRGB() */
174 : /************************************************************************/
175 :
176 : /**
177 : * \brief Fetch a table entry in RGB format.
178 : *
179 : * This function is the same as the C++ method
180 : * GDALColorTable::GetColorEntryAsRGB().
181 : */
182 3393 : int CPL_STDCALL GDALGetColorEntryAsRGB(GDALColorTableH hTable, int i,
183 : GDALColorEntry *poEntry)
184 :
185 : {
186 3393 : VALIDATE_POINTER1(hTable, "GDALGetColorEntryAsRGB", 0);
187 3393 : VALIDATE_POINTER1(poEntry, "GDALGetColorEntryAsRGB", 0);
188 :
189 3393 : return GDALColorTable::FromHandle(hTable)->GetColorEntryAsRGB(i, poEntry);
190 : }
191 :
192 : /************************************************************************/
193 : /* SetColorEntry() */
194 : /************************************************************************/
195 :
196 : /**
197 : * \brief Set entry in color table.
198 : *
199 : * Note that the passed in color entry is copied, and no internal reference
200 : * to it is maintained. Also, the passed in entry must match the color
201 : * interpretation of the table to which it is being assigned.
202 : *
203 : * The table is grown as needed to hold the supplied offset.
204 : *
205 : * This function is the same as the C function GDALSetColorEntry().
206 : *
207 : * @param i entry offset from zero to GetColorEntryCount()-1.
208 : * @param poEntry value to assign to table.
209 : */
210 :
211 432119 : void GDALColorTable::SetColorEntry(int i, const GDALColorEntry *poEntry)
212 :
213 : {
214 432119 : if (i < 0)
215 0 : return;
216 :
217 : try
218 : {
219 432119 : if (i >= static_cast<int>(aoEntries.size()))
220 : {
221 49059 : GDALColorEntry oBlack = {0, 0, 0, 0};
222 49059 : aoEntries.resize(i + 1, oBlack);
223 : }
224 :
225 432119 : aoEntries[i] = *poEntry;
226 : }
227 0 : catch (std::exception &e)
228 : {
229 0 : CPLError(CE_Failure, CPLE_AppDefined, "%s", e.what());
230 : }
231 : }
232 :
233 : /************************************************************************/
234 : /* GDALSetColorEntry() */
235 : /************************************************************************/
236 :
237 : /**
238 : * \brief Set entry in color table.
239 : *
240 : * This function is the same as the C++ method GDALColorTable::SetColorEntry()
241 : */
242 3955 : void CPL_STDCALL GDALSetColorEntry(GDALColorTableH hTable, int i,
243 : const GDALColorEntry *poEntry)
244 :
245 : {
246 3955 : VALIDATE_POINTER0(hTable, "GDALSetColorEntry");
247 3955 : VALIDATE_POINTER0(poEntry, "GDALSetColorEntry");
248 :
249 3955 : GDALColorTable::FromHandle(hTable)->SetColorEntry(i, poEntry);
250 : }
251 :
252 : /************************************************************************/
253 : /* Clone() */
254 : /************************************************************************/
255 :
256 : /**
257 : * \brief Make a copy of a color table.
258 : *
259 : * This method is the same as the C function GDALCloneColorTable().
260 : */
261 :
262 273 : GDALColorTable *GDALColorTable::Clone() const
263 :
264 : {
265 273 : return new GDALColorTable(*this);
266 : }
267 :
268 : /************************************************************************/
269 : /* GDALCloneColorTable() */
270 : /************************************************************************/
271 :
272 : /**
273 : * \brief Make a copy of a color table.
274 : *
275 : * This function is the same as the C++ method GDALColorTable::Clone()
276 : */
277 17 : GDALColorTableH CPL_STDCALL GDALCloneColorTable(GDALColorTableH hTable)
278 :
279 : {
280 17 : VALIDATE_POINTER1(hTable, "GDALCloneColorTable", nullptr);
281 :
282 17 : return GDALColorTable::ToHandle(
283 17 : GDALColorTable::FromHandle(hTable)->Clone());
284 : }
285 :
286 : /************************************************************************/
287 : /* GetColorEntryCount() */
288 : /************************************************************************/
289 :
290 : /**
291 : * \brief Get number of color entries in table.
292 : *
293 : * This method is the same as the function GDALGetColorEntryCount().
294 : *
295 : * @return the number of color entries.
296 : */
297 :
298 147035 : int GDALColorTable::GetColorEntryCount() const
299 :
300 : {
301 147035 : return static_cast<int>(aoEntries.size());
302 : }
303 :
304 : /************************************************************************/
305 : /* GDALGetColorEntryCount() */
306 : /************************************************************************/
307 :
308 : /**
309 : * \brief Get number of color entries in table.
310 : *
311 : * This function is the same as the C++ method
312 : * GDALColorTable::GetColorEntryCount()
313 : */
314 203 : int CPL_STDCALL GDALGetColorEntryCount(GDALColorTableH hTable)
315 :
316 : {
317 203 : VALIDATE_POINTER1(hTable, "GDALGetColorEntryCount", 0);
318 :
319 203 : return GDALColorTable::FromHandle(hTable)->GetColorEntryCount();
320 : }
321 :
322 : /************************************************************************/
323 : /* GetPaletteInterpretation() */
324 : /************************************************************************/
325 :
326 : /**
327 : * \brief Fetch palette interpretation.
328 : *
329 : * The returned value is used to interpret the values in the GDALColorEntry.
330 : *
331 : * This method is the same as the C function GDALGetPaletteInterpretation().
332 : *
333 : * @return palette interpretation enumeration value, usually GPI_RGB.
334 : */
335 :
336 18 : GDALPaletteInterp GDALColorTable::GetPaletteInterpretation() const
337 :
338 : {
339 18 : return eInterp;
340 : }
341 :
342 : /************************************************************************/
343 : /* GDALGetPaletteInterpretation() */
344 : /************************************************************************/
345 :
346 : /**
347 : * \brief Fetch palette interpretation.
348 : *
349 : * This function is the same as the C++ method
350 : * GDALColorTable::GetPaletteInterpretation()
351 : */
352 : GDALPaletteInterp CPL_STDCALL
353 9 : GDALGetPaletteInterpretation(GDALColorTableH hTable)
354 :
355 : {
356 9 : VALIDATE_POINTER1(hTable, "GDALGetPaletteInterpretation", GPI_Gray);
357 :
358 9 : return GDALColorTable::FromHandle(hTable)->GetPaletteInterpretation();
359 : }
360 :
361 : /**
362 : * \brief Create color ramp
363 : *
364 : * Automatically creates a color ramp from one color entry to
365 : * another. It can be called several times to create multiples ramps
366 : * in the same color table.
367 : *
368 : * This function is the same as the C function GDALCreateColorRamp().
369 : *
370 : * @param nStartIndex index to start the ramp on the color table [0..255]
371 : * @param psStartColor a color entry value to start the ramp
372 : * @param nEndIndex index to end the ramp on the color table [0..255]
373 : * @param psEndColor a color entry value to end the ramp
374 : * @return total number of entries, -1 to report error
375 : */
376 :
377 257 : int GDALColorTable::CreateColorRamp(int nStartIndex,
378 : const GDALColorEntry *psStartColor,
379 : int nEndIndex,
380 : const GDALColorEntry *psEndColor)
381 : {
382 : // Validate indexes.
383 257 : if (nStartIndex < 0 || nStartIndex > 255 || nEndIndex < 0 ||
384 257 : nEndIndex > 255 || nStartIndex > nEndIndex)
385 : {
386 0 : return -1;
387 : }
388 :
389 : // Validate color entries.
390 257 : if (psStartColor == nullptr || psEndColor == nullptr)
391 : {
392 0 : return -1;
393 : }
394 :
395 : // Calculate number of colors in-between + 1.
396 257 : const int nColors = nEndIndex - nStartIndex;
397 :
398 : // Set starting color.
399 257 : SetColorEntry(nStartIndex, psStartColor);
400 :
401 257 : if (nColors == 0)
402 : {
403 0 : return GetColorEntryCount(); // Only one color. No ramp to create.
404 : }
405 :
406 : // Set ending color.
407 257 : SetColorEntry(nEndIndex, psEndColor);
408 :
409 : // Calculate the slope of the linear transformation.
410 257 : const double dfColors = static_cast<double>(nColors);
411 257 : const double dfSlope1 = (psEndColor->c1 - psStartColor->c1) / dfColors;
412 257 : const double dfSlope2 = (psEndColor->c2 - psStartColor->c2) / dfColors;
413 257 : const double dfSlope3 = (psEndColor->c3 - psStartColor->c3) / dfColors;
414 257 : const double dfSlope4 = (psEndColor->c4 - psStartColor->c4) / dfColors;
415 :
416 : // Loop through the new colors.
417 257 : GDALColorEntry sColor = *psStartColor;
418 :
419 764 : for (int i = 1; i < nColors; i++)
420 : {
421 507 : sColor.c1 = static_cast<short>(i * dfSlope1 + psStartColor->c1);
422 507 : sColor.c2 = static_cast<short>(i * dfSlope2 + psStartColor->c2);
423 507 : sColor.c3 = static_cast<short>(i * dfSlope3 + psStartColor->c3);
424 507 : sColor.c4 = static_cast<short>(i * dfSlope4 + psStartColor->c4);
425 :
426 507 : SetColorEntry(nStartIndex + i, &sColor);
427 : }
428 :
429 : // Return the total number of colors.
430 257 : return GetColorEntryCount();
431 : }
432 :
433 : /************************************************************************/
434 : /* GDALCreateColorRamp() */
435 : /************************************************************************/
436 :
437 : /**
438 : * \brief Create color ramp
439 : *
440 : * This function is the same as the C++ method GDALColorTable::CreateColorRamp()
441 : */
442 1 : void CPL_STDCALL GDALCreateColorRamp(GDALColorTableH hTable, int nStartIndex,
443 : const GDALColorEntry *psStartColor,
444 : int nEndIndex,
445 : const GDALColorEntry *psEndColor)
446 : {
447 1 : VALIDATE_POINTER0(hTable, "GDALCreateColorRamp");
448 :
449 1 : GDALColorTable::FromHandle(hTable)->CreateColorRamp(
450 : nStartIndex, psStartColor, nEndIndex, psEndColor);
451 : }
452 :
453 : /************************************************************************/
454 : /* IsSame() */
455 : /************************************************************************/
456 :
457 : /**
458 : * \brief Returns if the current color table is the same as another one.
459 : *
460 : * @param poOtherCT other color table to be compared to.
461 : * @return TRUE if both color tables are identical.
462 : * @since GDAL 2.0
463 : */
464 :
465 14 : int GDALColorTable::IsSame(const GDALColorTable *poOtherCT) const
466 : {
467 42 : return aoEntries.size() == poOtherCT->aoEntries.size() &&
468 14 : (aoEntries.empty() ||
469 14 : memcmp(&aoEntries[0], &poOtherCT->aoEntries[0],
470 28 : aoEntries.size() * sizeof(GDALColorEntry)) == 0);
471 : }
472 :
473 : /************************************************************************/
474 : /* IsIdentity() */
475 : /************************************************************************/
476 :
477 : /**
478 : * \brief Returns if the current color table is the identity, that is
479 : * for each index i, colortable[i].c1 = .c2 = .c3 = i and .c4 = 255
480 : *
481 : * @since GDAL 3.4.1
482 : */
483 :
484 18 : bool GDALColorTable::IsIdentity() const
485 : {
486 290 : for (int i = 0; i < static_cast<int>(aoEntries.size()); ++i)
487 : {
488 562 : if (aoEntries[i].c1 != i || aoEntries[i].c2 != i ||
489 562 : aoEntries[i].c3 != i || aoEntries[i].c4 != 255)
490 : {
491 17 : return false;
492 : }
493 : }
494 1 : return true;
495 : }
|