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