Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
common/presets.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2019-2020 Pascal Obry.
4 Copyright (C) 2020-2021 Hubert Kowalski.
5 Copyright (C) 2021 Aldric Renaudin.
6 Copyright (C) 2021 Marco Carrarini.
7 Copyright (C) 2022 Aurélien PIERRE.
8 Copyright (C) 2022 Martin Bařinka.
9
10 darktable is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 darktable is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with darktable. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "common/presets.h"
25#include "common/darktable.h"
26#include "common/debug.h"
27#include "common/exif.h"
29#include "develop/blend.h"
30#include "develop/imageop.h"
31#include "libs/lib.h"
32
33#include <libxml/encoding.h>
34#include <libxml/xmlwriter.h>
35#include <libxml/parser.h>
36#include <libxml/xpath.h>
37#include <libxml/xpathInternals.h>
38
39#include <glib.h>
40#include <inttypes.h>
41#include <sqlite3.h>
42
43static char *dt_preset_encode(sqlite3_stmt *stmt, int row)
44{
45 const int32_t len = sqlite3_column_bytes(stmt, row);
46 char *vparams = dt_exif_xmp_encode((const unsigned char *)sqlite3_column_blob(stmt, row), len, NULL);
47 return vparams;
48}
49
50void dt_presets_save_to_file(const int rowid, const char *preset_name, const char *filedir)
51{
52 sqlite3_stmt *stmt;
53
54 // generate filename based on name of preset
55 // convert all characters to underscore which are not allowed in filenames
56 gchar *presetname = g_strdup(preset_name);
57 gchar *filename = g_strdup_printf("%s/%s.dtpreset", filedir, g_strdelimit(presetname, "/<>:\"\\|*?[]", '_'));
58
59 dt_free(presetname);
60
61 // clang-format off
63 "SELECT op_params, blendop_params, name, description, operation,"
64 " autoapply, model, maker, lens, iso_min, iso_max, exposure_min,"
65 " exposure_max, aperture_min, aperture_max, focal_length_min,"
66 " focal_length_max, op_version, blendop_version, enabled,"
67 " multi_priority, multi_name, filter, def, format "
68 " FROM data.presets"
69 " WHERE rowid = ?1",
70 -1, &stmt, NULL);
71 // clang-format on
72 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, rowid);
73
74 if(sqlite3_step(stmt) == SQLITE_ROW)
75 {
76 const gchar *name = (gchar *)sqlite3_column_text(stmt, 2);
77 const gchar *description = (gchar *)sqlite3_column_text(stmt, 3);
78 const gchar *operation = (gchar *)sqlite3_column_text(stmt, 4);
79 const int autoapply = sqlite3_column_int(stmt, 5);
80 const gchar *model = (gchar *)sqlite3_column_text(stmt, 6);
81 const gchar *maker = (gchar *)sqlite3_column_text(stmt, 7);
82 const gchar *lens = (gchar *)sqlite3_column_text(stmt, 8);
83 const float iso_min = sqlite3_column_double(stmt, 9);
84 const float iso_max = sqlite3_column_double(stmt, 10);
85 const float exposure_min = sqlite3_column_double(stmt, 11);
86 const float exposure_max = sqlite3_column_double(stmt, 12);
87 const float aperture_min = sqlite3_column_double(stmt, 13);
88 const float aperture_max = sqlite3_column_double(stmt, 14);
89 const int focal_length_min = sqlite3_column_double(stmt, 15);
90 const int focal_length_max = sqlite3_column_double(stmt, 16);
91 const int op_version = sqlite3_column_int(stmt, 17);
92 const int blendop_version = sqlite3_column_int(stmt, 18);
93 const int enabled = sqlite3_column_int(stmt, 19);
94 const int multi_priority = sqlite3_column_int(stmt, 20);
95 const gchar *multi_name = (gchar *)sqlite3_column_text(stmt, 21);
96 const int filter = sqlite3_column_double(stmt, 22);
97 const int def = sqlite3_column_double(stmt, 23);
98 const int format = sqlite3_column_double(stmt, 24);
99
100 int rc = 0;
101
102 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename, 0);
103
104 if(IS_NULL_PTR(writer))
105 {
106 fprintf(stderr, "[dt_presets_save_to_file] Error creating the xml writer\n, path: %s", filename);
107 dt_free(filename);
108 return;
109 }
110
111 rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
112 if(rc < 0)
113 {
114 fprintf(stderr, "[dt_presets_save_to_file]: Error on encoding setting");
115 dt_free(filename);
116 return;
117 }
118
119 xmlTextWriterStartElement(writer, BAD_CAST "darktable_preset");
120 xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0");
121
122 xmlTextWriterStartElement(writer, BAD_CAST "preset");
123 xmlTextWriterWriteFormatElement(writer, BAD_CAST "name", "%s", name);
124 xmlTextWriterWriteFormatElement(writer, BAD_CAST "description", "%s", description);
125 xmlTextWriterWriteFormatElement(writer, BAD_CAST "operation", "%s", operation);
126 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_params", "%s", dt_preset_encode(stmt, 0));
127 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_version", "%d", op_version);
128 xmlTextWriterWriteFormatElement(writer, BAD_CAST "enabled", "%d", enabled);
129 xmlTextWriterWriteFormatElement(writer, BAD_CAST "autoapply", "%d", autoapply);
130 xmlTextWriterWriteFormatElement(writer, BAD_CAST "model", "%s", model);
131 xmlTextWriterWriteFormatElement(writer, BAD_CAST "maker", "%s", maker);
132 xmlTextWriterWriteFormatElement(writer, BAD_CAST "lens", "%s", lens);
133 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iso_min", "%f", iso_min);
134 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iso_max", "%f", iso_max);
135 xmlTextWriterWriteFormatElement(writer, BAD_CAST "exposure_min", "%f", exposure_min);
136 xmlTextWriterWriteFormatElement(writer, BAD_CAST "exposure_max", "%f", exposure_max);
137 xmlTextWriterWriteFormatElement(writer, BAD_CAST "aperture_min", "%f", aperture_min);
138 xmlTextWriterWriteFormatElement(writer, BAD_CAST "aperture_max", "%f", aperture_max);
139 xmlTextWriterWriteFormatElement(writer, BAD_CAST "focal_length_min", "%d", focal_length_min);
140 xmlTextWriterWriteFormatElement(writer, BAD_CAST "focal_length_max", "%d", focal_length_max);
141 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_params", "%s", dt_preset_encode(stmt, 1));
142 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_version", "%d", blendop_version);
143 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_priority", "%d", multi_priority);
144 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_name", "%s", multi_name);
145 xmlTextWriterWriteFormatElement(writer, BAD_CAST "filter", "%d", filter);
146 xmlTextWriterWriteFormatElement(writer, BAD_CAST "def", "%d", def);
147 xmlTextWriterWriteFormatElement(writer, BAD_CAST "format", "%d", format);
148 xmlTextWriterEndElement(writer);
149
150 sqlite3_finalize(stmt);
151 xmlTextWriterEndDocument(writer);
152 xmlFreeTextWriter(writer);
153 }
154 dt_free(filename);
155}
156
157static gchar *get_preset_element(xmlDocPtr doc, gchar *name)
158{
159 xmlXPathContextPtr xpathCtx = xmlXPathNewContext(doc);
160 char xpath[128] = { 0 };
161 snprintf(xpath, sizeof(xpath), "//%s", name);
162 gchar *result = NULL;
163
164 xmlXPathObjectPtr xpathObj =
165 xmlXPathEvalExpression((const xmlChar *)xpath, xpathCtx);
166
167 if(xpathObj)
168 {
169 const xmlNodeSetPtr xnodes = xpathObj->nodesetval;
170 if(xnodes->nodeTab)
171 {
172 const xmlNodePtr xnode = xnodes->nodeTab[0];
173 xmlChar *value = xmlNodeListGetString(doc, xnode->xmlChildrenNode, 1);
174
175 if(value)
176 result = g_strdup((gchar *)value);
177 else
178 result = g_strdup("");
179
180 xmlFree(value);
181 }
182 xmlXPathFreeObject(xpathObj);
183 }
184
185 xmlXPathFreeContext(xpathCtx);
186 return result;
187}
188
189static int get_preset_element_int(xmlDocPtr doc, gchar *name)
190{
191 gchar *value = get_preset_element(doc, name);
192 const int result = value ? atoi(value) : 0;
193 dt_free(value);
194 return result;
195}
196
197static int get_preset_element_float(xmlDocPtr doc, gchar *name)
198{
199 gchar *value = get_preset_element(doc, name);
200 const float result = value ? atof(value) : 0.0f;
201 dt_free(value);
202 return result;
203}
204
205int dt_presets_import_from_file(const char *preset_path)
206{
207 xmlDocPtr doc = xmlParseFile(preset_path);
208 if(IS_NULL_PTR(doc))
209 return FALSE;
210
211 xmlNodePtr root = xmlDocGetRootElement(doc);
212 if(IS_NULL_PTR(root) || xmlStrcmp(root->name, BAD_CAST "darktable_preset") != 0)
213 {
214 xmlFreeDoc(doc);
215 return FALSE;
216 }
217
218 gchar *name = get_preset_element(doc, "name");
219 gchar *description = get_preset_element(doc, "description");
220 gchar *operation = get_preset_element(doc, "operation");
221 const int autoapply = get_preset_element_int(doc, "autoapply");
222 gchar *model = get_preset_element(doc, "model");
223 gchar *maker = get_preset_element(doc, "maker");
224 gchar *lens = get_preset_element(doc, "lens");
225 const float iso_min = get_preset_element_float(doc, "iso_min");
226 const float iso_max = get_preset_element_float(doc, "iso_max");
227 const float exposure_min = get_preset_element_float(doc, "exposure_min");
228 const float exposure_max = get_preset_element_float(doc, "exposure_max");
229 const float aperture_min = get_preset_element_float(doc, "aperture_min");
230 const float aperture_max = get_preset_element_float(doc, "aperture_max");
231 const int focal_length_min = get_preset_element_int(doc, "focal_length_min");
232 const int focal_length_max = get_preset_element_int(doc, "focal_length_max");
233 gchar *op_params = get_preset_element(doc, "op_params");
234 const int op_version = get_preset_element_int(doc, "op_version");
235 gchar *blendop_params = get_preset_element(doc, "blendop_params");
236 const int blendop_version = get_preset_element_int(doc, "blendop_version");
237 const int enabled = get_preset_element_int(doc, "enabled");
238 const int multi_priority = get_preset_element_int(doc, "multi_priority");
239 gchar *multi_name = get_preset_element(doc, "multi_name");
240 const int filter = get_preset_element_int(doc, "filter");
241 const int def = get_preset_element_int(doc, "def");
242 const int format = get_preset_element_int(doc, "format");
243 xmlFreeDoc(doc);
244
245 int blendop_params_len = 0;
246 const unsigned char *blendop_params_blob = dt_exif_xmp_decode
247 (blendop_params, strlen(blendop_params), &blendop_params_len);
248
249 int op_params_len = 0;
250 const unsigned char *op_params_blob = dt_exif_xmp_decode
251 (op_params, strlen(op_params), &op_params_len);
252
253 sqlite3_stmt *stmt;
254 int result = 0;
255
256 // clang-format off
258 "INSERT OR REPLACE"
259 " INTO data.presets"
260 " (name, description, operation, autoapply,"
261 " model, maker, lens, iso_min, iso_max, exposure_min, exposure_max,"
262 " aperture_min, aperture_max, focal_length_min, focal_length_max,"
263 " op_params, op_version, blendop_params, blendop_version, enabled,"
264 " multi_priority, multi_name, filter, def, format, writeprotect)"
265 " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, "
266 " ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23, ?24, ?25, 0)",
267 -1, &stmt, NULL);
268 // clang-format on
269
270 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, strlen(name), SQLITE_TRANSIENT);
271 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, description, strlen(description), SQLITE_TRANSIENT);
272 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, operation, strlen(operation), SQLITE_TRANSIENT);
273 DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, autoapply);
274 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, model, strlen(model), SQLITE_TRANSIENT);
275 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, maker, strlen(maker), SQLITE_TRANSIENT);
276 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 7, lens, strlen(lens), SQLITE_TRANSIENT);
279 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, exposure_min);
280 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 11, exposure_max);
281 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 12, aperture_min);
282 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 13, aperture_max);
283 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, focal_length_min);
284 DT_DEBUG_SQLITE3_BIND_INT(stmt, 15, focal_length_max);
285 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 16, op_params_blob, op_params_len, SQLITE_TRANSIENT);
286 DT_DEBUG_SQLITE3_BIND_INT(stmt, 17, op_version);
287 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 18, blendop_params_blob, blendop_params_len, SQLITE_TRANSIENT);
288 DT_DEBUG_SQLITE3_BIND_INT(stmt, 19, blendop_version);
289 DT_DEBUG_SQLITE3_BIND_INT(stmt, 20, enabled);
290 DT_DEBUG_SQLITE3_BIND_INT(stmt, 21, multi_priority);
291 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 22, multi_name, strlen(multi_name), SQLITE_TRANSIENT);
292 DT_DEBUG_SQLITE3_BIND_INT(stmt, 23, filter);
293 DT_DEBUG_SQLITE3_BIND_INT(stmt, 24, def);
294 DT_DEBUG_SQLITE3_BIND_INT(stmt, 25, format);
295
296 result = (sqlite3_step(stmt) == SQLITE_DONE);
297
298 sqlite3_finalize(stmt);
299
300 dt_free(name);
302 dt_free(operation);
303 dt_free(model);
304 dt_free(maker);
305 dt_free(lens);
306 dt_free(op_params);
307 dt_free(blendop_params);
308 dt_free(multi_name);
309
310 return result;
311}
312
313gboolean dt_presets_module_can_autoapply(const gchar *operation)
314{
315 for(const GList *lib_modules = darktable.lib->plugins; lib_modules; lib_modules = g_list_next(lib_modules))
316 {
317 dt_lib_module_t *lib_module = (dt_lib_module_t *)lib_modules->data;
318 if(!strcmp(lib_module->plugin_name, operation))
319 {
320 return dt_lib_presets_can_autoapply(lib_module);
321 }
322 }
323 return TRUE;
324}
325// clang-format off
326// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
327// vim: shiftwidth=2 expandtab tabstop=2 cindent
328// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
329// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:160
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
static const int row
char * name
int dt_presets_import_from_file(const char *preset_path)
static int get_preset_element_float(xmlDocPtr doc, gchar *name)
void dt_presets_save_to_file(const int rowid, const char *preset_name, const char *filedir)
static gchar * get_preset_element(xmlDocPtr doc, gchar *name)
gboolean dt_presets_module_can_autoapply(const gchar *operation)
static char * dt_preset_encode(sqlite3_stmt *stmt, int row)
static int get_preset_element_int(xmlDocPtr doc, gchar *name)
darktable_t darktable
Definition darktable.c:181
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#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 darktable.h:281
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition debug.h:119
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition debug.h:118
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
#define DT_DEBUG_SQLITE3_BIND_DOUBLE(a, b, c)
Definition debug.h:117
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
Definition exif.cc:2337
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:2246
float iso_max
const char * maker
int iso_min
const char * model
gboolean dt_lib_presets_can_autoapply(dt_lib_module_t *mod)
Definition lib.c:1546
struct dt_lib_t * lib
Definition darktable.h:771
const struct dt_database_t * db
Definition darktable.h:779
char plugin_name[128]
Definition lib.h:82
GModule *void * data
Definition lib.h:80
GList * plugins
Definition lib.h:55