Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
history/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 "history/presets.h"
25#include "system/macros.h"
26#include "system/mem_alloc.h"
28#include "metadata/exif.h"
29
30#include <libxml/xmlwriter.h>
31#include <libxml/parser.h>
32#include <libxml/xpath.h>
33
34#include <glib.h>
35#include <inttypes.h>
36
37void dt_presets_save_to_file(const int rowid, const char *preset_name, const char *filedir)
38{
40 if(IS_NULL_PTR(preset)) return;
41
42 // generate filename based on name of preset
43 // convert all characters to underscore which are not allowed in filenames
44 gchar *presetname = g_strdup(preset_name);
45 gchar *filename = g_strdup_printf("%s/%s.dtpreset", filedir, g_strdelimit(presetname, "/<>:\"\\|*?[]", '_'));
47
48 /* The two blobs are base64'd for XML. Both were leaked once per export before -- the
49 * encoder allocates and the results went straight into a "%s" argument. */
50 char *op_params = dt_exif_xmp_encode(preset->op_params, preset->op_params_size, NULL);
51 char *blendop_params = dt_exif_xmp_encode(preset->blendop_params, preset->blendop_params_size, NULL);
52
53 xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename, 0);
54 if(IS_NULL_PTR(writer))
55 {
56 fprintf(stderr, "[dt_presets_save_to_file] Error creating the xml writer\n, path: %s", filename);
57 goto cleanup;
58 }
59
60 if(xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL) < 0)
61 {
62 fprintf(stderr, "[dt_presets_save_to_file]: Error on encoding setting");
63 goto cleanup;
64 }
65
66 xmlTextWriterStartElement(writer, BAD_CAST "darktable_preset");
67 xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0");
68
69 xmlTextWriterStartElement(writer, BAD_CAST "preset");
70 xmlTextWriterWriteFormatElement(writer, BAD_CAST "name", "%s", preset->name);
71 xmlTextWriterWriteFormatElement(writer, BAD_CAST "description", "%s", preset->description);
72 xmlTextWriterWriteFormatElement(writer, BAD_CAST "operation", "%s", preset->operation);
73 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_params", "%s", op_params);
74 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_version", "%d", preset->op_version);
75 xmlTextWriterWriteFormatElement(writer, BAD_CAST "enabled", "%d", preset->enabled);
76 xmlTextWriterWriteFormatElement(writer, BAD_CAST "autoapply", "%d", preset->autoapply);
77 xmlTextWriterWriteFormatElement(writer, BAD_CAST "model", "%s", preset->model);
78 xmlTextWriterWriteFormatElement(writer, BAD_CAST "maker", "%s", preset->maker);
79 xmlTextWriterWriteFormatElement(writer, BAD_CAST "lens", "%s", preset->lens);
80 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iso_min", "%f", preset->iso_min);
81 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iso_max", "%f", preset->iso_max);
82 xmlTextWriterWriteFormatElement(writer, BAD_CAST "exposure_min", "%f", preset->exposure_min);
83 xmlTextWriterWriteFormatElement(writer, BAD_CAST "exposure_max", "%f", preset->exposure_max);
84 xmlTextWriterWriteFormatElement(writer, BAD_CAST "aperture_min", "%f", preset->aperture_min);
85 xmlTextWriterWriteFormatElement(writer, BAD_CAST "aperture_max", "%f", preset->aperture_max);
86 xmlTextWriterWriteFormatElement(writer, BAD_CAST "focal_length_min", "%d", preset->focal_length_min);
87 xmlTextWriterWriteFormatElement(writer, BAD_CAST "focal_length_max", "%d", preset->focal_length_max);
88 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_params", "%s", blendop_params);
89 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_version", "%d", preset->blendop_version);
90 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_priority", "%d", preset->multi_priority);
91 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_name", "%s", preset->multi_name);
92 xmlTextWriterWriteFormatElement(writer, BAD_CAST "filter", "%d", preset->filter);
93 xmlTextWriterWriteFormatElement(writer, BAD_CAST "def", "%d", preset->def);
94 xmlTextWriterWriteFormatElement(writer, BAD_CAST "format", "%d", preset->format);
96
98
100 if(writer) xmlFreeTextWriter(writer);
101 dt_free(op_params);
102 dt_free(blendop_params);
103 dt_free(filename);
105}
106
107static gchar *get_preset_element(xmlDocPtr doc, gchar *name)
108{
110 char xpath[128] = { 0 };
111 snprintf(xpath, sizeof(xpath), "//%s", name);
112 gchar *result = NULL;
113
116
117 if(xpathObj)
118 {
119 const xmlNodeSetPtr xnodes = xpathObj->nodesetval;
120 if(xnodes->nodeTab)
121 {
122 const xmlNodePtr xnode = xnodes->nodeTab[0];
123 xmlChar *value = xmlNodeListGetString(doc, xnode->xmlChildrenNode, 1);
124
125 if(value)
126 result = g_strdup((gchar *)value);
127 else
128 result = g_strdup("");
129
130 xmlFree(value);
131 }
133 }
134
136 return result;
137}
138
140{
141 gchar *value = get_preset_element(doc, name);
142 const int result = value ? atoi(value) : 0;
143 dt_free(value);
144 return result;
145}
146
148{
149 gchar *value = get_preset_element(doc, name);
150 const float result = value ? atof(value) : 0.0f;
151 dt_free(value);
152 return result;
153}
154
156{
158 if(IS_NULL_PTR(doc))
159 return FALSE;
160
162 if(IS_NULL_PTR(root) || xmlStrcmp(root->name, BAD_CAST "darktable_preset") != 0)
163 {
165 return FALSE;
166 }
167
168 dt_preset_t preset = { 0 };
169 preset.name = get_preset_element(doc, "name");
170 preset.description = get_preset_element(doc, "description");
171 preset.operation = get_preset_element(doc, "operation");
172 preset.autoapply = get_preset_element_int(doc, "autoapply");
173 preset.model = get_preset_element(doc, "model");
174 preset.maker = get_preset_element(doc, "maker");
175 preset.lens = get_preset_element(doc, "lens");
176 preset.iso_min = get_preset_element_float(doc, "iso_min");
177 preset.iso_max = get_preset_element_float(doc, "iso_max");
178 preset.exposure_min = get_preset_element_float(doc, "exposure_min");
179 preset.exposure_max = get_preset_element_float(doc, "exposure_max");
180 preset.aperture_min = get_preset_element_float(doc, "aperture_min");
181 preset.aperture_max = get_preset_element_float(doc, "aperture_max");
182 preset.focal_length_min = get_preset_element_int(doc, "focal_length_min");
183 preset.focal_length_max = get_preset_element_int(doc, "focal_length_max");
184 preset.op_version = get_preset_element_int(doc, "op_version");
185 preset.blendop_version = get_preset_element_int(doc, "blendop_version");
186 preset.enabled = get_preset_element_int(doc, "enabled");
187 preset.multi_priority = get_preset_element_int(doc, "multi_priority");
188 preset.multi_name = get_preset_element(doc, "multi_name");
189 preset.filter = get_preset_element_int(doc, "filter");
190 preset.def = get_preset_element_int(doc, "def");
191 preset.format = get_preset_element_int(doc, "format");
192
193 gchar *op_params = get_preset_element(doc, "op_params");
194 gchar *blendop_params = get_preset_element(doc, "blendop_params");
196
197 /* dt_exif_xmp_decode() returns memory the caller owns; the struct borrows it for the
198 * length of the insert and it is released below, not by dt_preset_free() -- `preset` is
199 * a stack value, not one the repository handed out. */
200 if(op_params)
201 preset.op_params = (void *)dt_exif_xmp_decode(op_params, strlen(op_params), &preset.op_params_size);
202 if(blendop_params)
203 preset.blendop_params
204 = (void *)dt_exif_xmp_decode(blendop_params, strlen(blendop_params), &preset.blendop_params_size);
205
206 const int result = dt_preset_repository_insert(&preset) ? 1 : 0;
207
208 dt_free(preset.name);
209 dt_free(preset.description);
210 dt_free(preset.operation);
211 dt_free(preset.model);
212 dt_free(preset.maker);
213 dt_free(preset.lens);
214 dt_free(preset.multi_name);
215 dt_free(preset.op_params);
216 dt_free(preset.blendop_params);
217 dt_free(op_params);
218 dt_free(blendop_params);
219
220 return result;
221}
222
224
229
230gboolean dt_presets_module_can_autoapply(const gchar *operation)
231{
233
234 // With nobody to ask -- ansel-cli, a unit test -- the answer is the same one the old
235 // loop gave for an operation that matched no panel: yes.
236 if(resolver == NULL) return TRUE;
237
238 return resolver(operation);
239}
240// clang-format off
241// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
242// vim: shiftwidth=2 expandtab tabstop=2 cindent
243// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
244// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:170
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
Definition exif.cc:1972
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:1881
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
int dt_presets_import_from_file(const char *preset_path)
void dt_presets_set_autoapply_resolver(dt_presets_autoapply_resolver_t resolver)
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)
static dt_presets_autoapply_resolver_t _autoapply_resolver
gboolean dt_presets_module_can_autoapply(const gchar *operation)
static int get_preset_element_int(xmlDocPtr doc, gchar *name)
gboolean(* dt_presets_autoapply_resolver_t)(const gchar *operation)
Answers whether the panel named operation allows its presets to auto-apply.
struct dt_iop_tonecurve_params_t preset
#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:65
#define dt_free(ptr)
Definition mem_alloc.h:97
const char * name
Definition pdf.h:90
gboolean dt_preset_repository_insert(const dt_preset_t *preset)
Insert preset, replacing any row that collides with it.
dt_preset_t * dt_preset_repository_get_by_rowid(const int rowid)
The preset at rowid, or NULL when there is none. Free with dt_preset_free().
void dt_preset_free(dt_preset_t *preset)
Release a dt_preset_t and everything it owns. NULL-safe.
data.presets: a module's saved parameters, with the conditions under which it auto-applies.
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
One row of data.presets, owned by the caller.