1 /*
2 * This file is part of darktable,
3 * Copyright (C) 2015-2021 darktable developers.
4 *
5 * darktable is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * darktable is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "common/noiseprofiles.h"
20 #include "common/file_location.h"
21 #include "control/control.h"
22
23 // bump this when the noiseprofiles are getting a different layout or meaning (raw-raw data, ...)
24 #define DT_NOISE_PROFILE_VERSION 0
25
26 const dt_noiseprofile_t dt_noiseprofile_generic = {N_("generic poissonian"), "", "", 0, {0.0001f, 0.0001f, 0.0001}, {0.0f, 0.0f, 0.0f}};
27
28 static gboolean dt_noiseprofile_verify(JsonParser *parser);
29
dt_noiseprofile_init(const char * alternative)30 JsonParser *dt_noiseprofile_init(const char *alternative)
31 {
32 GError *error = NULL;
33 char filename[PATH_MAX] = { 0 };
34
35 if(alternative == NULL)
36 {
37 // TODO: shall we look for profiles in the user config dir?
38 char datadir[PATH_MAX] = { 0 };
39 dt_loc_get_datadir(datadir, sizeof(datadir));
40 snprintf(filename, sizeof(filename), "%s/%s", datadir, "noiseprofiles.json");
41 }
42 else
43 g_strlcpy(filename, alternative, sizeof(filename));
44
45 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] loading noiseprofiles from `%s'\n", filename);
46 if(!g_file_test(filename, G_FILE_TEST_EXISTS)) return NULL;
47
48 // TODO: shall we cache the content? for now this looks fast enough(TM)
49 JsonParser *parser = json_parser_new();
50 if(!json_parser_load_from_file(parser, filename, &error))
51 {
52 fprintf(stderr, "[noiseprofile] error: parsing json from `%s' failed\n%s\n", filename, error->message);
53 g_error_free(error);
54 g_object_unref(parser);
55 return NULL;
56 }
57
58 // run over the file once to verify that it is sane
59 if(!dt_noiseprofile_verify(parser))
60 {
61 dt_control_log(_("noiseprofile file `%s' is not valid"), filename);
62 fprintf(stderr, "[noiseprofile] error: `%s' is not a valid noiseprofile file. run with -d control for details\n", filename);
63 g_object_unref(parser);
64 return NULL;
65 }
66
67 return parser;
68 }
69
is_member(gchar ** names,char * name)70 int is_member(gchar** names, char* name)
71 {
72 while(*names)
73 {
74 if(!g_strcmp0(*names, name))
75 return 1;
76 names++;
77 }
78 return 0;
79 }
80
_sort_by_iso(gconstpointer a,gconstpointer b)81 static gint _sort_by_iso(gconstpointer a, gconstpointer b)
82 {
83 const dt_noiseprofile_t *profile_a = (dt_noiseprofile_t *)a;
84 const dt_noiseprofile_t *profile_b = (dt_noiseprofile_t *)b;
85
86 return profile_a->iso - profile_b->iso;
87 }
88
89 #define _ERROR(...) {\
90 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] error: " );\
91 dt_print(DT_DEBUG_CONTROL, __VA_ARGS__);\
92 dt_print(DT_DEBUG_CONTROL, "\n");\
93 valid = FALSE;\
94 goto end;\
95 }
96
dt_noiseprofile_verify(JsonParser * parser)97 static gboolean dt_noiseprofile_verify(JsonParser *parser)
98 {
99 JsonReader *reader = NULL;
100 gboolean valid = TRUE;
101
102 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] verifying noiseprofile file\n");
103
104 JsonNode *root = json_parser_get_root(parser);
105 if(!root) _ERROR("can't get the root node");
106
107 reader = json_reader_new(root);
108
109 if(!json_reader_read_member(reader, "version")) _ERROR("can't find file version.");
110
111 // check the file version
112 const int version = json_reader_get_int_value(reader);
113 json_reader_end_member(reader);
114
115 if(version != DT_NOISE_PROFILE_VERSION) _ERROR("file version is not what this code understands");
116
117 if(!json_reader_read_member(reader, "noiseprofiles")) _ERROR("can't find `noiseprofiles' entry.");
118
119 if(!json_reader_is_array(reader)) _ERROR("`noiseprofiles' is supposed to be an array");
120
121 size_t n_profiles_total = 0;
122
123 // go through all makers
124 const int n_makers = json_reader_count_elements(reader);
125 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d makers\n", n_makers);
126 for(int i = 0; i < n_makers; i++)
127 {
128 if(!json_reader_read_element(reader, i)) _ERROR("can't access maker at position %d / %d", i+1, n_makers);
129
130 if(!json_reader_read_member(reader, "maker")) _ERROR("missing `maker`");
131
132 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found maker `%s'\n", json_reader_get_string_value(reader));
133 // go through all models and check those
134 json_reader_end_member(reader);
135
136 if(!json_reader_read_member(reader, "models")) _ERROR("missing `models`");
137
138 const int n_models = json_reader_count_elements(reader);
139 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d models\n", n_models);
140 n_profiles_total += n_models;
141 for(int j = 0; j < n_models; j++)
142 {
143 if(!json_reader_read_element(reader, j)) _ERROR("can't access model at position %d / %d", j+1, n_models);
144
145 if(!json_reader_read_member(reader, "model")) _ERROR("missing `model`");
146
147 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %s\n", json_reader_get_string_value(reader));
148 json_reader_end_member(reader);
149
150 if(!json_reader_read_member(reader, "profiles")) _ERROR("missing `profiles`");
151
152 const int n_profiles = json_reader_count_elements(reader);
153 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d profiles\n", n_profiles);
154 for(int k = 0; k < n_profiles; k++)
155 {
156 if(!json_reader_read_element(reader, k)) _ERROR("can't access profile at position %d / %d", k+1, n_profiles);
157
158 gchar** member_names = json_reader_list_members(reader);
159
160 // name
161 if(!is_member(member_names, "name"))
162 {
163 g_strfreev(member_names);
164 _ERROR("missing `name`");
165 }
166
167 // iso
168 if(!is_member(member_names, "iso"))
169 {
170 g_strfreev(member_names);
171 _ERROR("missing `iso`");
172 }
173
174 // a
175 if(!is_member(member_names, "a"))
176 {
177 g_strfreev(member_names);
178 _ERROR("missing `a`");
179 }
180 json_reader_read_member(reader, "a");
181 if(json_reader_count_elements(reader) != 3)
182 {
183 g_strfreev(member_names);
184 _ERROR("`a` with size != 3");
185 }
186 json_reader_end_member(reader);
187
188 // b
189 if(!is_member(member_names, "b"))
190 {
191 g_strfreev(member_names);
192 _ERROR("missing `b`");
193 }
194 json_reader_read_member(reader, "b");
195 if(json_reader_count_elements(reader) != 3)
196 {
197 g_strfreev(member_names);
198 _ERROR("`b` with size != 3");
199 }
200 json_reader_end_member(reader);
201
202 json_reader_end_element(reader);
203
204 g_strfreev(member_names);
205 } // profiles
206
207 json_reader_end_member(reader);
208 json_reader_end_element(reader);
209 } // models
210
211 json_reader_end_member(reader);
212 json_reader_end_element(reader);
213 } // makers
214
215 json_reader_end_member(reader);
216
217 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] verifying noiseprofile completed\n");
218 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %zu profiles total\n", n_profiles_total);
219
220 end:
221 if(reader) g_object_unref(reader);
222 return valid;
223 }
224 #undef _ERROR
225
dt_noiseprofile_get_matching(const dt_image_t * cimg)226 GList *dt_noiseprofile_get_matching(const dt_image_t *cimg)
227 {
228 JsonParser *parser = darktable.noiseprofile_parser;
229 JsonReader *reader = NULL;
230 GList *result = NULL;
231
232 if(!parser) goto end;
233
234 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] looking for maker `%s', model `%s'\n", cimg->camera_maker, cimg->camera_model);
235
236 JsonNode *root = json_parser_get_root(parser);
237
238 reader = json_reader_new(root);
239
240 json_reader_read_member(reader, "noiseprofiles");
241
242 // go through all makers
243 const int n_makers = json_reader_count_elements(reader);
244 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d makers\n", n_makers);
245 for(int i = 0; i < n_makers; i++)
246 {
247 json_reader_read_element(reader, i);
248
249 json_reader_read_member(reader, "maker");
250
251 if(g_strstr_len(cimg->camera_maker, -1, json_reader_get_string_value(reader)))
252 {
253 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found `%s' as `%s'\n", cimg->camera_maker, json_reader_get_string_value(reader));
254 // go through all models and check those
255 json_reader_end_member(reader);
256
257 json_reader_read_member(reader, "models");
258
259 const int n_models = json_reader_count_elements(reader);
260 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d models\n", n_models);
261 for(int j = 0; j < n_models; j++)
262 {
263 json_reader_read_element(reader, j);
264
265 json_reader_read_member(reader, "model");
266
267 if(!g_strcmp0(cimg->camera_model, json_reader_get_string_value(reader)))
268 {
269 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %s\n", cimg->camera_model);
270 // we got a match, return at most bufsize elements
271 json_reader_end_member(reader);
272
273 json_reader_read_member(reader, "profiles");
274
275 const int n_profiles = json_reader_count_elements(reader);
276 dt_print(DT_DEBUG_CONTROL, "[noiseprofile] found %d profiles\n", n_profiles);
277 for(int k = 0; k < n_profiles; k++)
278 {
279 dt_noiseprofile_t tmp_profile = { 0 };
280
281 json_reader_read_element(reader, k);
282
283 gchar** member_names = json_reader_list_members(reader);
284
285 // do we want to skip this entry?
286 if(is_member(member_names, "skip"))
287 {
288 json_reader_read_member(reader, "skip");
289 gboolean skip = json_reader_get_boolean_value(reader);
290 json_reader_end_member(reader);
291 if(skip)
292 {
293 json_reader_end_element(reader);
294 g_strfreev(member_names);
295 continue;
296 }
297 }
298
299 // maker
300 tmp_profile.maker = g_strdup(cimg->camera_maker);
301
302 // model
303 tmp_profile.model = g_strdup(cimg->camera_model);
304
305 // name
306 json_reader_read_member(reader, "name");
307 tmp_profile.name = g_strdup(json_reader_get_string_value(reader));
308 json_reader_end_member(reader);
309
310 // iso
311 json_reader_read_member(reader, "iso");
312 tmp_profile.iso = json_reader_get_double_value(reader);
313 json_reader_end_member(reader);
314
315 // a
316 json_reader_read_member(reader, "a");
317 for(int a = 0; a < 3; a++)
318 {
319 json_reader_read_element(reader, a);
320 tmp_profile.a[a] = json_reader_get_double_value(reader);
321 json_reader_end_element(reader);
322 }
323 json_reader_end_member(reader);
324
325 // b
326 json_reader_read_member(reader, "b");
327 for(int b = 0; b < 3; b++)
328 {
329 json_reader_read_element(reader, b);
330 tmp_profile.b[b] = json_reader_get_double_value(reader);
331 json_reader_end_element(reader);
332 }
333 json_reader_end_member(reader);
334
335 json_reader_end_element(reader);
336
337 // everything worked out, add tmp_profile to result
338 dt_noiseprofile_t *new_profile = (dt_noiseprofile_t *)malloc(sizeof(dt_noiseprofile_t));
339 *new_profile = tmp_profile;
340 result = g_list_prepend(result, new_profile);
341
342 g_strfreev(member_names);
343 } // profiles
344
345 goto end;
346 }
347
348 json_reader_end_member(reader);
349 json_reader_end_element(reader);
350 } // models
351 }
352
353 json_reader_end_member(reader);
354 json_reader_end_element(reader);
355 } // makers
356
357 json_reader_end_member(reader);
358
359 end:
360 if(reader) g_object_unref(reader);
361 if(result) result = g_list_sort(result, _sort_by_iso);
362 return result;
363 }
364
dt_noiseprofile_free(gpointer data)365 void dt_noiseprofile_free(gpointer data)
366 {
367 dt_noiseprofile_t *profile = (dt_noiseprofile_t *)data;
368 g_free(profile->name);
369 g_free(profile->maker);
370 g_free(profile->model);
371 free(profile);
372 }
373
dt_noiseprofile_interpolate(const dt_noiseprofile_t * const p1,const dt_noiseprofile_t * const p2,dt_noiseprofile_t * out)374 void dt_noiseprofile_interpolate(
375 const dt_noiseprofile_t *const p1, // the smaller iso
376 const dt_noiseprofile_t *const p2, // the larger iso (can't be == iso1)
377 dt_noiseprofile_t *out) // has iso initialized
378 {
379 // stupid linear interpolation.
380 // to be confirmed for gaussian part.
381 const float t = CLAMP(
382 (float)(out->iso - p1->iso) / (float)(p2->iso - p1->iso),
383 0.0f, 1.0f);
384 for(int k=0; k<3; k++)
385 {
386 out->a[k] = (1.0f-t)*p1->a[k] + t*p2->a[k];
387 out->b[k] = (1.0f-t)*p1->b[k] + t*p2->b[k];
388 }
389 }
390
391
392 // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.sh
393 // vim: shiftwidth=2 expandtab tabstop=2 cindent
394 // kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
395