Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
colorchecker.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020-2021 Aurélien PIERRE.
4 Copyright (C) 2021 Hubert Kowalski.
5 Copyright (C) 2021 Marco Carrarini.
6 Copyright (C) 2021 Ralf Brown.
7 Copyright (C) 2022 Martin Bařinka.
8 Copyright (C) 2023 Luca Zulberti.
9 Copyright (C) 2026 Guillaume Stutin.
10
11 darktable is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
15
16 darktable is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with darktable. If not, see <http://www.gnu.org/licenses/>.
23*/
24
25#ifndef DT_COMMON_COLORCHECKER_H
26#define DT_COMMON_COLORCHECKER_H
27
28#include "system/macros.h"
29#include "system/mem_alloc.h"
30#include "system/simd.h"
31#include "common/logging.h"
32
33#include <glib/gi18n.h>
34
39// types of targets we support
53
54// helper to deal with patch color
56{
57 char *name; // mnemonic name for the patch
58 dt_aligned_pixel_t Lab; // reference color in CIE Lab
59
60 // (x, y) position of the patch center, relatively to the guides (white dots)
61 // in ratio of the grid dimension along that axis
62 struct
63 {
64 float x;
65 float y;
66 };
68
69typedef struct dt_color_checker_t
70{
71 char *name;
72 char *author;
73 char *date;
76
77 float ratio; // format ratio of the chart, guide to guide (white dots)
78 float radius; // radius of a patch in ratio of the checker diagonal
79 size_t patches; // number of patches in target
80 size_t size[2]; // dimension along x, y axes
81 size_t middle_grey; // index of the closest patch to 20% neutral grey
82 size_t white; // index of the closest patch to pure white
83 size_t black; // index of the closest patch to pure black
84 dt_color_checker_patch *values; // pointer to an array of colors
85 gboolean finished; // whether the color checker is loaded or not
87
89 { "A1", { 37.986, 13.555, 14.059 }, { 0.087, 0.125}},
90 { "A2", { 65.711, 18.13, 17.81 }, { 0.250, 0.125}},
91 { "A3", { 49.927, -04.88, -21.905 }, { 0.417, 0.125}},
92 { "A4", { 43.139, -13.095, 21.905 }, { 0.584, 0.125}},
93 { "A5", { 55.112, 08.844, -25.399 }, { 0.751, 0.125}},
94 { "A6", { 70.719, -33.397, -0.199 }, { 0.918, 0.125}},
95 { "B1", { 62.661, 36.067, 57.096 }, { 0.087, 0.375}},
96 { "B2", { 40.02, 10.41, -45.964 }, { 0.250, 0.375}},
97 { "B3", { 51.124, 48.239, 16.248 }, { 0.417, 0.375}},
98 { "B4", { 30.325, 22.976, -21.587 }, { 0.584, 0.375}},
99 { "B5", { 72.532, -23.709, 57.255 }, { 0.751, 0.375}},
100 { "B6", { 71.941, 19.363, 67.857 }, { 0.918, 0.375}},
101 { "C1", { 28.778, 14.179, -50.297 }, { 0.087, 0.625}},
102 { "C2", { 55.261, -38.342, 31.37 }, { 0.250, 0.625}},
103 { "C3", { 42.101, 53.378, 28.19 }, { 0.417, 0.625}},
104 { "C4", { 81.733, 04.039, 79.819 }, { 0.584, 0.625}},
105 { "C5", { 51.935, 49.986, -14.574 }, { 0.751, 0.625}},
106 { "C6", { 51.038, -28.631, -28.638 }, { 0.918, 0.625}},
107 { "D1", { 96.539, -0.425, 1.186 }, { 0.087, 0.875}},
108 { "D2", { 81.257, -0.638, -0.335 }, { 0.250, 0.875}},
109 { "D3", { 66.766, -0.734, -0.504 }, { 0.417, 0.875}},
110 { "D4", { 50.867, -0.153, -0.27 }, { 0.584, 0.875}},
111 { "D5", { 35.656, -0.421, -1.231 }, { 0.751, 0.875}},
112 { "D6", { 20.461, -0.079, -0.973 }, { 0.918, 0.875}} };
113
114static dt_color_checker_t xrite_24_2000 = { .name = "Xrite ColorChecker 24 before 2014",
115 .author = "X-Rite",
116 .date = "3/27/2000",
117 .manufacturer = "X-Rite/Gretag Macbeth",
119 .ratio = 2.f / 3.f,
120 .radius = 0.055f,
121 .patches = 24,
122 .size = { 4, 6 },
123 .middle_grey = 21,
124 .white = 18,
125 .black = 23,
126 .values = xrite_24_2000_patches };
127
129 { "A1", { 37.54, 14.37, 14.92 }, { 0.087, 0.125}},
130 { "A2", { 64.66, 19.27, 17.50 }, { 0.250, 0.125}},
131 { "A3", { 49.32, -03.82, -22.54 }, { 0.417, 0.125}},
132 { "A4", { 43.46, -12.74, 22.72 }, { 0.584, 0.125}},
133 { "A5", { 54.94, 09.61, -24.79 }, { 0.751, 0.125}},
134 { "A6", { 70.48, -32.26, -00.37 }, { 0.918, 0.125}},
135 { "B1", { 62.73, 35.83, 56.50 }, { 0.087, 0.375}},
136 { "B2", { 39.43, 10.75, -45.17 }, { 0.250, 0.375}},
137 { "B3", { 50.57, 48.64, 16.67 }, { 0.417, 0.375}},
138 { "B4", { 30.10, 22.54, -20.87 }, { 0.584, 0.375}},
139 { "B5", { 71.77, -24.13, 58.19 }, { 0.751, 0.375}},
140 { "B6", { 71.51, 18.24, 67.37 }, { 0.918, 0.375}},
141 { "C1", { 28.37, 15.42, -49.80 }, { 0.087, 0.625}},
142 { "C2", { 54.38, -39.72, 32.27 }, { 0.250, 0.625}},
143 { "C3", { 42.43, 51.05, 28.62 }, { 0.417, 0.625}},
144 { "C4", { 81.80, 02.67, 80.41 }, { 0.584, 0.625}},
145 { "C5", { 50.63, 51.28, -14.12 }, { 0.751, 0.625}},
146 { "C6", { 49.57, -29.71, -28.32 }, { 0.918, 0.625}},
147 { "D1", { 95.19, -01.03, 02.93 }, { 0.087, 0.875}},
148 { "D2", { 81.29, -00.57, 00.44 }, { 0.250, 0.875}},
149 { "D3", { 66.89, -00.75, -00.06 }, { 0.417, 0.875}},
150 { "D4", { 50.76, -00.13, 00.14 }, { 0.584, 0.875}},
151 { "D5", { 35.63, -00.46, -00.48 }, { 0.751, 0.875}},
152 { "D6", { 20.64, 00.07, -00.46 }, { 0.918, 0.875}} };
153
154static dt_color_checker_t xrite_24_2014 = { .name = "Xrite ColorChecker 24 after 2014",
155 .author = "X-Rite",
156 .date = "3/28/2015",
157 .manufacturer = "X-Rite/Gretag Macbeth",
159 .ratio = 2.f / 3.f,
160 .radius = 0.055f,
161 .patches = 24,
162 .size = { 4, 6 },
163 .middle_grey = 21,
164 .white = 18,
165 .black = 23,
166 .values = xrite_24_2014_patches };
167
168
169// dimensions between reference dots : 197 mm width x 135 mm height
170// patch width : 26x26 mm
171// outer gutter : 8 mm
172// internal gutters (gap between patches) : 5 mm
173
175 { "A1", { 96.04, 2.16, 2.60 }, { 0.107, 0.844 } },
176 { "A2", { 80.44, 1.17, 2.05 }, { 0.264, 0.844 } },
177 { "A3", { 65.52, 0.69, 1.86 }, { 0.421, 0.844 } },
178 { "A4", { 49.62, 0.58, 1.56 }, { 0.579, 0.844 } },
179 { "A5", { 33.55, 0.35, 1.40 }, { 0.736, 0.844 } },
180 { "A6", { 16.91, 1.43, -0.81 }, { 0.893, 0.844 } },
181 { "B1", { 47.12, -32.50, -28.75 }, { 0.107, 0.615 } },
182 { "B2", { 50.49, 53.45, -13.55 }, { 0.264, 0.615 } },
183 { "B3", { 83.61, 3.36, 87.02 }, { 0.421, 0.615 } },
184 { "B4", { 41.05, 60.75, 31.17 }, { 0.579, 0.615 } },
185 { "B5", { 54.14, -40.80, 34.75 }, { 0.736, 0.615 } },
186 { "B6", { 24.75, 13.78, -49.48 }, { 0.893, 0.615 } },
187 { "C1", { 60.94, 38.21, 61.31 }, { 0.107, 0.385 } },
188 { "C2", { 37.80, 7.30, -43.04 }, { 0.264, 0.385 } },
189 { "C3", { 49.81, 48.50, 15.76 }, { 0.421, 0.385 } },
190 { "C4", { 28.88, 19.36, -24.48 }, { 0.579, 0.385 } },
191 { "C5", { 72.45, -23.60, 60.47 }, { 0.736, 0.385 } },
192 { "C6", { 71.65, 23.74, 72.28 }, { 0.893, 0.385 } },
193 { "D1", { 70.19, -31.90, 1.98 }, { 0.107, 0.155 } },
194 { "D2", { 54.38, 8.84, -25.71 }, { 0.264, 0.155 } },
195 { "D3", { 42.03, -15.80, 22.93 }, { 0.421, 0.155 } },
196 { "D4", { 48.82, -5.11, -23.08 }, { 0.579, 0.155 } },
197 { "D5", { 65.10, 18.14, 18.68 }, { 0.736, 0.155 } },
198 { "D6", { 36.13, 14.15, 15.78 }, { 0.893, 0.155 } } };
199
200static dt_color_checker_t spyder_24 = { .name = "Datacolor SpyderCheckr 24 before 2018",
201 .author = "Aur\303\251lien PIERRE",
202 .date = "dec, 9 2016",
203 .manufacturer = "DataColor",
205 .ratio = 2.f / 3.f,
206 .radius = 0.035,
207 .patches = 24,
208 .size = { 4, 6 },
209 .middle_grey = 03,
210 .white = 00,
211 .black = 05,
212 .values = spyder_24_patches };
213
214
215// dimensions between reference dots : 197 mm width x 135 mm height
216// patch width : 26x26 mm
217// outer gutter : 8 mm
218// internal gutters (gap between patches) : 5 mm
219
220static dt_color_checker_patch spyder_24_v2_patch[] = {{ "A1", { 96.04, 2.16, 2.60 }, { 0.107, 0.844 } },
221 { "A2", { 80.44, 1.17, 2.05 }, { 0.264, 0.844 } },
222 { "A3", { 65.52, 0.69, 1.86 }, { 0.421, 0.844 } },
223 { "A4", { 49.62, 0.58, 1.56 }, { 0.579, 0.844 } },
224 { "A5", { 33.55, 0.35, 1.40 }, { 0.736, 0.844 } },
225 { "A6", { 16.91, 1.43, -0.81 }, { 0.893, 0.844 } },
226 { "B1", { 47.12, -32.50, -28.75 }, { 0.107, 0.615 } },
227 { "B2", { 50.49, 53.45, -13.55 }, { 0.264, 0.615 } },
228 { "B3", { 83.61, 3.36, 87.02 }, { 0.421, 0.615 } },
229 { "B4", { 41.05, 60.75, 31.17 }, { 0.579, 0.615 } },
230 { "B5", { 54.14, -40.80, 34.75 }, { 0.736, 0.615 } },
231 { "B6", { 24.75, 13.78, -49.48 }, { 0.893, 0.615 } },
232 { "C1", { 60.94, 38.21, 61.31 }, { 0.107, 0.385 } },
233 { "C2", { 37.80, 7.30, -43.04 }, { 0.264, 0.385 } },
234 { "C3", { 49.81, 48.50, 15.76 }, { 0.421, 0.385 } },
235 { "C4", { 28.88, 19.36, -24.48 }, { 0.579, 0.385 } },
236 { "C5", { 72.45, -23.57, 60.47 }, { 0.736, 0.385 } },
237 { "C6", { 71.65, 23.74, 72.28 }, { 0.893, 0.385 } },
238 { "D1", { 70.19, -31.85, 1.98 }, { 0.107, 0.155 } },
239 { "D2", { 54.38, 8.84, -25.71 }, { 0.264, 0.155 } },
240 { "D3", { 42.03, -15.78, 22.93 }, { 0.421, 0.155 } },
241 { "D4", { 48.82, -5.11, -23.08 }, { 0.579, 0.155 } },
242 { "D5", { 65.10, 18.14, 18.68 }, { 0.736, 0.155 } },
243 { "D6", { 36.13, 14.15, 15.78 }, { 0.893, 0.155 } } };
244
245static dt_color_checker_t spyder_24_v2 = { .name = "Datacolor SpyderCheckr 24 after 2018",
246 .author = "Aur\303\251lien PIERRE",
247 .date = "dec, 9 2016",
248 .manufacturer = "DataColor",
250 .ratio = 2.f / 3.f,
251 .radius = 0.035,
252 .patches = 24,
253 .size = { 4, 6 },
254 .middle_grey = 03,
255 .white = 00,
256 .black = 05,
257 .values = spyder_24_v2_patch };
258
259
260// dimensions between reference dots : 297 mm width x 197 mm height
261// patch width : 26x26 mm
262// outer gutter : 8 mm
263// internal gutters (gap between patches) : 5 mm
264
265static dt_color_checker_patch spyder_48_patches[] = { { "A1", { 61.35, 34.81, 18.38 }, { 0.071, 0.107 } },
266 { "A2", { 75.50 , 5.84, 50.42 }, { 0.071, 0.264 } },
267 { "A3", { 66.82, -25.1, 23.47 }, { 0.071, 0.421 } },
268 { "A4", { 60.53, -22.6, -20.40 }, { 0.071, 0.579 } },
269 { "A5", { 59.66, -2.03, -28.46 }, { 0.071, 0.736 } },
270 { "A6", { 59.15, 30.83, -5.72 }, { 0.071, 0.893 } },
271 { "B1", { 82.68, 5.03, 3.02 }, { 0.175, 0.107 } },
272 { "B2", { 82.25, -2.42, 3.78 }, { 0.175, 0.264 } },
273 { "B3", { 82.29, 2.20, -2.04 }, { 0.175, 0.421 } },
274 { "B4", { 24.89, 4.43, 0.78 }, { 0.175, 0.579 } },
275 { "B5", { 25.16, -3.88, 2.13 }, { 0.175, 0.736 } },
276 { "B6", { 26.13, 2.61, -5.03 }, { 0.175, 0.893 } },
277 { "C1", { 85.42, 9.41, 14.49 }, { 0.279, 0.107 } },
278 { "C2", { 74.28, 9.05, 27.21 }, { 0.279, 0.264 } },
279 { "C3", { 64.57, 12.39, 37.24 }, { 0.279, 0.421 } },
280 { "C4", { 44.49, 17.23, 26.24 }, { 0.279, 0.579 } },
281 { "C5", { 25.29, 7.95, 8.87 }, { 0.279, 0.736 } },
282 { "C6", { 22.67, 2.11, -1.10 }, { 0.279, 0.893 } },
283 { "D1", { 92.72, 1.89, 2.76 }, { 0.384, 0.107 } },
284 { "D2", { 88.85, 1.59, 2.27 }, { 0.384, 0.264 } },
285 { "D3", { 73.42, 0.99, 1.89 }, { 0.384, 0.421 } },
286 { "D4", { 57.15, 0.57, 1.19 }, { 0.384, 0.579 } },
287 { "D5", { 41.57, 0.24, 1.45 }, { 0.384, 0.736 } },
288 { "D6", { 25.65, 1.24, 0.05 }, { 0.384, 0.893 } },
289 { "E1", { 96.04, 2.16, 2.60 }, { 0.616, 0.107 } },
290 { "E2", { 80.44, 1.17, 2.05 }, { 0.616, 0.264 } },
291 { "E3", { 65.52, 0.69, 1.86 }, { 0.616, 0.421 } },
292 { "E4", { 49.62, 0.58, 1.56 }, { 0.616, 0.579 } },
293 { "E5", { 33.55, 0.35, 1.40 }, { 0.616, 0.736 } },
294 { "E6", { 16.91, 1.43, -0.81 }, { 0.616, 0.893 } },
295 { "F1", { 47.12, -32.50, -28.75 }, { 0.721, 0.107 } },
296 { "F2", { 50.49, 53.45, -13.55 }, { 0.721, 0.264 } },
297 { "F3", { 83.61, 3.36, 87.02 }, { 0.721, 0.421 } },
298 { "F4", { 41.05, 60.75, 31.17 }, { 0.721, 0.579 } },
299 { "F5", { 54.14, -40.80, 34.75 }, { 0.721, 0.736 } },
300 { "F6", { 24.75, 13.78, -49.48 }, { 0.721, 0.893 } },
301 { "G1", { 60.94, 38.21, 61.31 }, { 0.825, 0.107 } },
302 { "G2", { 37.80, 7.30, -43.04 }, { 0.825, 0.264 } },
303 { "G3", { 49.81, 48.50, 15.76 }, { 0.825, 0.421 } },
304 { "G4", { 28.88, 19.36, -24.48 }, { 0.825, 0.579 } },
305 { "G5", { 72.45, -23.60, 60.47 }, { 0.825, 0.736 } },
306 { "G6", { 71.65, 23.74, 72.28 }, { 0.825, 0.893 } },
307 { "H1", { 70.19, -31.90, 1.98 }, { 0.929, 0.107 } },
308 { "H2", { 54.38, 8.84, -25.71 }, { 0.929, 0.264 } },
309 { "H3", { 42.03, -15.80, 22.93 }, { 0.929, 0.421 } },
310 { "H4", { 48.82, -5.11, -23.08 }, { 0.929, 0.579 } },
311 { "H5", { 65.10, 18.14, 18.68 }, { 0.929, 0.736 } },
312 { "H6", { 36.13, 14.15, 15.78 }, { 0.929, 0.893 } } };
313
314static dt_color_checker_t spyder_48 = { .name = "Datacolor SpyderCheckr 48 before 2018",
315 .author = "Aur\303\251lien PIERRE",
316 .date = "dec, 9 2016",
317 .manufacturer = "DataColor",
319 .ratio = 2.f / 3.f,
320 .radius = 0.035,
321 .patches = 48,
322 .size = { 8, 6 },
323 .middle_grey = 27,
324 .white = 24,
325 .black = 29,
326 .values = spyder_48_patches };
327
328
329// dimensions between reference dots : 297 mm width x 197 mm height
330// patch width : 26x26 mm
331// outer gutter : 8 mm
332// internal gutters (gap between patches) : 5 mm
333
334static dt_color_checker_patch spyder_48_v2_patch[] = { { "A1", { 61.35, 34.81, 18.38 }, { 0.071, 0.107 } },
335 { "A2", { 75.50 , 5.84, 50.42 }, { 0.071, 0.264 } },
336 { "A3", { 66.82, -25.1, 23.47 }, { 0.071, 0.421 } },
337 { "A4", { 60.53, -22.62, -20.40 }, { 0.071, 0.579 } },
338 { "A5", { 59.66, -2.03, -28.46 }, { 0.071, 0.736 } },
339 { "A6", { 59.15, 30.83, -5.72 }, { 0.071, 0.893 } },
340 { "B1", { 82.68, 5.03, 3.02 }, { 0.175, 0.107 } },
341 { "B2", { 82.25, -2.42, 3.78 }, { 0.175, 0.264 } },
342 { "B3", { 82.29, 2.20, -2.04 }, { 0.175, 0.421 } },
343 { "B4", { 24.89, 4.43, 0.78 }, { 0.175, 0.579 } },
344 { "B5", { 25.16, -3.88, 2.13 }, { 0.175, 0.736 } },
345 { "B6", { 26.13, 2.61, -5.03 }, { 0.175, 0.893 } },
346 { "C1", { 85.42, 9.41, 14.49 }, { 0.279, 0.107 } },
347 { "C2", { 74.28, 9.05, 27.21 }, { 0.279, 0.264 } },
348 { "C3", { 64.57, 12.39, 37.24 }, { 0.279, 0.421 } },
349 { "C4", { 44.49, 17.23, 26.24 }, { 0.279, 0.579 } },
350 { "C5", { 25.29, 7.95, 8.87 }, { 0.279, 0.736 } },
351 { "C6", { 22.67, 2.11, -1.10 }, { 0.279, 0.893 } },
352 { "D1", { 92.72, 1.89, 2.76 }, { 0.384, 0.107 } },
353 { "D2", { 88.85, 1.59, 2.27 }, { 0.384, 0.264 } },
354 { "D3", { 73.42, 0.99, 1.89 }, { 0.384, 0.421 } },
355 { "D4", { 57.15, 0.57, 1.19 }, { 0.384, 0.579 } },
356 { "D5", { 41.57, 0.24, 1.45 }, { 0.384, 0.736 } },
357 { "D6", { 25.65, 1.24, 0.05 }, { 0.384, 0.893 } },
358 { "E1", { 96.04, 2.16, 2.60 }, { 0.616, 0.107 } },
359 { "E2", { 80.44, 1.17, 2.05 }, { 0.616, 0.264 } },
360 { "E3", { 65.52, 0.69, 1.86 }, { 0.616, 0.421 } },
361 { "E4", { 49.62, 0.58, 1.56 }, { 0.616, 0.579 } },
362 { "E5", { 33.55, 0.35, 1.40 }, { 0.616, 0.736 } },
363 { "E6", { 16.91, 1.43, -0.81 }, { 0.616, 0.893 } },
364 { "F1", { 47.12, -32.50, -28.75 }, { 0.721, 0.107 } },
365 { "F2", { 50.49, 53.45, -13.55 }, { 0.721, 0.264 } },
366 { "F3", { 83.61, 3.36, 87.02 }, { 0.721, 0.421 } },
367 { "F4", { 41.05, 60.75, 31.17 }, { 0.721, 0.579 } },
368 { "F5", { 54.14, -40.80, 34.75 }, { 0.721, 0.736 } },
369 { "F6", { 24.75, 13.78, -49.48 }, { 0.721, 0.893 } },
370 { "G1", { 60.94, 38.21, 61.31 }, { 0.825, 0.107 } },
371 { "G2", { 37.80, 7.30, -43.04 }, { 0.825, 0.264 } },
372 { "G3", { 49.81, 48.50, 15.76 }, { 0.825, 0.421 } },
373 { "G4", { 28.88, 19.36, -24.48 }, { 0.825, 0.579 } },
374 { "G5", { 72.45, -23.57, 60.47 }, { 0.825, 0.736 } },
375 { "G6", { 71.65, 23.74, 72.28 }, { 0.825, 0.893 } },
376 { "H1", { 70.19, -31.85, 1.98 }, { 0.929, 0.107 } },
377 { "H2", { 54.38, 8.84, -25.71 }, { 0.929, 0.264 } },
378 { "H3", { 42.03, -15.78, 22.93 }, { 0.929, 0.421 } },
379 { "H4", { 48.82, -5.11, -23.08 }, { 0.929, 0.579 } },
380 { "H5", { 65.10, 18.14, 18.68 }, { 0.929, 0.736 } },
381 { "H6", { 36.13, 14.15, 15.78 }, { 0.929, 0.893 } } };
382
383static dt_color_checker_t spyder_48_v2 = { .name = "Datacolor SpyderCheckr 48 after 2018",
384 .author = "Aur\303\251lien PIERRE",
385 .date = "dec, 9 2016",
386 .manufacturer = "DataColor",
388 .ratio = 2.f / 3.f,
389 .radius = 0.035,
390 .patches = 48,
391 .size = { 8, 6 },
392 .middle_grey = 27,
393 .white = 24,
394 .black = 29,
395 .values = spyder_48_v2_patch };
396
397
398// One panel of the chart above, shot on its own: columns A..D here are the 48's columns
399// E..H, the right panel -- the full neutral ramp plus the saturated colors, which is the
400// half that carries the calibration. Same convention as above: the bounding box goes on the
401// four outer corners of the black panel, and the coordinates are normalized to it.
402
404 { "A1", { 93.14, 0.29, 1.91 }, { 0.166, 0.164 } },
405 { "A2", { 80.04, 0.30, 0.32 }, { 0.166, 0.299 } },
406 { "A3", { 66.83, 0.10, 0.03 }, { 0.166, 0.433 } },
407 { "A4", { 51.50, 0.77, -0.42 }, { 0.166, 0.567 } },
408 { "A5", { 36.87, 1.07, -0.03 }, { 0.166, 0.701 } },
409 { "A6", { 14.41, 0.45, 1.21 }, { 0.166, 0.835 } },
410 { "B1", { 49.21, -29.74, -28.15 }, { 0.389, 0.164 } },
411 { "B2", { 50.22, 48.19, -14.47 }, { 0.389, 0.299 } },
412 { "B3", { 81.87, 3.40, 81.35 }, { 0.389, 0.433 } },
413 { "B4", { 43.77, 51.98, 24.51 }, { 0.389, 0.567 } },
414 { "B5", { 54.47, -35.36, 33.08 }, { 0.389, 0.701 } },
415 { "B6", { 31.48, 12.72, -42.34 }, { 0.389, 0.835 } },
416 { "C1", { 61.60, 31.83, 55.23 }, { 0.611, 0.164 } },
417 { "C2", { 39.85, 6.59, -43.46 }, { 0.611, 0.299 } },
418 { "C3", { 50.75, 47.22, 13.05 }, { 0.611, 0.433 } },
419 { "C4", { 32.44, 22.62, -21.32 }, { 0.611, 0.567 } },
420 { "C5", { 70.22, -21.64, 58.34 }, { 0.611, 0.701 } },
421 { "C6", { 70.31, 18.33, 64.52 }, { 0.611, 0.835 } },
422 { "D1", { 70.31, -31.39, -0.56 }, { 0.834, 0.164 } },
423 { "D2", { 56.10, 7.42, -25.07 }, { 0.834, 0.299 } },
424 { "D3", { 42.79, -14.00, 20.46 }, { 0.834, 0.433 } },
425 { "D4", { 50.34, -7.34, -23.06 }, { 0.834, 0.567 } },
426 { "D5", { 65.88, 16.24, 16.82 }, { 0.834, 0.701 } },
427 { "D6", { 37.51, 14.65, 13.49 }, { 0.834, 0.835 } } };
428
429static dt_color_checker_t spyder_24_photo = { .name = "Datacolor SpyderCheckr Photo 24 2022",
430 .author = "Datacolor",
431 .date = "2022",
432 .manufacturer = "DataColor",
434 .ratio = 1.660f,
435 .radius = 0.047,
436 .patches = 24,
437 .size = { 4, 6 },
438 .middle_grey = 03,
439 .white = 00,
440 .black = 05,
441 .values = spyder_24_photo_patches };
442
443
444// Lab values from the "Photo 48" section of the "SpyderCheckr Default Measurements.txt"
445// reference file shipped with the Datacolor SpyderCheckr calibration software.
446// That file lists the patches row-major (A1, B1, ... H1, A2, ...), while this array is
447// column-major (A1 ... A6, B1 ...), so the values are transposed here.
448
449// This chart is a hinged case holding two identical black panels of 4 columns x 6 rows.
450// Columns A..D are the left panel, E..H the right one. Unlike the older SpyderCheckr, it
451// carries no printed registration dot, so the bounding box goes on the OUTER CORNERS OF THE
452// BLACK PANELS: top-left of the left panel, top-right of the right one, and so on. Patch
453// coordinates are normalized to that rectangle, hinge gap included.
454
456 { "A1", { 61.51, 32.31, 14.43 }, { 0.072, 0.164 } },
457 { "A2", { 74.71, 4.09, 47.99 }, { 0.072, 0.299 } },
458 { "A3", { 67.34, -25.92, 23.07 }, { 0.072, 0.433 } },
459 { "A4", { 61.13, -22.28, -21.58 }, { 0.072, 0.567 } },
460 { "A5", { 59.55, -4.22, -29.44 }, { 0.072, 0.701 } },
461 { "A6", { 57.31, 33.77, -7.32 }, { 0.072, 0.835 } },
462 { "B1", { 82.02, 2.79, 1.48 }, { 0.169, 0.164 } },
463 { "B2", { 81.67, -3.30, 1.34 }, { 0.169, 0.299 } },
464 { "B3", { 81.53, 1.66, -3.51 }, { 0.169, 0.433 } },
465 { "B4", { 29.74, 5.74, 3.05 }, { 0.169, 0.567 } },
466 { "B5", { 29.69, -4.49, 2.82 }, { 0.169, 0.701 } },
467 { "B6", { 29.19, 2.76, -4.28 }, { 0.169, 0.835 } },
468 { "C1", { 84.13, 7.62, 11.25 }, { 0.265, 0.164 } },
469 { "C2", { 74.20, 8.73, 24.67 }, { 0.265, 0.299 } },
470 { "C3", { 64.18, 13.06, 34.44 }, { 0.265, 0.433 } },
471 { "C4", { 45.98, 15.67, 23.86 }, { 0.265, 0.567 } },
472 { "C5", { 25.33, 5.05, 7.14 }, { 0.265, 0.701 } },
473 { "C6", { 22.04, 2.15, 0.69 }, { 0.265, 0.835 } },
474 { "D1", { 90.49, 0.26, 1.91 }, { 0.362, 0.164 } },
475 { "D2", { 86.98, 0.29, 0.56 }, { 0.362, 0.299 } },
476 { "D3", { 74.28, 0.13, 0.24 }, { 0.362, 0.433 } },
477 { "D4", { 59.81, 0.57, -0.65 }, { 0.362, 0.567 } },
478 { "D5", { 43.95, 1.11, -0.33 }, { 0.362, 0.701 } },
479 { "D6", { 29.49, 0.71, 0.07 }, { 0.362, 0.835 } },
480 { "E1", { 93.14, 0.29, 1.91 }, { 0.639, 0.164 } },
481 { "E2", { 80.04, 0.30, 0.32 }, { 0.639, 0.299 } },
482 { "E3", { 66.83, 0.10, 0.03 }, { 0.639, 0.433 } },
483 { "E4", { 51.50, 0.77, -0.42 }, { 0.639, 0.567 } },
484 { "E5", { 36.87, 1.07, -0.03 }, { 0.639, 0.701 } },
485 { "E6", { 14.41, 0.45, 1.21 }, { 0.639, 0.835 } },
486 { "F1", { 49.21, -29.74, -28.15 }, { 0.735, 0.164 } },
487 { "F2", { 50.22, 48.19, -14.47 }, { 0.735, 0.299 } },
488 { "F3", { 81.87, 3.40, 81.35 }, { 0.735, 0.433 } },
489 { "F4", { 43.77, 51.98, 24.51 }, { 0.735, 0.567 } },
490 { "F5", { 54.47, -35.36, 33.08 }, { 0.735, 0.701 } },
491 { "F6", { 31.48, 12.72, -42.34 }, { 0.735, 0.835 } },
492 { "G1", { 61.60, 31.83, 55.23 }, { 0.832, 0.164 } },
493 { "G2", { 39.85, 6.59, -43.46 }, { 0.832, 0.299 } },
494 { "G3", { 50.75, 47.22, 13.05 }, { 0.832, 0.433 } },
495 { "G4", { 32.44, 22.62, -21.32 }, { 0.832, 0.567 } },
496 { "G5", { 70.22, -21.64, 58.34 }, { 0.832, 0.701 } },
497 { "G6", { 70.31, 18.33, 64.52 }, { 0.832, 0.835 } },
498 { "H1", { 70.31, -31.39, -0.56 }, { 0.928, 0.164 } },
499 { "H2", { 56.10, 7.42, -25.07 }, { 0.928, 0.299 } },
500 { "H3", { 42.79, -14.00, 20.46 }, { 0.928, 0.433 } },
501 { "H4", { 50.34, -7.34, -23.06 }, { 0.928, 0.567 } },
502 { "H5", { 65.88, 16.24, 16.82 }, { 0.928, 0.701 } },
503 { "H6", { 37.51, 14.65, 13.49 }, { 0.928, 0.835 } } };
504
505static dt_color_checker_t spyder_48_photo = { .name = "Datacolor SpyderCheckr Photo 48 2022",
506 .author = "Datacolor",
507 .date = "2022",
508 .manufacturer = "DataColor",
510 .ratio = 0.719f,
511 .radius = 0.032,
512 .patches = 48,
513 .size = { 8, 6 },
514 .middle_grey = 27,
515 .white = 24,
516 .black = 29,
517 .values = spyder_48_photo_patches };
518
526
527// Add other supported type of CGATS here
536
543
550
551// This defines charts specifications
553{
554 const gchar *type;
555 float radius; // radius of a patch in ratio of the checker diagonal
556 float ratio; // format ratio of the chart, guide to guide (white dots)
557 size_t size[2]; // number of patch along x, y axes
558 float guide_size[2];// size of the guide area, specified by "MARK" data in cht files
560 size_t white;
561 size_t black;
562
563 int num_patches; // total number of patches
565 int rows;
570
571 GSList *patches; // list of patches struct, data are dt_color_checker_patch
572
574
575static inline dt_colorchecker_label_t *dt_colorchecker_label_init(const char *label, const dt_color_checker_targets type, const char *path, const int patch_nb)
576{
577 dt_colorchecker_label_t *checker_label = malloc(sizeof(dt_colorchecker_label_t));
578 if(!checker_label) return NULL;
579
580 checker_label->name = label ? g_strdup(label) : NULL;
581 checker_label->type = type;
582 checker_label->path = path ? g_strdup(path) : NULL;
583 checker_label->patch_nb = patch_nb;
584
585 return checker_label;
586}
587
588static inline dt_color_checker_patch *dt_colorchecker_patch_array_init(const size_t num_patches)
589{
591 if(!patches) return NULL;
592
593 // Initialize the patches
594 for(size_t i = 0; i < num_patches; i++)
595 {
596 patches[i].name = NULL;
597 patches[i].x = 0.0f;
598 patches[i].y = 0.0f;
599 patches[i].Lab[0] = 0.0f;
600 patches[i].Lab[1] = 0.0f;
601 patches[i].Lab[2] = 0.0f;
602 }
603 return patches;
604}
605
607{
608 if(!patch) return;
609 if(!patch->name) return;
610
611 dt_free(patch->name);
612}
613
614// This one is to fully free GSList of dt_color_checker_patch
615static inline void dt_colorchecker_patch_cleanup_list(void *_patch)
616{
618 if(!patch) return;
619
620 // Free the name if it was allocated
621 dt_free(patch->name);
622
623 dt_free_align(patch); // paired with the dt_alloc_align in _dt_colorchecker_patch_init()
624}
625
627{
628 dt_color_checker_t *checker = (dt_color_checker_t*)malloc(sizeof(dt_color_checker_t));
629 if(!checker) return NULL;
630
631 checker->name = NULL;
632 checker->author = NULL;
633 checker->date = NULL;
634 checker->manufacturer = NULL;
635 checker->values = NULL;
636 checker->finished = FALSE;
637
638 return checker;
639}
640
641static inline void dt_colorchecker_cleanup(dt_color_checker_t *checker)
642{
643 if (!checker) return;
644
645 dt_free(checker->name);
646 dt_free(checker->author);
647 dt_free(checker->date);
648 dt_free(checker->manufacturer);
649
650 if(checker->patches > 0 && checker->values)
651 {
652 for(size_t i = 0; i < checker->patches; i++)
653 {
655 }
656
657 dt_free_align(checker->values);
658 }
659 free(checker);
660 checker = NULL;
661}
662
663static inline void dt_colorchecker_label_free(gpointer data)
664{
665 dt_colorchecker_label_t *checker_label = (dt_colorchecker_label_t *)data;
666 if(!checker_label) return;
667
668 dt_free(checker_label->name);
669 dt_free(checker_label->path);
670 dt_free(checker_label);
671}
672
673static inline void dt_colorchecker_label_list_cleanup(GList **colorcheckers)
674{
675 if(!colorcheckers) return;
676
677 g_list_free_full(g_steal_pointer(colorcheckers), dt_colorchecker_label_free);
678 *colorcheckers = NULL;
679}
680
688dt_color_checker_t *dt_colorchecker_user_ref_create(const char *color_filename, const char *cht_filename);
689
696int dt_colorchecker_find_cht_files(GList **chts);
697
704int dt_colorchecker_find_CGATS_reference_files(GList **ref_colorcheckers_files);
705
712int dt_colorchecker_find_builtin(GList **colorcheckers_label);
713
721
722
737static dt_color_checker_t *dt_get_color_checker(const dt_color_checker_targets target_type, const char *cht_filename, const char *color_filename)
738{
739 // initialize the destination checker
740 dt_color_checker_t *checker_dest = NULL;
741 checker_dest = dt_colorchecker_init();
742 if(!checker_dest) return NULL;
743
744 // Copy the color checker data from the predefined checkers or from reference file
745 switch(target_type)
746 {
748 dt_colorchecker_copy(checker_dest, &xrite_24_2000);
749 break;
751 dt_colorchecker_copy(checker_dest, &xrite_24_2014);
752 break;
754 dt_colorchecker_copy(checker_dest, &spyder_24);
755 break;
757 dt_colorchecker_copy(checker_dest, &spyder_24_v2);
758 break;
760 dt_colorchecker_copy(checker_dest, &spyder_48);
761 break;
763 dt_colorchecker_copy(checker_dest, &spyder_48_v2);
764 break;
767 break;
770 break;
772 if(color_filename)
773 {
774 dt_color_checker_t *p = dt_colorchecker_user_ref_create(color_filename, cht_filename);
775 if(p)
776 {
777 dt_colorchecker_copy(checker_dest, p);
779 }
780 }
781 else fprintf(stderr, "dt_get_color_checker: colorchecker %i is a user reference but no color filename was provided!\n", target_type);
782 break;
783
785 fprintf(stderr, "dt_get_color_checker: colorchecker type %i not found!\n", target_type);
786 dt_colorchecker_copy(checker_dest, &xrite_24_2014);
787 }
788
789 return checker_dest;
790}
791
796// get a patch index in the list of values from the coordinates of the patch in the checker array
797static inline size_t dt_color_checker_get_index(const dt_color_checker_t *const target_checker, const size_t coordinates[2])
798{
799 // patches are stored column-major
800 const size_t height = target_checker->size[1];
801 return CLAMP(height * coordinates[0] + coordinates[1], 0, target_checker->patches - 1);
802}
803
804// get a a patch coordinates of in the checker array from the patch index in the list of values
805static inline void dt_color_checker_get_coordinates(const dt_color_checker_t *const target_checker, size_t *coordinates, const size_t index)
806{
807 // patches are stored column-major
808 const size_t idx = CLAMP(index, 0, target_checker->patches - 1);
809 const size_t height = target_checker->size[1];
810 const size_t num_col = idx / height;
811 const size_t num_lin = idx - num_col * height;
812 coordinates[0] = CLAMP(num_col, 0, target_checker->size[0] - 1);
813 coordinates[1] = CLAMP(num_lin, 0, target_checker->size[1] - 1);
814}
815
816// find a patch matching a name
817static inline const dt_color_checker_patch *dt_color_checker_get_patch_by_name(const dt_color_checker_t *const target_checker, const char *name, size_t *index)
818{
819 size_t idx = -1;
820 const dt_color_checker_patch *patch = NULL;
821
822 for(size_t k = 0; k < target_checker->patches; k++)
823 if(strcmp(name, target_checker->values[k].name) == 0)
824 {
825 idx = k;
826 patch = &target_checker->values[k];
827 break;
828 }
829
830 if(IS_NULL_PTR(patch)) fprintf(stderr, "No patch matching name `%s` was found in %s\n", name, target_checker->name);
831
832 if(index) *index = idx;
833 return patch;
834}
835
842static inline int dt_colorchecker_find(GList **colorcheckers_label)
843{
844 int total = dt_colorchecker_find_builtin(colorcheckers_label);
845 dt_print(DT_DEBUG_VERBOSE, _("dt_colorchecker_find: found %d builtin colorcheckers\n"), total);
846 int b_nb = total;
847
848 total += dt_colorchecker_find_cht_files(colorcheckers_label);
849 if (total) dt_print(DT_DEBUG_VERBOSE, _("dt_colorchecker_find: found %d CGAT references files\n"), total - b_nb);
850 return total;
851}
852
859static inline int dt_colorchecker_find_color(GList **color_label)
860{
861 if(!color_label) return 0;
862
863 // Clear cht file list
865
866 // Refill the list
867 const int total = dt_colorchecker_find_CGATS_reference_files(color_label);
868 if(total) dt_print(DT_DEBUG_VERBOSE, _("dt_colorchecker_find_color: found %d .cht files\n"), total);
869
870 if(*color_label == NULL)
871 fprintf(stderr, "[channelmixerrgb] no CGATS file found\n");
872
873 return *color_label ? total : 0;
874}
875
876#endif // DT_COMMON_COLORCHECKER_H
877
878// clang-format off
879// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
880// vim: shiftwidth=2 expandtab tabstop=2 cindent
881// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
882// clang-format on
#define FALSE
Definition ashift_lsd.c:158
int dt_colorchecker_find_CGATS_reference_files(GList **ref_colorcheckers_files)
Find all CGAT files in the user config/color/it8 directory.
static int dt_colorchecker_find_color(GList **color_label)
Find all builtin and CGATS colorcheckers.
static dt_colorchecker_label_t * dt_colorchecker_label_init(const char *label, const dt_color_checker_targets type, const char *path, const int patch_nb)
static dt_color_checker_patch spyder_48_v2_patch[]
dt_color_checker_targets
@ COLOR_CHECKER_SPYDER_48
@ COLOR_CHECKER_SPYDER_PHOTO_24
@ COLOR_CHECKER_XRITE_24_2000
@ COLOR_CHECKER_XRITE_24_2014
@ COLOR_CHECKER_LAST
@ COLOR_CHECKER_SPYDER_PHOTO_48
@ COLOR_CHECKER_SPYDER_24_V2
@ COLOR_CHECKER_SPYDER_24
@ COLOR_CHECKER_USER_REF
@ COLOR_CHECKER_SPYDER_48_V2
static dt_color_checker_patch spyder_24_patches[]
static void dt_colorchecker_cleanup(dt_color_checker_t *checker)
static dt_color_checker_patch xrite_24_2014_patches[]
dt_colorchecker_material_types
@ COLOR_CHECKER_MATERIAL_TRANSPARENT
@ COLOR_CHECKER_MATERIAL_UNKNOWN
@ COLOR_CHECKER_MATERIAL_OPAQUE
int dt_colorchecker_find_cht_files(GList **chts)
Find all .cht files in the user config/color/it8 directory.
static void dt_colorchecker_patch_cleanup(dt_color_checker_patch *patch)
static size_t dt_color_checker_get_index(const dt_color_checker_t *const target_checker, const size_t coordinates[2])
dt_colorchecker_CGATS_types
@ CGATS_TYPE_IT8_7_1
@ CGATS_TYPE_UNKOWN
@ CGATS_TYPE_IT8_7_2
@ CGATS_TYPE_CTI3
static void dt_colorchecker_patch_cleanup_list(void *_patch)
static dt_color_checker_t spyder_24
static dt_color_checker_t spyder_24_photo
static const dt_color_checker_patch * dt_color_checker_get_patch_by_name(const dt_color_checker_t *const target_checker, const char *name, size_t *index)
static dt_color_checker_patch spyder_24_photo_patches[]
static void dt_colorchecker_label_free(gpointer data)
static dt_color_checker_t * dt_get_color_checker(const dt_color_checker_targets target_type, const char *cht_filename, const char *color_filename)
Build a color checker of the given type.
static dt_color_checker_t spyder_48
static void dt_colorchecker_label_list_cleanup(GList **colorcheckers)
void dt_colorchecker_copy(dt_color_checker_t *dest, const dt_color_checker_t *src)
Copy the content of a color checker from source to destination.
dt_color_checker_t * dt_colorchecker_user_ref_create(const char *color_filename, const char *cht_filename)
Creates a color checker from a reference file (CGATS format).
static dt_color_checker_patch spyder_48_patches[]
static dt_color_checker_t spyder_48_v2
static dt_color_checker_t * dt_colorchecker_init()
static dt_color_checker_t spyder_24_v2
static void dt_color_checker_get_coordinates(const dt_color_checker_t *const target_checker, size_t *coordinates, const size_t index)
static dt_color_checker_patch spyder_48_photo_patches[]
static dt_color_checker_patch * dt_colorchecker_patch_array_init(const size_t num_patches)
static dt_color_checker_t xrite_24_2014
static dt_color_checker_patch spyder_24_v2_patch[]
int dt_colorchecker_find_builtin(GList **colorcheckers_label)
Find all builtin colorcheckers.
static dt_color_checker_t xrite_24_2000
static dt_color_checker_patch xrite_24_2000_patches[]
static dt_color_checker_t spyder_48_photo
static int dt_colorchecker_find(GList **colorcheckers_label)
Find all builtin and .cht colorcheckers.
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:508
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_VERBOSE
Definition logging.h:78
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint32_t height
Definition mipmap_cache.c:1
const char * name
Definition pdf.h:90
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
Definition simd.h:53
dt_aligned_pixel_t Lab
dt_color_checker_targets type
dt_color_checker_patch * values
dt_color_checker_targets type