Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
src/common/styles.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 calca.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2010-2012 johannes hanika.
6 Copyright (C) 2010-2017 Tobias Ellinghaus.
7 Copyright (C) 2012-2013, 2019-2022 Aldric Renaudin.
8 Copyright (C) 2012 Frédéric Grollier.
9 Copyright (C) 2012-2013 Jérémy Rosen.
10 Copyright (C) 2012-2015, 2017, 2019-2022 Pascal Obry.
11 Copyright (C) 2012 Richard Levitte.
12 Copyright (C) 2012 Richard Wonka.
13 Copyright (C) 2012-2013, 2015 Ulrich Pegelow.
14 Copyright (C) 2013 Pascal de Bruijn.
15 Copyright (C) 2013 Simon Spannagel.
16 Copyright (C) 2014, 2016 Roman Lebedev.
17 Copyright (C) 2018-2019 Edgardo Hoszowski.
18 Copyright (C) 2019, 2021 Hanno Schwalm.
19 Copyright (C) 2019-2020 Heiko Bauke.
20 Copyright (C) 2019-2020 Philippe Weyland.
21 Copyright (C) 2020 Chris Elston.
22 Copyright (C) 2020-2021 darkelectron.
23 Copyright (C) 2020 EdgarLux.
24 Copyright (C) 2020-2022 Hubert Kowalski.
25 Copyright (C) 2020 JP Verrue.
26 Copyright (C) 2021-2022 Diederik Ter Rahe.
27 Copyright (C) 2021 luzpaz.
28 Copyright (C) 2021 Ralf Brown.
29 Copyright (C) 2022, 2025-2026 Aurélien PIERRE.
30 Copyright (C) 2022 Martin Bařinka.
31
32 darktable is free software: you can redistribute it and/or modify
33 it under the terms of the GNU General Public License as published by
34 the Free Software Foundation, either version 3 of the License, or
35 (at your option) any later version.
36
37 darktable is distributed in the hope that it will be useful,
38 but WITHOUT ANY WARRANTY; without even the implied warranty of
39 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 GNU General Public License for more details.
41
42 You should have received a copy of the GNU General Public License
43 along with darktable. If not, see <http://www.gnu.org/licenses/>.
44*/
45
46#include "common/styles.h"
47#include "common/collection.h"
48#include "common/darktable.h"
49#include "common/debug.h"
50#include "common/exif.h"
52#include "common/history.h"
54#include "common/image_cache.h"
55#include "common/imageio.h"
56#include "common/iop_order.h"
57#include "common/tags.h"
58#include "control/control.h"
59
60static sqlite3_stmt *_styles_get_list_stmt = NULL;
61static sqlite3_stmt *_styles_apply_items_stmt = NULL;
62#include "develop/develop.h"
63#include "develop/dev_history.h"
64
65
66#include "gui/styles.h"
67#include <libxml/encoding.h>
68#include <libxml/xmlwriter.h>
69
70#include <glib.h>
71#include <stdio.h>
72#include <string.h>
73
74#define DT_IOP_ORDER_INFO (darktable.unmuted & DT_DEBUG_IOPORDER)
75
76typedef struct
77{
78 GString *name;
79 GString *description;
80 GList *iop_list;
82
83typedef struct
84{
85 int num;
86 int module;
87 GString *operation;
88 GString *op_params;
92 GString *multi_name;
94 double iop_order;
96
97typedef struct
98{
100 GList *plugins;
101 gboolean in_plugin;
102} StyleData;
103
104void dt_style_free(gpointer data)
105{
106 dt_style_t *style = (dt_style_t *)data;
107 dt_free(style->name);
108 dt_free(style->description);
109 style->name = NULL;
110 style->description = NULL;
111 dt_free(style);
112}
113
114void dt_style_item_free(gpointer data)
115{
116 dt_style_item_t *item = (dt_style_item_t *)data;
117 dt_free(item->name);
118 dt_free(item->operation);
119 dt_free(item->multi_name);
120 dt_free(item->params);
121 dt_free(item->blendop_params);
122 item->name = NULL;
123 item->operation = NULL;
124 item->multi_name = NULL;
125 item->params = NULL;
126 item->blendop_params = NULL;
127 dt_free(item);
128}
129
130int32_t dt_styles_get_id_by_name(const char *name);
131
132gboolean dt_styles_exists(const char *name)
133{
134 if(name)
135 return (dt_styles_get_id_by_name(name)) != 0 ? TRUE : FALSE;
136 return FALSE;
137}
138
140{
141 sqlite3_stmt *stmt;
142 GList *list = NULL;
143 struct _data
144 {
145 int rowid;
146 int mi;
147 };
148 char last_operation[128] = { 0 };
149 int last_mi = 0;
150
151 /* let's clean-up the style multi-instance. What we want to do is have a unique multi_priority value for
152 each iop.
153 Furthermore this value must start to 0 and increment one by one for each multi-instance of the same
154 module. On
155 SQLite there is no notion of ROW_NUMBER, so we use rather resource consuming SQL statement, but as a
156 style has
157 never a huge number of items that's not a real issue. */
158
159 /* 1. read all data for the style and record multi_instance value. */
160
163 "SELECT rowid,operation FROM data.style_items WHERE styleid=?1 ORDER BY operation, multi_priority ASC", -1,
164 &stmt, NULL);
165 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
166
167 while(sqlite3_step(stmt) == SQLITE_ROW)
168 {
169 struct _data *d = malloc(sizeof(struct _data));
170 const char *operation = (const char *)sqlite3_column_text(stmt, 1);
171
172 if(strncmp(last_operation, operation, 128) != 0)
173 {
174 last_mi = 0;
175 g_strlcpy(last_operation, operation, sizeof(last_operation));
176 }
177 else
178 last_mi++;
179
180 d->rowid = sqlite3_column_int(stmt, 0);
181 d->mi = last_mi;
182 list = g_list_prepend(list, d);
183 }
184 sqlite3_finalize(stmt);
185 list = g_list_reverse(list); // list was built in reverse order, so un-reverse it
186
187 /* 2. now update all multi_instance values previously recorded */
188
189 for(GList *list_iter = list; list_iter; list_iter = g_list_next(list_iter))
190 {
191 struct _data *d = (struct _data *)list_iter->data;
192
194 "UPDATE data.style_items SET multi_priority=?1 WHERE rowid=?2", -1, &stmt, NULL);
195 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, d->mi);
196 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, d->rowid);
197 sqlite3_step(stmt);
198 sqlite3_finalize(stmt);
199 }
200
201 /* 3. free the list we built in step 1 */
202 g_list_free_full(list, dt_free_gpointer);
203 list = NULL;
204}
205
206gboolean dt_styles_has_module_order(const char *name)
207{
208 sqlite3_stmt *stmt;
209 // clang-format off
211 "SELECT iop_list"
212 " FROM data.styles"
213 " WHERE name=?1",
214 -1, &stmt, NULL);
215 // clang-format on
216 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, -1, SQLITE_TRANSIENT);
217 sqlite3_step(stmt);
218 const gboolean has_iop_list = (sqlite3_column_type(stmt, 0) != SQLITE_NULL);
219 sqlite3_finalize(stmt);
220 return has_iop_list;
221}
222
224{
225 GList *iop_list = NULL;
226 sqlite3_stmt *stmt;
227 // clang-format off
229 "SELECT iop_list"
230 " FROM data.styles"
231 " WHERE name=?1",
232 -1, &stmt, NULL);
233 // clang-format on
234 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, -1, SQLITE_TRANSIENT);
235 sqlite3_step(stmt);
236 if(sqlite3_column_type(stmt, 0) != SQLITE_NULL)
237 {
238 const char *iop_list_txt = (char *)sqlite3_column_text(stmt, 0);
239 iop_list = dt_ioppr_deserialize_text_iop_order_list(iop_list_txt);
240 }
241 sqlite3_finalize(stmt);
242 return iop_list;
243}
244
245static gboolean dt_styles_create_style_header(const char *name, const char *description, GList *iop_list)
246{
247 sqlite3_stmt *stmt;
248
250 {
251 dt_control_log(_("style with name '%s' already exists"), name);
252 return FALSE;
253 }
254
255 char *iop_list_txt = NULL;
256
257 /* first create the style header */
258 // clang-format off
261 "INSERT INTO data.styles (name, description, id, iop_list)"
262 " VALUES (?1, ?2, (SELECT COALESCE(MAX(id),0)+1 FROM data.styles), ?3)", -1, &stmt, NULL);
263 // clang-format on
264 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, -1, SQLITE_STATIC);
265 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, description, -1, SQLITE_STATIC);
266 if(iop_list)
267 {
268 iop_list_txt = dt_ioppr_serialize_text_iop_order_list(iop_list);
269 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, iop_list_txt, -1, SQLITE_STATIC);
270 }
271 else
272 sqlite3_bind_null(stmt, 3);
273
274 sqlite3_step(stmt);
275 sqlite3_finalize(stmt);
276
277 dt_free(iop_list_txt);
278 return TRUE;
279}
280
281static void _dt_style_update_from_image(int id, int32_t imgid, GList *filter, GList *update)
282{
283 if(update && imgid != UNKNOWN_IMAGE)
284 {
285 GList *list = filter;
286 GList *upd = update;
287 char query[4096] = { 0 };
288 char tmp[500];
289 char *fields[] = { "op_params", "module", "enabled", "blendop_params",
290 "blendop_version", "multi_priority", "multi_name", 0 };
291
292 do
293 {
294 query[0] = '\0';
295
296 // included and update set, we then need to update the corresponding style item
297 if(GPOINTER_TO_INT(upd->data) != -1 && GPOINTER_TO_INT(list->data) != -1)
298 {
299 g_strlcpy(query, "UPDATE data.style_items SET ", sizeof(query));
300
301 for(int k = 0; fields[k]; k++)
302 {
303 if(k != 0) g_strlcat(query, ",", sizeof(query));
304 snprintf(tmp, sizeof(tmp),
305 "%s=(SELECT %s FROM main.history WHERE imgid=%d AND num=%d)",
306 fields[k], fields[k], imgid, GPOINTER_TO_INT(upd->data));
307 g_strlcat(query, tmp, sizeof(query));
308 }
309 snprintf(tmp, sizeof(tmp), " WHERE styleid=%d AND data.style_items.num=%d", id,
310 GPOINTER_TO_INT(list->data));
311 g_strlcat(query, tmp, sizeof(query));
312 }
313 // update only, so we want to insert the new style item
314 else if(GPOINTER_TO_INT(upd->data) != -1)
315 // clang-format off
316 snprintf(query, sizeof(query),
317 "INSERT INTO data.style_items "
318 " (styleid, num, module, operation, op_params, enabled, blendop_params,"
319 " blendop_version, multi_priority, multi_name)"
320 " SELECT %d,"
321 " (SELECT num+1 "
322 " FROM data.style_items"
323 " WHERE styleid=%d"
324 " ORDER BY num DESC LIMIT 1), "
325 " module, operation, op_params, enabled, blendop_params, blendop_version,"
326 " multi_priority, multi_name"
327 " FROM main.history"
328 " WHERE imgid=%d AND num=%d",
329 id, id, imgid, GPOINTER_TO_INT(upd->data));
330 // clang-format on
331
332 if(*query) DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL);
333
334 list = g_list_next(list);
335 upd = g_list_next(upd);
336 } while(list);
337 }
338}
339
340static void _dt_style_update_iop_order(const gchar *name, const int id, const int32_t imgid,
341 const gboolean copy_iop_order, const gboolean update_iop_order)
342{
343 sqlite3_stmt *stmt;
344
345 GList *iop_list = dt_styles_module_order_list(name);
346
347 // if we update or if the style does not contains an order then the
348 // copy must be done using the imgid iop-order.
349
350 if(update_iop_order || IS_NULL_PTR(iop_list))
351 iop_list = dt_ioppr_get_iop_order_list(imgid, FALSE);
352
353 gchar *iop_list_txt = dt_ioppr_serialize_text_iop_order_list(iop_list);
354
355 if(copy_iop_order || update_iop_order)
356 {
357 // copy from style name to style id
359 "UPDATE data.styles SET iop_list=?1 WHERE id=?2", -1, &stmt, NULL);
360 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, iop_list_txt, -1, SQLITE_TRANSIENT);
361 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id);
362 }
363 else
364 {
366 "UPDATE data.styles SET iop_list=NULL WHERE id=?1", -1, &stmt, NULL);
367 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
368 }
369
370 g_list_free_full(iop_list, dt_free_gpointer);
371 iop_list = NULL;
372 dt_free(iop_list_txt);
373
374 sqlite3_step(stmt);
375 sqlite3_finalize(stmt);
376}
377
378void dt_styles_update(const char *name, const char *newname, const char *newdescription, GList *filter,
379 const int32_t imgid, GList *update,
380 const gboolean copy_iop_order, const gboolean update_iop_order)
381{
382 sqlite3_stmt *stmt;
383
384 const int id = dt_styles_get_id_by_name(name);
385 if(id == 0) return;
386
387 gchar *desc = dt_styles_get_description(name);
388
389 if((g_strcmp0(name, newname)) || (g_strcmp0(desc, newdescription)))
390 {
392 "UPDATE data.styles SET name=?1, description=?2 WHERE id=?3", -1, &stmt, NULL);
393 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, newname, -1, SQLITE_STATIC);
394 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, newdescription, -1, SQLITE_STATIC);
395 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id);
396 sqlite3_step(stmt);
397 sqlite3_finalize(stmt);
398 }
399
400 if(filter)
401 {
402 char tmp[64];
403 char include[2048] = { 0 };
404 g_strlcat(include, "num NOT IN (", sizeof(include));
405 for(GList *list = filter; list; list = g_list_next(list))
406 {
407 if(list != filter) g_strlcat(include, ",", sizeof(include));
408 snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data));
409 g_strlcat(include, tmp, sizeof(include));
410 }
411 g_strlcat(include, ")", sizeof(include));
412
413 char query[4096] = { 0 };
414 snprintf(query, sizeof(query), "DELETE FROM data.style_items WHERE styleid=?1 AND %s", include);
416 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
417 sqlite3_step(stmt);
418 sqlite3_finalize(stmt);
419 }
420
421 _dt_style_update_from_image(id, imgid, filter, update);
422
423 _dt_style_update_iop_order(name, id, imgid, copy_iop_order, update_iop_order);
424
425 if(!copy_iop_order && !update_iop_order)
426 {
427 // Without a stored module order, style items are self-contained and can use compact priorities.
429 }
430
431 /* backup style to disk */
432 dt_styles_save_to_file(newname, NULL, TRUE);
433
435
436 dt_free(desc);
437}
438
439void dt_styles_create_from_style(const char *name, const char *newname, const char *description,
440 GList *filter, const int32_t imgid, GList *update,
441 const gboolean copy_iop_order, const gboolean update_iop_order)
442{
443 sqlite3_stmt *stmt;
444 int id = 0;
445
446 const int oldid = dt_styles_get_id_by_name(name);
447 if(oldid == 0) return;
448
449 /* create the style header */
450 if(!dt_styles_create_style_header(newname, description, NULL)) return;
451
452 if((id = dt_styles_get_id_by_name(newname)) != 0)
453 {
454 if(filter)
455 {
456 char tmp[64];
457 char include[2048] = { 0 };
458 g_strlcat(include, "num IN (", sizeof(include));
459 for(GList *list = filter; list; list = g_list_next(list))
460 {
461 if(list != filter) g_strlcat(include, ",", sizeof(include));
462 snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data));
463 g_strlcat(include, tmp, sizeof(include));
464 }
465 g_strlcat(include, ")", sizeof(include));
466 char query[4096] = { 0 };
467
468 // clang-format off
469 snprintf(query, sizeof(query),
470 "INSERT INTO data.style_items "
471 " (styleid,num,module,operation,op_params,enabled,blendop_params,blendop_version,"
472 " multi_priority,multi_name)"
473 " SELECT ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,"
474 " multi_priority,multi_name"
475 " FROM data.style_items"
476 " WHERE styleid=?2 AND %s",
477 include);
478 // clang-format on
480 }
481 else
482 // clang-format off
484 "INSERT INTO data.style_items "
485 " (styleid,num,module,operation,op_params,enabled,blendop_params,"
486 " blendop_version,multi_priority,multi_name)"
487 " SELECT ?1, num,module,operation,op_params,enabled,blendop_params,"
488 " blendop_version,multi_priority,multi_name"
489 " FROM data.style_items"
490 " WHERE styleid=?2",
491 -1, &stmt, NULL);
492 // clang-format on
493 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
494 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, oldid);
495 sqlite3_step(stmt);
496 sqlite3_finalize(stmt);
497
498 /* insert items from imgid if defined */
499
500 _dt_style_update_from_image(id, imgid, filter, update);
501
502 _dt_style_update_iop_order(name, id, imgid, copy_iop_order, update_iop_order);
503
504 if(!copy_iop_order && !update_iop_order)
505 {
506 // Without a stored module order, style items are self-contained and can use compact priorities.
508 }
509
510 /* backup style to disk */
511 dt_styles_save_to_file(newname, NULL, FALSE);
512
513 dt_control_log(_("style named '%s' successfully created"), newname);
515 }
516}
517
518gboolean dt_styles_create_from_image(const char *name, const char *description,
519 const int32_t imgid, GList *filter, gboolean copy_iop_order)
520{
521 int id = 0;
522 sqlite3_stmt *stmt;
523
524 GList *iop_list = NULL;
525 if(copy_iop_order)
526 {
527 iop_list = dt_ioppr_get_iop_order_list(imgid, FALSE);
528 }
529
530 /* first create the style header */
531 if(!dt_styles_create_style_header(name, description, iop_list)) return FALSE;
532
533 g_list_free_full(iop_list, dt_free_gpointer);
534 iop_list = NULL;
535
536 if((id = dt_styles_get_id_by_name(name)) != 0)
537 {
538 /* create the style_items from source image history stack */
539 if(filter)
540 {
541 char tmp[64];
542 char include[2048] = { 0 };
543 g_strlcat(include, "num IN (", sizeof(include));
544 for(GList *list = filter; list; list = g_list_next(list))
545 {
546 if(list != filter) g_strlcat(include, ",", sizeof(include));
547 snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data));
548 g_strlcat(include, tmp, sizeof(include));
549 }
550
551 g_strlcat(include, ")", sizeof(include));
552 char query[4096] = { 0 };
553 // clang-format off
554 snprintf(query, sizeof(query),
555 "INSERT INTO data.style_items"
556 " (styleid,num,module,operation,op_params,enabled,blendop_params,"
557 " blendop_version,multi_priority,multi_name)"
558 " SELECT ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,"
559 " multi_priority,multi_name"
560 " FROM main.history"
561 " WHERE imgid=?2 AND %s",
562 include);
563 // clang-format on
565 }
566 else
567 // clang-format off
569 "INSERT INTO data.style_items"
570 " (styleid,num,module,operation,op_params,enabled,blendop_params,"
571 " blendop_version,multi_priority,multi_name)"
572 " SELECT ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,"
573 " multi_priority,multi_name"
574 " FROM main.history"
575 " WHERE imgid=?2",
576 -1, &stmt, NULL);
577 // clang-format on
578 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
579 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
580 sqlite3_step(stmt);
581 sqlite3_finalize(stmt);
582
583 if(!copy_iop_order)
584 {
585 // A style without module order cannot use sparse image priorities, so compact them locally.
587 }
588
589 /* backup style to disk */
591
593 return TRUE;
594 }
595 return FALSE;
596}
597
598
599void dt_multiple_styles_apply_to_list(GList *styles, const GList *list, gboolean duplicate)
600{
601 /* write current history changes so nothing gets lost,
602 do that only in the darkroom as there is nothing to be saved
603 when in the lighttable (and it would write over current history stack) */
604
605 if(IS_NULL_PTR(styles) && !list)
606 {
607 dt_control_log(_("no images nor styles selected!"));
608 return;
609 }
610 else if(!styles)
611 {
612 dt_control_log(_("no styles selected!"));
613 return;
614 }
615 else if(!list)
616 {
617 dt_control_log(_("no image selected!"));
618 return;
619 }
620
621 /* for each selected image apply style */
623 for(const GList *l = list; l; l = g_list_next(l))
624 {
625 const int32_t imgid = GPOINTER_TO_INT(l->data);
626 for(GList *style = styles; style; style = g_list_next(style))
627 {
628 dt_history_style_on_image(imgid, (char *)style->data, duplicate);
629 }
630 }
632
633 const guint styles_cnt = g_list_length(styles);
634 dt_control_log(ngettext("style successfully applied!", "styles successfully applied!", styles_cnt));
635}
636
637void dt_styles_create_from_list(const GList *list)
638{
639 gboolean selected = FALSE;
640 /* for each image create style */
641 for(const GList *l = list; l; l = g_list_next(l))
642 {
643 const int32_t imgid = GPOINTER_TO_INT(l->data);
645 selected = TRUE;
646 }
647
648 if(!selected) dt_control_log(_("no image selected!"));
649}
650
651static const char *_dt_styles_normalize_multi_name(const char *multi_name)
652{
653 if(IS_NULL_PTR(multi_name) || !*multi_name || !strcmp(multi_name, "0")) return "";
654 return multi_name;
655}
656
657static gboolean _dt_styles_apply_item_to_module(dt_iop_module_t *module, const dt_style_item_t *style_item)
658{
659 module->enabled = style_item->enabled;
660
661 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
662 if(*multi_name)
663 g_strlcpy(module->multi_name, multi_name, sizeof(module->multi_name));
664 else
665 module->multi_name[0] = '\0';
666
667 if(style_item->blendop_params && (style_item->blendop_version == dt_develop_blend_version())
668 && (style_item->blendop_params_size == sizeof(dt_develop_blend_params_t)))
669 {
670 memcpy(module->blend_params, style_item->blendop_params, sizeof(dt_develop_blend_params_t));
671 }
672 else if(style_item->blendop_params
673 && dt_develop_blend_legacy_params(module, style_item->blendop_params, style_item->blendop_version,
675 style_item->blendop_params_size)
676 == 0)
677 {
678 // do nothing
679 }
680 else if(module->default_blendop_params)
681 {
682 memcpy(module->blend_params, module->default_blendop_params, sizeof(dt_develop_blend_params_t));
683 }
684
685 gboolean ok = TRUE;
686 if(module->version() != style_item->module_version || module->params_size != style_item->params_size
687 || strcmp(style_item->operation, module->op))
688 {
689 if(!module->legacy_params
690 || module->legacy_params(module, style_item->params, labs(style_item->module_version), module->params,
691 labs(module->version())))
692 {
693 fprintf(stderr, "[dt_styles_apply] module `%s' version mismatch: history is %d, dt %d.\n", module->op,
694 style_item->module_version, module->version());
695 dt_control_log(_("module `%s' version mismatch: %d != %d"), module->op, module->version(),
696 style_item->module_version);
697 ok = FALSE;
698 }
699 }
700 else
701 {
702 memcpy(module->params, style_item->params, module->params_size);
703 }
704
705 if(ok && !strcmp(module->op, "flip") && module->enabled == 0 && labs(style_item->module_version) == 1)
706 {
707 memcpy(module->params, module->default_params, module->params_size);
708 module->enabled = 1;
709 }
710
711 return ok;
712}
713
715{
716 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
717 dt_iop_module_t *module = dt_dev_get_module_instance(dev, style_item->operation, multi_name,
718 style_item->multi_priority);
719 if(module) return module;
720
721 module = dt_dev_create_module_instance(dev, style_item->operation, multi_name, style_item->multi_priority, FALSE);
722 if(module) module->iop_order = style_item->iop_order;
723 return module;
724}
725
727{
728 dt_iop_module_t *mod_src = dt_iop_get_module_by_op_priority(dev->iop, style_item->operation, -1);
729 if(IS_NULL_PTR(mod_src)) return NULL;
730
731 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
732 if(dt_iop_load_module(module, mod_src->so, dev))
733 {
734 fprintf(stderr, "[dt_styles_apply] can't load module %s %s\n", style_item->operation,
735 style_item->multi_name ? style_item->multi_name : "(null)");
736 dt_free(module);
737 return NULL;
738 }
739
740 module->instance = mod_src->instance;
741 module->multi_priority = style_item->multi_priority;
742 module->iop_order = style_item->iop_order;
743
744 if(!_dt_styles_apply_item_to_module(module, style_item))
745 {
746 dt_iop_cleanup_module(module);
747 dt_free(module);
748 return NULL;
749 }
750
751 return module;
752}
753
754static GList *_dt_styles_get_apply_items(const int style_id)
755{
757 {
758 // clang-format off
760 "SELECT num, module, operation, op_params, enabled,"
761 " blendop_params, blendop_version, multi_priority, multi_name"
762 " FROM data.style_items WHERE styleid=?1 "
763 " ORDER BY num, operation, multi_priority",
764 -1, &_styles_apply_items_stmt, NULL);
765 // clang-format on
766 }
767
768 sqlite3_stmt *stmt = _styles_apply_items_stmt;
769 sqlite3_reset(stmt);
770 sqlite3_clear_bindings(stmt);
771 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, style_id);
772
773 GList *si_list = NULL;
774 while(sqlite3_step(stmt) == SQLITE_ROW)
775 {
776 dt_style_item_t *style_item = (dt_style_item_t *)malloc(sizeof(dt_style_item_t));
777
778 style_item->num = sqlite3_column_int(stmt, 0);
779 style_item->selimg_num = 0;
780 style_item->enabled = sqlite3_column_int(stmt, 4);
781 style_item->multi_priority = sqlite3_column_int(stmt, 7);
782 style_item->name = NULL;
783 style_item->operation = g_strdup((char *)sqlite3_column_text(stmt, 2));
784 style_item->multi_name = g_strdup((char *)sqlite3_column_text(stmt, 8));
785 style_item->module_version = sqlite3_column_int(stmt, 1);
786 style_item->blendop_version = sqlite3_column_int(stmt, 6);
787 style_item->params_size = sqlite3_column_bytes(stmt, 3);
788 style_item->params = (void *)malloc(style_item->params_size);
789 memcpy(style_item->params, (void *)sqlite3_column_blob(stmt, 3), style_item->params_size);
790 style_item->blendop_params_size = sqlite3_column_bytes(stmt, 5);
791 style_item->blendop_params = (void *)malloc(style_item->blendop_params_size);
792 memcpy(style_item->blendop_params, (void *)sqlite3_column_blob(stmt, 5), style_item->blendop_params_size);
793 style_item->iop_order = 0;
794
795 si_list = g_list_prepend(si_list, style_item);
796 }
797
798 sqlite3_reset(stmt);
799 return g_list_reverse(si_list); // list was built in reverse order, so un-reverse it
800}
801
802static GList *_dt_styles_build_mod_list_from_history(dt_develop_t *dev, GHashTable *style_ids)
803{
804 GList *mod_list = NULL;
805 for(GList *h = g_list_first(dev->history); h; h = g_list_next(h))
806 {
808 if(!hist || !hist->module) continue;
809 char *id_str = g_strdup_printf("%s|%s", hist->op_name, hist->multi_name);
810 const gboolean keep = g_hash_table_contains(style_ids, id_str);
811 dt_free(id_str);
812 if(!keep) continue;
813
814 if(!g_list_find(mod_list, hist->module))
815 mod_list = g_list_append(mod_list, hist->module);
816 }
817 return mod_list;
818}
819
821{
822 if(IS_NULL_PTR(module)) return;
823 dt_iop_cleanup_module(module);
824 dt_free(module);
825}
826
827static int _styles_init_source_dev(dt_develop_t *dev_src, const char *name, const int32_t imgid,
828 gboolean *has_iop_list)
829{
830 dt_dev_init(dev_src, FALSE);
831 if(dt_dev_ensure_image_storage(dev_src, imgid)) return 1;
832
833 *has_iop_list = FALSE;
834 dt_ioppr_set_default_iop_order(dev_src, imgid);
835 dt_dev_init_default_history(dev_src, imgid, FALSE);
836
837 // If the style has a stored iop-order list, apply it to the temporary pipeline
838 GList *iop_list = dt_styles_module_order_list(name);
839 if(iop_list)
840 {
841 g_list_free_full(dev_src->iop_order_list, dt_free_gpointer);
842 dev_src->iop_order_list = iop_list;
843 *has_iop_list = TRUE;
844 }
845
846 return 0;
847}
848
849static GList *_styles_collect_applied_items(dt_develop_t *dev_src, GList *si_list, GHashTable *style_ids)
850{
851 GList *applied_items = NULL;
852
853 for(GList *l = si_list; l; l = g_list_next(l))
854 {
855 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
856 dt_iop_module_t *module = _dt_styles_get_or_create_module_instance(dev_src, style_item);
857 if(IS_NULL_PTR(module)) continue;
858
859 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
860 module->multi_priority = style_item->multi_priority;
861 g_strlcpy(module->multi_name, multi_name, sizeof(module->multi_name));
862
863 if(!_dt_styles_apply_item_to_module(module, style_item)) continue;
864
865 applied_items = g_list_append(applied_items, style_item);
866 g_hash_table_add(style_ids, g_strdup_printf("%s|%s", style_item->operation, multi_name));
867 }
868
869 return applied_items;
870}
871
872static void _styles_sync_pipeline_from_items(dt_develop_t *dev_src, GList *applied_items,
873 const gboolean has_iop_list)
874{
875 if(!has_iop_list) dt_ioppr_update_for_style_items(dev_src, applied_items, FALSE);
876
877 for(GList *l = applied_items; l; l = g_list_next(l))
878 {
879 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
880 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
881 dt_iop_module_t *module
882 = dt_dev_get_module_instance(dev_src, style_item->operation, multi_name, style_item->multi_priority);
883 if(!IS_NULL_PTR(module))
884 {
885 if(has_iop_list)
886 style_item->iop_order = dt_ioppr_get_iop_order(dev_src->iop_order_list, style_item->operation,
887 style_item->multi_priority);
888 module->multi_priority = style_item->multi_priority;
889 module->iop_order = style_item->iop_order;
890 }
891 }
892
893 dt_ioppr_resync_pipeline(dev_src, 0, NULL, FALSE);
894}
895
896static int _styles_rebuild_history_from_items(dt_develop_t *dev_src, GList *applied_items)
897{
899
900 for(GList *l = applied_items; l; l = g_list_next(l))
901 {
902 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
903 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
904 dt_iop_module_t *module
905 = dt_dev_get_module_instance(dev_src, style_item->operation, multi_name, style_item->multi_priority);
906 if(IS_NULL_PTR(module)) continue;
907
909 if(IS_NULL_PTR(hist)) return 1;
910
911 dev_src->history = g_list_append(dev_src->history, hist);
912 if(!dt_dev_history_item_update_from_params(dev_src, hist, module, module->enabled, NULL, 0, NULL, NULL))
913 {
915 return 1;
916 }
917 }
918
919 dt_dev_set_history_end_ext(dev_src, g_list_length(dev_src->history));
920
923
924 return 0;
925}
926
927static int _styles_prepare_source_dev(dt_develop_t *dev_src, const char *name, const int style_id,
928 const int32_t imgid, GList **out_si_list, GHashTable **out_style_ids,
929 GList **out_mod_list)
930{
931 gboolean has_iop_list = FALSE;
932 if(_styles_init_source_dev(dev_src, name, imgid, &has_iop_list)) return 1;
933
934 GList *si_list = _dt_styles_get_apply_items(style_id);
935 if(!has_iop_list)
936 {
937 // Without a stored iop_list, add order entries before creating the style modules;
938 // otherwise update_for_style_items() sees the new modules as already present.
939 dt_ioppr_update_for_style_items(dev_src, si_list, FALSE);
940 }
941
942 GHashTable *style_ids = g_hash_table_new_full(g_str_hash, g_str_equal, dt_free_gpointer, NULL);
943 GList *applied_items = _styles_collect_applied_items(dev_src, si_list, style_ids);
944
945 if(IS_NULL_PTR(applied_items))
946 {
947 g_hash_table_destroy(style_ids);
948 g_list_free_full(si_list, dt_style_item_free);
949 si_list = NULL;
950 return 1;
951 }
952
953 _styles_sync_pipeline_from_items(dev_src, applied_items, has_iop_list);
954 if(_styles_rebuild_history_from_items(dev_src, applied_items))
955 {
956 g_list_free(applied_items);
957 applied_items = NULL;
958 g_hash_table_destroy(style_ids);
959 g_list_free_full(si_list, dt_style_item_free);
960 si_list = NULL;
961 return 1;
962 }
963
964 // Build module list from the compressed history to guarantee a matching history entry
965 GList *mod_list = _dt_styles_build_mod_list_from_history(dev_src, style_ids);
966 g_list_free(applied_items);
967 applied_items = NULL;
968
969 if(!mod_list)
970 {
971 g_hash_table_destroy(style_ids);
972 g_list_free_full(si_list, dt_style_item_free);
973 si_list = NULL;
974 return 1;
975 }
976
977 *out_si_list = si_list;
978 *out_style_ids = style_ids;
979 *out_mod_list = mod_list;
980 return 0;
981}
982
983int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid,
985{
986 int ret_val = 1;
987
988 // Init source history + pipeline (style content)
989 dt_develop_t dev_src = { 0 };
990
991 GList *si_list = NULL;
992 GHashTable *style_ids = NULL;
993 GList *mod_list = NULL;
994
995 if(_styles_prepare_source_dev(&dev_src, name, style_id, newimgid, &si_list, &style_ids, &mod_list))
996 {
997 dt_dev_cleanup(&dev_src);
998 return 1;
999 }
1000
1001 if (DT_IOP_ORDER_INFO) fprintf(stderr,"\n^^^^^ Apply style on image %i, history size %i\n",newimgid, dt_dev_get_history_end_ext(&dev_src));
1002
1003 if(mode == DT_HISTORY_MERGE_REPLACE)
1004 {
1005 ret_val = dt_dev_replace_history_on_image(&dev_src, newimgid, TRUE, "_styles_apply_to_image_merge");
1006 }
1007 else
1008 {
1009 ret_val = dt_dev_merge_history_into_image(&dev_src, newimgid, mod_list,
1010 dt_conf_get_bool("history/style/copy_iop_order"), mode,
1011 dt_conf_get_bool("history/paste_instances"), name, batch);
1012 }
1013
1014 g_list_free(mod_list);
1015 mod_list = NULL;
1016 g_hash_table_destroy(style_ids);
1017 g_list_free_full(si_list, dt_style_item_free);
1018 si_list = NULL;
1019 dt_dev_cleanup(&dev_src);
1020
1021 return ret_val;
1022}
1023
1025{
1027
1028 dt_iop_module_t *module = _dt_styles_tmp_module_from_style_item(dev, style_item);
1029 if(module)
1030 {
1031 dt_history_merge_module_into_history(dev, NULL, module);
1032 dt_ioppr_resync_pipeline(dev, 0, NULL, FALSE);
1035 }
1036
1038}
1039
1040void dt_styles_apply_to_image(const char *name, const gboolean duplicate, const int32_t imgid)
1041{
1043 dt_history_style_on_image(imgid, name, duplicate);
1045}
1046
1047void dt_styles_delete_by_name_adv(const char *name, const gboolean raise)
1048{
1049 int id = 0;
1050 if((id = dt_styles_get_id_by_name(name)) != 0)
1051 {
1052 /* delete the style */
1053 sqlite3_stmt *stmt;
1054 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM data.styles WHERE id = ?1", -1, &stmt,
1055 NULL);
1056 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
1057 sqlite3_step(stmt);
1058 sqlite3_finalize(stmt);
1059
1060 /* delete style_items belonging to style */
1061 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM data.style_items WHERE styleid = ?1",
1062 -1, &stmt, NULL);
1063 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
1064 sqlite3_step(stmt);
1065 sqlite3_finalize(stmt);
1066
1067 if(raise)
1069 }
1070}
1071
1076
1077GList *dt_styles_get_item_list(const char *name, gboolean params, int32_t imgid)
1078{
1079 GList *result = NULL;
1080 sqlite3_stmt *stmt;
1081 int id = 0;
1082 if((id = dt_styles_get_id_by_name(name)) != 0)
1083 {
1084 if(params)
1085 // clang-format off
1087 "SELECT num, multi_priority, module, operation, enabled, op_params, blendop_params, "
1088 " multi_name, blendop_version"
1089 " FROM data.style_items"
1090 " WHERE styleid=?1 ORDER BY num DESC",
1091 -1, &stmt, NULL);
1092 // clang-format on
1093 else if(imgid != UNKNOWN_IMAGE)
1094 {
1095 // get all items from the style
1096 // UNION
1097 // get all items from history, not in the style : select only the last operation, that is max(num)
1098 // clang-format off
1101 "SELECT num, multi_priority, module, operation, enabled,"
1102 " (SELECT MAX(num)"
1103 " FROM main.history"
1104 " WHERE imgid=?2 "
1105 " AND operation=data.style_items.operation"
1106 " AND multi_priority=data.style_items.multi_priority),"
1107 " 0, multi_name, blendop_version"
1108 " FROM data.style_items"
1109 " WHERE styleid=?1"
1110 " UNION"
1111 " SELECT -1,main.history.multi_priority,main.history.module,main.history.operation,main.history.enabled, "
1112 " main.history.num,0,multi_name, blendop_version"
1113 " FROM main.history"
1114 " WHERE imgid=?2 AND main.history.enabled=1"
1115 " AND (main.history.operation NOT IN (SELECT operation FROM data.style_items WHERE styleid=?1))"
1116 " GROUP BY operation HAVING MAX(num) ORDER BY num DESC", -1, &stmt, NULL);
1117 // clang-format on
1118 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid);
1119 }
1120 else
1121 // clang-format off
1123 "SELECT num, multi_priority, module, operation, enabled, 0, 0, multi_name"
1124 " FROM data.style_items"
1125 " WHERE styleid=?1 ORDER BY num DESC",
1126 -1, &stmt, NULL);
1127 // clang-format on
1128
1129 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
1130 while(sqlite3_step(stmt) == SQLITE_ROW)
1131 {
1132 if(strcmp((const char*)sqlite3_column_text(stmt, 3), "mask_manager") == 0) continue;
1133
1134 // name of current item of style
1135 char iname[512] = { 0 };
1136 dt_style_item_t *item = calloc(1, sizeof(dt_style_item_t));
1137
1138 if(sqlite3_column_type(stmt, 0) == SQLITE_NULL)
1139 item->num = -1;
1140 else
1141 item->num = sqlite3_column_int(stmt, 0);
1142
1143 item->multi_priority = sqlite3_column_int(stmt, 1);
1144
1145 item->selimg_num = -1;
1146 item->module_version = sqlite3_column_int(stmt, 2);
1147
1148 item->enabled = sqlite3_column_int(stmt, 4);
1149
1150 const char *multi_name = (const char *)sqlite3_column_text(stmt, 7);
1151 const gboolean has_multi_name = multi_name && *multi_name && (strcmp(multi_name, "0") != 0);
1152
1153 if(params)
1154 {
1155 // when we get the parameters we do not want to get the operation localized as this
1156 // is used to compare against the internal module name.
1157
1158 if(has_multi_name)
1159 g_snprintf(iname, sizeof(iname), "%s %s", sqlite3_column_text(stmt, 3), multi_name);
1160 else
1161 g_snprintf(iname, sizeof(iname), "%s", sqlite3_column_text(stmt, 3));
1162
1163 const unsigned char *op_blob = sqlite3_column_blob(stmt, 5);
1164 const int32_t op_len = sqlite3_column_bytes(stmt, 5);
1165 const unsigned char *bop_blob = sqlite3_column_blob(stmt, 6);
1166 const int32_t bop_len = sqlite3_column_bytes(stmt, 6);
1167 const int32_t bop_ver = sqlite3_column_int(stmt, 8);
1168
1169 item->params = malloc(op_len);
1170 item->params_size = op_len;
1171 memcpy(item->params, op_blob, op_len);
1172
1173 item->blendop_params = malloc(bop_len);
1174 item->blendop_params_size = bop_len;
1175 item->blendop_version = bop_ver;
1176 memcpy(item->blendop_params, bop_blob, bop_len);
1177 }
1178 else
1179 {
1180 const gchar *itname = dt_iop_get_localized_name((char *)sqlite3_column_text(stmt, 3));
1181
1182 if(has_multi_name)
1183 g_snprintf(iname, sizeof(iname), "%s %s", itname, multi_name);
1184 else
1185 g_snprintf(iname, sizeof(iname), "%s", itname);
1186
1187 item->params = NULL;
1188 item->blendop_params = NULL;
1189 item->params_size = 0;
1190 item->blendop_params_size = 0;
1191 item->blendop_version = 0;
1192 if(imgid != UNKNOWN_IMAGE && sqlite3_column_type(stmt, 5) != SQLITE_NULL)
1193 item->selimg_num = sqlite3_column_int(stmt, 5);
1194 }
1195 item->name = g_strdup(iname);
1196 item->operation = g_strdup((char *)sqlite3_column_text(stmt, 3));
1197 item->multi_name = g_strdup((char *)sqlite3_column_text(stmt, 7));
1198 item->iop_order = sqlite3_column_double(stmt, 8);
1199 result = g_list_prepend(result, item);
1200 }
1201 sqlite3_finalize(stmt);
1202 }
1203 return g_list_reverse(result); // list was built in reverse order, so un-reverse it
1204}
1205
1207{
1208 GList *items = dt_styles_get_item_list(name, FALSE, -1);
1209 if(IS_NULL_PTR(items)) return NULL;
1210
1211 GList *names = NULL;
1212 for(GList *items_iter = items; items_iter; items_iter = g_list_next(items_iter))
1213 {
1214 dt_style_item_t *item = (dt_style_item_t *)items_iter->data;
1215 names = g_list_prepend(names, g_strdup(item->name));
1216 }
1217 names = g_list_reverse(names); // list was built in reverse order, so un-reverse it
1218
1219 char *result = dt_util_glist_to_str("\n", names);
1220 g_list_free_full(names, dt_free_gpointer);
1221 names = NULL;
1222 g_list_free_full(items, dt_style_item_free);
1223 items = NULL;
1224 return result;
1225}
1226
1227GList *dt_styles_get_list(const char *filter)
1228{
1229 char filterstring[512] = { 0 };
1230 snprintf(filterstring, sizeof(filterstring), "%%%s%%", filter);
1232 {
1235 "SELECT name, description FROM data.styles WHERE name LIKE ?1 OR description LIKE ?1 ORDER BY name", -1,
1236 &_styles_get_list_stmt, NULL);
1237 }
1238 sqlite3_stmt *stmt = _styles_get_list_stmt;
1239 sqlite3_reset(stmt);
1240 sqlite3_clear_bindings(stmt);
1241 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, filterstring, -1, SQLITE_TRANSIENT);
1242 GList *result = NULL;
1243 while(sqlite3_step(stmt) == SQLITE_ROW)
1244 {
1245 const char *name = (const char *)sqlite3_column_text(stmt, 0);
1246 const char *description = (const char *)sqlite3_column_text(stmt, 1);
1247 dt_style_t *s = g_malloc(sizeof(dt_style_t));
1248 s->name = g_strdup(name);
1249 s->description = g_strdup(description);
1250 result = g_list_prepend(result, s);
1251 }
1252 return g_list_reverse(result); // list was built in reverse order, so un-reverse it
1253}
1254
1255static char *dt_style_encode(sqlite3_stmt *stmt, int row)
1256{
1257 const int32_t len = sqlite3_column_bytes(stmt, row);
1258 char *vparams = dt_exif_xmp_encode((const unsigned char *)sqlite3_column_blob(stmt, row), len, NULL);
1259 return vparams;
1260}
1261
1262void dt_styles_save_to_file(const char *style_name, const char *filedir, gboolean overwrite)
1263{
1264 char stylesdir[PATH_MAX] = { 0 };
1265 if(IS_NULL_PTR(filedir))
1266 {
1267 dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir));
1268 g_strlcat(stylesdir, "/styles", sizeof(stylesdir));
1269 g_mkdir_with_parents(stylesdir, 00755);
1270 filedir = stylesdir;
1271 }
1272
1273 int rc = 0;
1274 char stylename[PATH_MAX];
1275 sqlite3_stmt *stmt;
1276
1277 // generate filename based on name of style
1278 // convert all characters to underscore which are not allowed in filenames
1279 char *filename = g_strdup_printf("%s.dtstyle", style_name);
1280 g_strdelimit(filename, "/<>:\"\\|*?[]", '_');
1281 dt_concat_path_file(stylename, filedir, filename);
1282 dt_free(filename);
1283
1284 // check if file exists
1285 if(g_file_test(stylename, G_FILE_TEST_EXISTS) == TRUE)
1286 {
1287 if(overwrite)
1288 {
1289 if(g_unlink(stylename))
1290 {
1291 dt_control_log(_("failed to overwrite style file for %s"), style_name);
1292 return;
1293 }
1294 }
1295 else
1296 {
1297 dt_control_log(_("style file for %s exists"), style_name);
1298 return;
1299 }
1300 }
1301
1302 if(!dt_styles_exists(style_name)) return;
1303
1304 xmlTextWriterPtr writer = xmlNewTextWriterFilename(stylename, 0);
1305 if(IS_NULL_PTR(writer))
1306 {
1307 fprintf(stderr, "[dt_styles_save_to_file] Error creating the xml writer\n, path: %s", stylename);
1308 return;
1309 }
1310 rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
1311 if(rc < 0)
1312 {
1313 fprintf(stderr, "[dt_styles_save_to_file]: Error on encoding setting");
1314 return;
1315 }
1316 xmlTextWriterStartElement(writer, BAD_CAST "darktable_style");
1317 xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0");
1318
1319 xmlTextWriterStartElement(writer, BAD_CAST "info");
1320 xmlTextWriterWriteFormatElement(writer, BAD_CAST "name", "%s", style_name);
1321 xmlTextWriterWriteFormatElement(writer, BAD_CAST "description", "%s", dt_styles_get_description(style_name));
1322 GList *iop_list = dt_styles_module_order_list(style_name);
1323 if(iop_list)
1324 {
1325 char *iop_list_text = dt_ioppr_serialize_text_iop_order_list(iop_list);
1326 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iop_list", "%s", iop_list_text);
1327 dt_free(iop_list_text);
1328 g_list_free_full(iop_list, dt_free_gpointer);
1329 iop_list = NULL;
1330 }
1331 xmlTextWriterEndElement(writer);
1332
1333 xmlTextWriterStartElement(writer, BAD_CAST "style");
1334 // clang-format off
1336 "SELECT num, module, operation, op_params, enabled,"
1337 " blendop_params, blendop_version, multi_priority, multi_name"
1338 " FROM data.style_items"
1339 " WHERE styleid =?1",
1340 -1, &stmt, NULL);
1341 // clang-format on
1343 while(sqlite3_step(stmt) == SQLITE_ROW)
1344 {
1345 xmlTextWriterStartElement(writer, BAD_CAST "plugin");
1346 xmlTextWriterWriteFormatElement(writer, BAD_CAST "num", "%d", sqlite3_column_int(stmt, 0));
1347 xmlTextWriterWriteFormatElement(writer, BAD_CAST "module", "%d", sqlite3_column_int(stmt, 1));
1348 xmlTextWriterWriteFormatElement(writer, BAD_CAST "operation", "%s", sqlite3_column_text(stmt, 2));
1349 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_params", "%s", dt_style_encode(stmt, 3));
1350 xmlTextWriterWriteFormatElement(writer, BAD_CAST "enabled", "%d", sqlite3_column_int(stmt, 4));
1351 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_params", "%s", dt_style_encode(stmt, 5));
1352 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_version", "%d", sqlite3_column_int(stmt, 6));
1353 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_priority", "%d", sqlite3_column_int(stmt, 7));
1354 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_name", "%s", sqlite3_column_text(stmt, 8));
1355 xmlTextWriterEndElement(writer);
1356 }
1357 sqlite3_finalize(stmt);
1358 xmlTextWriterEndDocument(writer);
1359 xmlFreeTextWriter(writer);
1360}
1361
1363{
1364 StyleInfoData *info = g_new0(StyleInfoData, 1);
1365 info->name = g_string_new("");
1366 info->description = g_string_new("");
1367
1368 StyleData *data = g_new0(StyleData, 1);
1369 data->info = info;
1370 data->in_plugin = FALSE;
1371 data->plugins = NULL;
1372
1373 return data;
1374}
1375
1377{
1378 StylePluginData *plugin = g_new0(StylePluginData, 1);
1379 plugin->operation = g_string_new("");
1380 plugin->op_params = g_string_new("");
1381 plugin->blendop_params = g_string_new("");
1382 plugin->multi_name = g_string_new("");
1383 plugin->iop_order = -1.0;
1384 return plugin;
1385}
1386
1387static void dt_styles_style_data_free(StyleData *style, gboolean free_segments)
1388{
1389 g_string_free(style->info->name, free_segments);
1390 g_string_free(style->info->description, free_segments);
1391 g_list_free_full(style->info->iop_list, dt_free_gpointer);
1392 style->info->iop_list = NULL;
1393 g_list_free(style->plugins);
1394 style->plugins = NULL;
1395 dt_free(style);
1396}
1397
1398static void dt_styles_start_tag_handler(GMarkupParseContext *context, const gchar *element_name,
1399 const gchar **attribute_names, const gchar **attribute_values,
1400 gpointer user_data, GError **error)
1401{
1402 StyleData *style = user_data;
1403 const gchar *elt = g_markup_parse_context_get_element(context);
1404
1405 // We need to append the contents of any subtags to the content field
1406 // for this we need to know when we are inside the note-content tag
1407 if(g_ascii_strcasecmp(elt, "plugin") == 0)
1408 {
1409 style->in_plugin = TRUE;
1410 style->plugins = g_list_prepend(style->plugins, dt_styles_style_plugin_new());
1411 }
1412}
1413
1414static void dt_styles_end_tag_handler(GMarkupParseContext *context, const gchar *element_name,
1415 gpointer user_data, GError **error)
1416{
1417 StyleData *style = user_data;
1418 const gchar *elt = g_markup_parse_context_get_element(context);
1419
1420 // We need to append the contents of any subtags to the content field
1421 // for this we need to know when we are inside the note-content tag
1422 if(g_ascii_strcasecmp(elt, "plugin") == 0)
1423 {
1424 style->in_plugin = FALSE;
1425 }
1426}
1427
1428static void dt_styles_style_text_handler(GMarkupParseContext *context, const gchar *text, gsize text_len,
1429 gpointer user_data, GError **error)
1430{
1431 StyleData *style = user_data;
1432 const gchar *elt = g_markup_parse_context_get_element(context);
1433
1434 if(g_ascii_strcasecmp(elt, "name") == 0)
1435 {
1436 g_string_append_len(style->info->name, text, text_len);
1437 }
1438 else if(g_ascii_strcasecmp(elt, "description") == 0)
1439 {
1440 g_string_append_len(style->info->description, text, text_len);
1441 }
1442 else if(g_ascii_strcasecmp(elt, "iop_list") == 0)
1443 {
1445 }
1446 else if(style->in_plugin)
1447 {
1448 StylePluginData *plug = style->plugins->data;
1449 if(g_ascii_strcasecmp(elt, "operation") == 0)
1450 {
1451 g_string_append_len(plug->operation, text, text_len);
1452 }
1453 else if(g_ascii_strcasecmp(elt, "op_params") == 0)
1454 {
1455 g_string_append_len(plug->op_params, text, text_len);
1456 }
1457 else if(g_ascii_strcasecmp(elt, "blendop_params") == 0)
1458 {
1459 g_string_append_len(plug->blendop_params, text, text_len);
1460 }
1461 else if(g_ascii_strcasecmp(elt, "blendop_version") == 0)
1462 {
1463 plug->blendop_version = atoi(text);
1464 }
1465 else if(g_ascii_strcasecmp(elt, "multi_priority") == 0)
1466 {
1467 plug->multi_priority = atoi(text);
1468 }
1469 else if(g_ascii_strcasecmp(elt, "multi_name") == 0)
1470 {
1471 g_string_append_len(plug->multi_name, text, text_len);
1472 }
1473 else if(g_ascii_strcasecmp(elt, "num") == 0)
1474 {
1475 plug->num = atoi(text);
1476 }
1477 else if(g_ascii_strcasecmp(elt, "module") == 0)
1478 {
1479 plug->module = atoi(text);
1480 }
1481 else if(g_ascii_strcasecmp(elt, "enabled") == 0)
1482 {
1483 plug->enabled = atoi(text);
1484 }
1485 else if(g_ascii_strcasecmp(elt, "iop_order") == 0)
1486 {
1487 plug->iop_order = atof(text);
1488 }
1489 }
1490}
1491
1492static GMarkupParser dt_style_parser = {
1493 dt_styles_start_tag_handler, // Start element handler
1494 dt_styles_end_tag_handler, // End element handler
1495 dt_styles_style_text_handler, // Text element handler
1496 NULL, // Passthrough handler
1497 NULL // Error handler
1498};
1499
1500static void dt_style_plugin_save(StylePluginData *plugin, gpointer styleId)
1501{
1502 int id = GPOINTER_TO_INT(styleId);
1503 sqlite3_stmt *stmt;
1504 // clang-format off
1506 "INSERT INTO data.style_items "
1507 " (styleid, num, module, operation, op_params, enabled, blendop_params,"
1508 " blendop_version, multi_priority, multi_name)"
1509 " VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)",
1510 -1, &stmt, NULL);
1511 // clang-format on
1512 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
1513 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, plugin->num);
1514 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, plugin->module);
1515 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, plugin->operation->str, plugin->operation->len, SQLITE_TRANSIENT);
1516 //
1517 const char *param_c = plugin->op_params->str;
1518 const int param_c_len = strlen(param_c);
1519 int params_len = 0;
1520 unsigned char *params = dt_exif_xmp_decode(param_c, param_c_len, &params_len);
1521 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 5, params, params_len, SQLITE_TRANSIENT);
1522 //
1523 DT_DEBUG_SQLITE3_BIND_INT(stmt, 6, plugin->enabled);
1524
1525 /* decode and store blendop params */
1526 int blendop_params_len = 0;
1527 unsigned char *blendop_params = dt_exif_xmp_decode(
1528 plugin->blendop_params->str, strlen(plugin->blendop_params->str), &blendop_params_len);
1529 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 7, blendop_params, blendop_params_len, SQLITE_TRANSIENT);
1530
1532
1533 DT_DEBUG_SQLITE3_BIND_INT(stmt, 9, plugin->multi_priority);
1534 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 10, plugin->multi_name->str, plugin->multi_name->len, SQLITE_TRANSIENT);
1535
1536 sqlite3_step(stmt);
1537 sqlite3_finalize(stmt);
1538 dt_free(params);
1539}
1540
1541static void dt_style_save(StyleData *style)
1542{
1543 int id = 0;
1544 if(IS_NULL_PTR(style)) return;
1545
1546 /* first create the style header */
1547 if(!dt_styles_create_style_header(style->info->name->str, style->info->description->str, style->info->iop_list)) return;
1548
1549 if((id = dt_styles_get_id_by_name(style->info->name->str)) != 0)
1550 {
1551 g_list_foreach(style->plugins, (GFunc)dt_style_plugin_save, GINT_TO_POINTER(id));
1552 dt_control_log(_("style %s was successfully imported"), style->info->name->str);
1553 }
1554}
1555
1556void dt_styles_import_from_file(const char *style_path)
1557{
1558 FILE *style_file;
1559 StyleData *style;
1560 GMarkupParseContext *parser;
1561 gchar buf[1024];
1562
1563 style = dt_styles_style_data_new();
1564 parser = g_markup_parse_context_new(&dt_style_parser, 0, style, NULL);
1565
1566 if((style_file = g_fopen(style_path, "r")))
1567 {
1568
1569 while(!feof(style_file))
1570 {
1571 const size_t num_read = fread(buf, sizeof(gchar), sizeof(buf), style_file);
1572
1573 if(num_read == 0)
1574 {
1575 break;
1576 }
1577 else if(num_read == -1)
1578 {
1579 // FIXME: ferror?
1580 // ERROR !
1581 break;
1582 }
1583
1584 if(!g_markup_parse_context_parse(parser, buf, num_read, NULL))
1585 {
1586 g_markup_parse_context_free(parser);
1588 fclose(style_file);
1589 return;
1590 }
1591 }
1592 }
1593 else
1594 {
1595 // Failed to open file, clean up.
1596 dt_control_log(_("could not read file `%s'"), style_path);
1597 g_markup_parse_context_free(parser);
1599 return;
1600 }
1601
1602 if(!g_markup_parse_context_end_parse(parser, NULL))
1603 {
1604 g_markup_parse_context_free(parser);
1606 fclose(style_file);
1607 return;
1608 }
1609 g_markup_parse_context_free(parser);
1610 // save data
1611 dt_style_save(style);
1612 //
1614 fclose(style_file);
1615
1617}
1618
1620{
1621 sqlite3_stmt *stmt;
1622 int id = 0;
1623 gchar *description = NULL;
1624 if((id = dt_styles_get_id_by_name(name)) != 0)
1625 {
1626 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT description FROM data.styles WHERE id=?1",
1627 -1, &stmt, NULL);
1628 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id);
1629 sqlite3_step(stmt);
1630 description = (char *)sqlite3_column_text(stmt, 0);
1631 if(description) description = g_strdup(description);
1632 sqlite3_finalize(stmt);
1633 }
1634 return description;
1635}
1636
1637int32_t dt_styles_get_id_by_name(const char *name)
1638{
1639 int id = 0;
1640 sqlite3_stmt *stmt;
1642 "SELECT id FROM data.styles WHERE name=?1 ORDER BY id DESC LIMIT 1", -1, &stmt,
1643 NULL);
1644 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, -1, SQLITE_TRANSIENT);
1645 if(sqlite3_step(stmt) == SQLITE_ROW)
1646 {
1647 id = sqlite3_column_int(stmt, 0);
1648 }
1649 sqlite3_finalize(stmt);
1650 return id;
1651}
1652
1654{
1655 sqlite3_stmt *stmt;
1657 "SELECT name, description FROM data.styles WHERE name = ?1", -1, &stmt, NULL);
1658 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, -1, SQLITE_STATIC);
1659 if(sqlite3_step(stmt) == SQLITE_ROW)
1660 {
1661 const char *style_name = (const char *)sqlite3_column_text(stmt, 0);
1662 const char *description = (const char *)sqlite3_column_text(stmt, 1);
1663 dt_style_t *s = g_malloc(sizeof(dt_style_t));
1664 s->name = g_strdup(style_name);
1665 s->description = g_strdup(description);
1666 sqlite3_finalize(stmt);
1667 return s;
1668 }
1669 else
1670 {
1671
1672 sqlite3_finalize(stmt);
1673 return NULL;
1674 }
1675}
1676
1678{
1680 {
1681 sqlite3_finalize(_styles_get_list_stmt);
1682 _styles_get_list_stmt = NULL;
1683 }
1685 {
1686 sqlite3_finalize(_styles_apply_items_stmt);
1688 }
1689}
1690
1691#undef DT_IOP_ORDER_INFO
1692// clang-format off
1693// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1694// vim: shiftwidth=2 expandtab tabstop=2 cindent
1695// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1696// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:160
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int dt_develop_blend_version(void)
Definition blend.c:1630
int dt_develop_blend_legacy_params(dt_iop_module_t *module, const void *const old_params, const int old_version, void *new_params, const int new_version, const int length)
Definition blend.c:1694
static const int row
char * name
int dt_conf_get_bool(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:761
void dt_concat_path_file(char destination[PATH_MAX], const char path[PATH_MAX], const char *const file)
Definition darktable.c:1889
darktable_t darktable
Definition darktable.c:181
#define UNKNOWN_IMAGE
Definition darktable.h:182
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
#define PATH_MAX
Definition darktable.h:1062
#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_EXEC(a, b, c, d, e)
Definition debug.h:99
#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
int dt_history_merge_module_into_history(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_src)
Merge a single module instance into a destination history.
int dt_dev_replace_history_on_image(dt_develop_t *dev_src, const int32_t dest_imgid, const gboolean reload_defaults, const char *msg)
Replace an image history with the content of dev_src.
gboolean dt_dev_history_item_update_from_params(dt_develop_t *dev, dt_dev_history_item_t *hist, dt_iop_module_t *module, const gboolean enabled, const void *params, const int32_t params_size, const dt_develop_blend_params_t *blend_params, GList *forms)
void dt_dev_history_free_history(dt_develop_t *dev)
Free the whole history list attached to dev->history.
void dt_dev_history_compress_ext(dt_develop_t *dev, gboolean write_history)
Variant of history compression that optionally skips DB writeback.
void dt_dev_pop_history_items_ext(dt_develop_t *dev)
Apply history items to module params up to dev->history_end.
int dt_dev_merge_history_into_image(dt_develop_t *dev_src, int32_t dest_imgid, const GList *mod_list, gboolean merge_iop_order, const dt_history_merge_strategy_t mode, const gboolean paste_instances, const char *source_label, dt_hm_batch_state_t *batch)
Merge a list of modules into a destination image history via dt_history_merge().
gboolean dt_dev_init_default_history(dt_develop_t *dev, const int32_t imgid, gboolean apply_auto_presets)
Initialize module defaults and insert required default modules.
void dt_dev_set_history_end_ext(struct dt_develop_t *dev, const uint32_t index)
Set the history end index (GUI perspective).
Definition develop.c:1665
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
Definition develop.c:1659
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:188
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:128
dt_dev_image_storage_t dt_dev_ensure_image_storage(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:847
#define dt_pthread_rwlock_wrlock
Definition dtpthread.h:394
#define dt_pthread_rwlock_unlock
Definition dtpthread.h:392
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
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
const dt_collection_sort_t items[]
Definition filter.c:95
void dt_gui_styles_dialog_new(int32_t imgid)
gboolean dt_history_style_on_image(const int32_t imgid, const char *name, const gboolean duplicate)
dt_history_merge_strategy_t
@ DT_HISTORY_MERGE_REPLACE
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1561
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:2999
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
Definition imageop.c:1550
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
Definition imageop.c:3081
GList * dt_ioppr_get_iop_order_list(int32_t imgid, gboolean sorted)
Load the order list for an image from the DB.
Definition iop_order.c:1096
int dt_ioppr_get_iop_order(GList *iop_order_list, const char *op_name, const int multi_priority)
Return the iop_order for a given operation/instance pair.
Definition iop_order.c:868
void dt_ioppr_update_for_style_items(dt_develop_t *dev, GList *st_items, gboolean append)
Update dev->iop_order_list with modules referenced by style items.
Definition iop_order.c:1747
void dt_ioppr_set_default_iop_order(dt_develop_t *dev, const int32_t imgid)
Set dev->iop_order_list to the default order for a given image.
Definition iop_order.c:1325
void dt_ioppr_resync_pipeline(dt_develop_t *dev, const int32_t imgid, const char *msg, gboolean check_duplicates)
Resynchronize pipeline order and related structures.
Definition iop_order.c:1263
char * dt_ioppr_serialize_text_iop_order_list(GList *iop_order_list)
Serialize an order list to a text representation.
Definition iop_order.c:2533
GList * dt_ioppr_deserialize_text_iop_order_list(const char *buf)
Deserialize an order list from a text representation.
Definition iop_order.c:2588
float *const restrict const size_t k
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
Definition signal.h:147
static StyleData * dt_styles_style_data_new()
void dt_styles_cleanup(void)
gboolean dt_styles_exists(const char *name)
static void dt_styles_end_tag_handler(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
GList * dt_styles_get_item_list(const char *name, gboolean params, int32_t imgid)
static GList * _dt_styles_build_mod_list_from_history(dt_develop_t *dev, GHashTable *style_ids)
static gboolean _dt_styles_apply_item_to_module(dt_iop_module_t *module, const dt_style_item_t *style_item)
gchar * dt_styles_get_description(const char *name)
static int _styles_rebuild_history_from_items(dt_develop_t *dev_src, GList *applied_items)
void dt_styles_apply_to_image(const char *name, const gboolean duplicate, const int32_t imgid)
char * dt_styles_get_item_list_as_string(const char *name)
static void dt_style_plugin_save(StylePluginData *plugin, gpointer styleId)
static const char * _dt_styles_normalize_multi_name(const char *multi_name)
static char * dt_style_encode(sqlite3_stmt *stmt, int row)
void dt_styles_update(const char *name, const char *newname, const char *newdescription, GList *filter, const int32_t imgid, GList *update, const gboolean copy_iop_order, const gboolean update_iop_order)
void dt_multiple_styles_apply_to_list(GList *styles, const GList *list, gboolean duplicate)
void dt_styles_apply_style_item(dt_develop_t *dev, dt_style_item_t *style_item)
static void dt_styles_style_data_free(StyleData *style, gboolean free_segments)
int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid, const dt_history_merge_strategy_t mode, dt_hm_batch_state_t *batch)
void dt_style_item_free(gpointer data)
static sqlite3_stmt * _styles_apply_items_stmt
void dt_styles_delete_by_name_adv(const char *name, const gboolean raise)
void dt_styles_save_to_file(const char *style_name, const char *filedir, gboolean overwrite)
void dt_styles_create_from_style(const char *name, const char *newname, const char *description, GList *filter, const int32_t imgid, GList *update, const gboolean copy_iop_order, const gboolean update_iop_order)
static GList * _styles_collect_applied_items(dt_develop_t *dev_src, GList *si_list, GHashTable *style_ids)
static void _dt_style_update_iop_order(const gchar *name, const int id, const int32_t imgid, const gboolean copy_iop_order, const gboolean update_iop_order)
void dt_style_free(gpointer data)
static void dt_styles_style_text_handler(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
void dt_styles_delete_by_name(const char *name)
static void _styles_sync_pipeline_from_items(dt_develop_t *dev_src, GList *applied_items, const gboolean has_iop_list)
static void _dt_style_update_from_image(int id, int32_t imgid, GList *filter, GList *update)
static StylePluginData * dt_styles_style_plugin_new()
dt_style_t * dt_styles_get_by_name(const char *name)
int32_t dt_styles_get_id_by_name(const char *name)
static void dt_style_save(StyleData *style)
void dt_styles_create_from_list(const GList *list)
static GMarkupParser dt_style_parser
void dt_styles_import_from_file(const char *style_path)
static sqlite3_stmt * _styles_get_list_stmt
static dt_iop_module_t * _dt_styles_get_or_create_module_instance(dt_develop_t *dev, const dt_style_item_t *style_item)
static int _styles_init_source_dev(dt_develop_t *dev_src, const char *name, const int32_t imgid, gboolean *has_iop_list)
GList * dt_styles_module_order_list(const char *name)
static void _dt_styles_tmp_module_free(dt_iop_module_t *module)
#define DT_IOP_ORDER_INFO
static void _dt_style_cleanup_multi_instance(int id)
gboolean dt_styles_has_module_order(const char *name)
gboolean dt_styles_create_from_image(const char *name, const char *description, const int32_t imgid, GList *filter, gboolean copy_iop_order)
GList * dt_styles_get_list(const char *filter)
static GList * _dt_styles_get_apply_items(const int style_id)
static gboolean dt_styles_create_style_header(const char *name, const char *description, GList *iop_list)
static int _styles_prepare_source_dev(dt_develop_t *dev_src, const char *name, const int style_id, const int32_t imgid, GList **out_si_list, GHashTable **out_style_ids, GList **out_mod_list)
static dt_iop_module_t * _dt_styles_tmp_module_from_style_item(dt_develop_t *dev, const dt_style_item_t *style_item)
static void dt_styles_start_tag_handler(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error)
StyleInfoData * info
gboolean in_plugin
GString * description
int GString * operation
struct dt_undo_t * undo
Definition darktable.h:787
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_iop_module_t *gboolean enabled
Definition dev_history.h:50
GList * iop_order_list
Definition develop.h:285
GList * iop
Definition develop.h:279
dt_pthread_rwlock_t history_mutex
Definition develop.h:263
GList * history
Definition develop.h:275
dt_iop_params_t * default_params
Definition imageop.h:307
struct dt_develop_blend_params_t * blend_params
Definition imageop.h:316
char multi_name[128]
Definition imageop.h:363
GModule *dt_dev_operation_t op
Definition imageop.h:256
gboolean enabled
Definition imageop.h:298
dt_iop_module_so_t * so
Definition imageop.h:359
struct dt_develop_blend_params_t * default_blendop_params
Definition imageop.h:316
int32_t params_size
Definition imageop.h:309
dt_iop_params_t * params
Definition imageop.h:307
dt_iop_params_t * params
dt_develop_blend_params_t * blendop_params
int32_t blendop_params_size
gchar * description
gchar * name
void dt_undo_end_group(dt_undo_t *self)
Definition undo.c:149
void dt_undo_start_group(dt_undo_t *self, dt_undo_type_t type)
Definition undo.c:134
@ DT_UNDO_LT_HISTORY
Definition undo.h:48
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)
Definition utility.c:166