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/utility.h"
48#include "common/conf.h"
49#include <glib/gstdio.h>
51#include "common/styles.h"
52#include "history/notify.h"
53#include "system/macros.h"
54#include "system/mem_alloc.h"
55#include "common/logging.h"
56#include "common/paths.h"
57#include "common/image.h"
58#include "metadata/exif.h"
60#include "history/history.h"
62#include "develop/iop_order.h"
63#include "metadata/tags.h"
64
65#include "develop/develop.h"
66#include "develop/dev_history.h"
67
68#include <libxml/encoding.h>
69#include <libxml/xmlwriter.h>
70
71#include <glib.h>
72#include <stdio.h>
73#include <string.h>
74
75#define DT_IOP_ORDER_INFO (dt_get_debug_flags() & DT_DEBUG_IOPORDER)
76
77typedef struct
78{
79 GString *name;
80 GString *description;
81 GList *iop_list;
83
84typedef struct
85{
86 int num;
87 int module;
88 GString *operation;
89 GString *op_params;
93 GString *multi_name;
95 double iop_order;
97
98typedef struct
99{
101 GList *plugins;
102 gboolean in_plugin;
103} StyleData;
104
105void dt_style_free(gpointer data)
106{
107 dt_style_t *style = (dt_style_t *)data;
108 dt_free(style->name);
109 dt_free(style->description);
110 style->name = NULL;
111 style->description = NULL;
112 dt_free(style);
113}
114
115void dt_style_item_free(gpointer data)
116{
117 dt_style_item_t *item = (dt_style_item_t *)data;
118 dt_free(item->name);
119 dt_free(item->operation);
120 dt_free(item->multi_name);
121 dt_free(item->params);
122 dt_free(item->blendop_params);
123 item->name = NULL;
124 item->operation = NULL;
125 item->multi_name = NULL;
126 item->params = NULL;
127 item->blendop_params = NULL;
128 dt_free(item);
129}
130
131int32_t dt_styles_get_id_by_name(const char *name);
132
133gboolean dt_styles_exists(const char *name)
134{
135 if(name)
136 return (dt_styles_get_id_by_name(name)) != 0 ? TRUE : FALSE;
137 return FALSE;
138}
139
140gboolean dt_styles_has_module_order(const char *name)
141{
142 char *iop_list_txt = dt_style_repository_get_iop_list(name);
143 const gboolean has_iop_list = (iop_list_txt != NULL);
144 dt_free(iop_list_txt);
145 return has_iop_list;
146}
147
149{
150 GList *iop_list = NULL;
151 char *iop_list_txt = dt_style_repository_get_iop_list(name);
152 if(iop_list_txt)
153 {
154 iop_list = dt_ioppr_deserialize_text_iop_order_list(iop_list_txt);
155 // style saved before newer modules existed: place them so applying it
156 // does not mis-order those modules
157 if(iop_list) iop_list = dt_ioppr_insert_missing_modules(iop_list);
158 dt_free(iop_list_txt);
159 }
160 return iop_list;
161}
162
163static gboolean dt_styles_create_style_header(const char *name, const char *description, GList *iop_list)
164{
166 {
167 dt_history_message(_("style with name '%s' already exists"), name);
168 return FALSE;
169 }
170
171 char *iop_list_txt = iop_list ? dt_ioppr_serialize_text_iop_order_list(iop_list) : NULL;
173 dt_free(iop_list_txt);
174 return TRUE;
175}
176
177static void _dt_style_update_from_image(int id, int32_t imgid, GList *filter, GList *update)
178{
179 if(update && imgid != UNKNOWN_IMAGE)
180 {
181 GList *list = filter;
182 GList *upd = update;
183
184 do
185 {
186 const int history_num = GPOINTER_TO_INT(upd->data);
187 const int item_num = GPOINTER_TO_INT(list->data);
188
189 // included and update set, we then need to update the corresponding style item
190 if(history_num != -1 && item_num != -1)
191 dt_style_repository_update_item_from_history(id, item_num, imgid, history_num);
192 // update only, so we want to insert the new style item
193 else if(history_num != -1)
194 dt_style_repository_append_item_from_history(id, imgid, history_num);
195
196 list = g_list_next(list);
197 upd = g_list_next(upd);
198 } while(list);
199 }
200}
201
202static void _dt_style_update_iop_order(const gchar *name, const int id, const int32_t imgid,
203 const gboolean copy_iop_order, const gboolean update_iop_order)
204{
205 GList *iop_list = dt_styles_module_order_list(name);
206
207 // if we update or if the style does not contains an order then the
208 // copy must be done using the imgid iop-order.
209
210 if(update_iop_order || IS_NULL_PTR(iop_list))
211 iop_list = dt_ioppr_get_iop_order_list(imgid, FALSE);
212
213 gchar *iop_list_txt = dt_ioppr_serialize_text_iop_order_list(iop_list);
214
215 // copy from style name to style id, or clear the order outright
216 dt_style_repository_set_iop_list(id, (copy_iop_order || update_iop_order) ? iop_list_txt : NULL);
217
218 g_list_free_full(iop_list, dt_free_gpointer);
219 iop_list = NULL;
220 dt_free(iop_list_txt);
221}
222
223void dt_styles_update(const char *name, const char *newname, const char *newdescription, GList *filter,
224 const int32_t imgid, GList *update,
225 const gboolean copy_iop_order, const gboolean update_iop_order)
226{
227 const int id = dt_styles_get_id_by_name(name);
228 if(id == 0) return;
229
230 gchar *desc = dt_styles_get_description(name);
231
232 if((g_strcmp0(name, newname)) || (g_strcmp0(desc, newdescription)))
233 dt_style_repository_update_header(id, newname, newdescription);
234
235 if(filter)
237
238 _dt_style_update_from_image(id, imgid, filter, update);
239
240 _dt_style_update_iop_order(name, id, imgid, copy_iop_order, update_iop_order);
241
242 if(!copy_iop_order && !update_iop_order)
243 {
244 // Without a stored module order, style items are self-contained and can use compact priorities.
246 }
247
248 /* backup style to disk */
249 dt_styles_save_to_file(newname, NULL, TRUE);
250
252
253 dt_free(desc);
254}
255
256void dt_styles_create_from_style(const char *name, const char *newname, const char *description,
257 GList *filter, const int32_t imgid, GList *update,
258 const gboolean copy_iop_order, const gboolean update_iop_order)
259{
260 int id = 0;
261
262 const int oldid = dt_styles_get_id_by_name(name);
263 if(oldid == 0) return;
264
265 /* create the style header */
266 if(!dt_styles_create_style_header(newname, description, NULL)) return;
267
268 if((id = dt_styles_get_id_by_name(newname)) != 0)
269 {
271
272 /* insert items from imgid if defined */
273
274 _dt_style_update_from_image(id, imgid, filter, update);
275
276 _dt_style_update_iop_order(name, id, imgid, copy_iop_order, update_iop_order);
277
278 if(!copy_iop_order && !update_iop_order)
279 {
280 // Without a stored module order, style items are self-contained and can use compact priorities.
282 }
283
284 /* backup style to disk */
285 dt_styles_save_to_file(newname, NULL, FALSE);
286
287 dt_history_message(_("style named '%s' successfully created"), newname);
289 }
290}
291
292gboolean dt_styles_create_from_image(const char *name, const char *description,
293 const int32_t imgid, GList *filter, gboolean copy_iop_order)
294{
295 int id = 0;
296
297 GList *iop_list = NULL;
298 if(copy_iop_order)
299 {
300 iop_list = dt_ioppr_get_iop_order_list(imgid, FALSE);
301 }
302
303 /* first create the style header */
304 if(!dt_styles_create_style_header(name, description, iop_list)) return FALSE;
305
306 g_list_free_full(iop_list, dt_free_gpointer);
307 iop_list = NULL;
308
309 if((id = dt_styles_get_id_by_name(name)) != 0)
310 {
311 /* create the style_items from source image history stack */
313
314 if(!copy_iop_order)
315 {
316 // A style without module order cannot use sparse image priorities, so compact them locally.
318 }
319
320 /* backup style to disk */
322
324 return TRUE;
325 }
326 return FALSE;
327}
328
329void dt_multiple_styles_apply_to_list(GList *styles, const GList *list, gboolean duplicate)
330{
331 /* write current history changes so nothing gets lost,
332 do that only in the darkroom as there is nothing to be saved
333 when in the lighttable (and it would write over current history stack) */
334
335 if(IS_NULL_PTR(styles) && !list)
336 {
337 dt_history_message(_("no images nor styles selected!"));
338 return;
339 }
340 else if(!styles)
341 {
342 dt_history_message(_("no styles selected!"));
343 return;
344 }
345 else if(!list)
346 {
347 dt_history_message(_("no image selected!"));
348 return;
349 }
350
351 /* for each selected image apply style */
353 for(const GList *l = list; l; l = g_list_next(l))
354 {
355 const int32_t imgid = GPOINTER_TO_INT(l->data);
356 for(GList *style = styles; style; style = g_list_next(style))
357 {
358 dt_history_style_on_image(imgid, (char *)style->data, duplicate);
359 }
360 }
362
363 const guint styles_cnt = g_list_length(styles);
364 dt_history_message(ngettext("style successfully applied!", "styles successfully applied!", styles_cnt));
365}
366
367static const char *_dt_styles_normalize_multi_name(const char *multi_name)
368{
369 if(IS_NULL_PTR(multi_name) || !*multi_name || !strcmp(multi_name, "0")) return "";
370 return multi_name;
371}
372
373static gboolean _dt_styles_apply_item_to_module(dt_iop_module_t *module, const dt_style_item_t *style_item)
374{
375 module->enabled = style_item->enabled;
376
377 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
378 if(*multi_name)
379 g_strlcpy(module->multi_name, multi_name, sizeof(module->multi_name));
380 else
381 module->multi_name[0] = '\0';
382
383 if(style_item->blendop_params && (style_item->blendop_version == dt_develop_blend_version())
384 && (style_item->blendop_params_size == sizeof(dt_develop_blend_params_t)))
385 {
386 memcpy(module->blend_params, style_item->blendop_params, sizeof(dt_develop_blend_params_t));
387 }
388 else if(style_item->blendop_params
389 && dt_develop_blend_legacy_params(module, style_item->blendop_params, style_item->blendop_version,
391 style_item->blendop_params_size)
392 == 0)
393 {
394 // do nothing
395 }
396 else if(module->default_blendop_params)
397 {
398 memcpy(module->blend_params, module->default_blendop_params, sizeof(dt_develop_blend_params_t));
399 }
400
401 gboolean ok = TRUE;
402 if(module->version() != style_item->module_version || module->params_size != style_item->params_size
403 || strcmp(style_item->operation, module->op))
404 {
405 if(!module->legacy_params
406 || module->legacy_params(module, style_item->params, labs(style_item->module_version), module->params,
407 labs(module->version())))
408 {
409 fprintf(stderr, "[dt_styles_apply] module `%s' version mismatch: history is %d, dt %d.\n", module->op,
410 style_item->module_version, module->version());
411 dt_history_message(_("module `%s' version mismatch: %d != %d"), module->op, module->version(),
412 style_item->module_version);
413 ok = FALSE;
414 }
415 }
416 else
417 {
418 memcpy(module->params, style_item->params, module->params_size);
419 }
420
421 if(ok && !strcmp(module->op, "flip") && module->enabled == 0 && labs(style_item->module_version) == 1)
422 {
423 memcpy(module->params, module->default_params, module->params_size);
424 module->enabled = 1;
425 }
426
427 return ok;
428}
429
431{
432 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
433 dt_iop_module_t *module = dt_dev_get_module_instance(dev, style_item->operation, multi_name,
434 style_item->multi_priority);
435 if(module) return module;
436
437 module = dt_dev_create_module_instance(dev, style_item->operation, multi_name, style_item->multi_priority, FALSE);
438 if(module) module->iop_order = style_item->iop_order;
439 return module;
440}
441
443{
444 dt_iop_module_t *mod_src = dt_iop_get_module_by_op_priority(dev->iop, style_item->operation, -1);
445 if(IS_NULL_PTR(mod_src)) return NULL;
446
447 dt_iop_module_t *module = (dt_iop_module_t *)calloc(1, sizeof(dt_iop_module_t));
448 if(dt_iop_load_module(module, mod_src->so, dev))
449 {
450 fprintf(stderr, "[dt_styles_apply] can't load module %s %s\n", style_item->operation,
451 style_item->multi_name ? style_item->multi_name : "(null)");
452 dt_free(module);
453 return NULL;
454 }
455
456 module->instance = mod_src->instance;
457 module->multi_priority = style_item->multi_priority;
458 module->iop_order = style_item->iop_order;
459
460 if(!_dt_styles_apply_item_to_module(module, style_item))
461 {
462 dt_iop_cleanup_module(module);
463 dt_free(module);
464 return NULL;
465 }
466
467 return module;
468}
469
470static void _prepend_apply_item(void *user_data, const int num, const int multi_priority,
471 const int module_version, const char *operation, const int enabled,
472 const void *params, const int32_t params_size,
473 const void *blendop_params, const int32_t blendop_params_size,
474 const int blendop_version, const char *multi_name,
475 const int selimg_num, const double iop_order)
476{
477 GList **si_list = (GList **)user_data;
478 dt_style_item_t *style_item = (dt_style_item_t *)malloc(sizeof(dt_style_item_t));
479
480 style_item->num = num;
481 style_item->selimg_num = selimg_num;
482 style_item->enabled = enabled;
483 style_item->multi_priority = multi_priority;
484 style_item->name = NULL;
485 style_item->operation = g_strdup(operation);
486 style_item->multi_name = g_strdup(multi_name);
487 style_item->module_version = module_version;
488 style_item->blendop_version = blendop_version;
489 style_item->params_size = params_size;
490 style_item->params = (void *)malloc(params_size);
491 memcpy(style_item->params, params, params_size);
492 style_item->blendop_params_size = blendop_params_size;
493 style_item->blendop_params = (void *)malloc(blendop_params_size);
494 memcpy(style_item->blendop_params, blendop_params, blendop_params_size);
495 style_item->iop_order = iop_order;
496
497 *si_list = g_list_prepend(*si_list, style_item);
498}
499
500static GList *_dt_styles_get_apply_items(const int style_id)
501{
502 GList *si_list = NULL;
504 return g_list_reverse(si_list); // list was built in reverse order, so un-reverse it
505}
506
507static GList *_dt_styles_build_mod_list_from_history(dt_develop_t *dev, GHashTable *style_ids)
508{
509 GList *mod_list = NULL;
510 for(GList *h = g_list_first(dev->history); h; h = g_list_next(h))
511 {
513 if(!hist || !hist->module) continue;
514 char *id_str = g_strdup_printf("%s|%s", hist->op_name, hist->multi_name);
515 const gboolean keep = g_hash_table_contains(style_ids, id_str);
516 dt_free(id_str);
517 if(!keep) continue;
518
519 if(!g_list_find(mod_list, hist->module))
520 mod_list = g_list_append(mod_list, hist->module);
521 }
522 return mod_list;
523}
524
526{
527 if(IS_NULL_PTR(module)) return;
528 dt_iop_cleanup_module(module);
529 dt_free(module);
530}
531
532static int _styles_init_source_dev(dt_develop_t *dev_src, const char *name, const int32_t imgid,
533 gboolean *has_iop_list)
534{
535 dt_dev_init(dev_src, FALSE);
536 if(dt_dev_ensure_image_storage(dev_src, imgid)) return 1;
537
538 *has_iop_list = FALSE;
539 dt_ioppr_set_default_iop_order(dev_src, imgid);
540 dt_dev_init_default_history(dev_src, imgid, FALSE);
541
542 // If the style has a stored iop-order list, apply it to the temporary pipeline
543 GList *iop_list = dt_styles_module_order_list(name);
544 if(iop_list)
545 {
546 g_list_free_full(dev_src->iop_order_list, dt_free_gpointer);
547 dev_src->iop_order_list = iop_list;
548 *has_iop_list = TRUE;
549 }
550
551 return 0;
552}
553
554static GList *_styles_collect_applied_items(dt_develop_t *dev_src, GList *si_list, GHashTable *style_ids)
555{
556 GList *applied_items = NULL;
557
558 for(GList *l = si_list; l; l = g_list_next(l))
559 {
560 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
561 dt_iop_module_t *module = _dt_styles_get_or_create_module_instance(dev_src, style_item);
562 if(IS_NULL_PTR(module)) continue;
563
564 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
565 module->multi_priority = style_item->multi_priority;
566 g_strlcpy(module->multi_name, multi_name, sizeof(module->multi_name));
567
568 if(!_dt_styles_apply_item_to_module(module, style_item)) continue;
569
570 applied_items = g_list_append(applied_items, style_item);
571 g_hash_table_add(style_ids, g_strdup_printf("%s|%s", style_item->operation, multi_name));
572 }
573
574 return applied_items;
575}
576
577static void _styles_sync_pipeline_from_items(dt_develop_t *dev_src, GList *applied_items,
578 const gboolean has_iop_list)
579{
580 if(!has_iop_list) dt_ioppr_update_for_style_items(dev_src, applied_items, FALSE);
581
582 for(GList *l = applied_items; l; l = g_list_next(l))
583 {
584 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
585 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
586 dt_iop_module_t *module
587 = dt_dev_get_module_instance(dev_src, style_item->operation, multi_name, style_item->multi_priority);
588 if(!IS_NULL_PTR(module))
589 {
590 if(has_iop_list)
591 style_item->iop_order = dt_ioppr_get_iop_order(dev_src->iop_order_list, style_item->operation,
592 style_item->multi_priority);
593 module->multi_priority = style_item->multi_priority;
594 module->iop_order = style_item->iop_order;
595 }
596 }
597
598 dt_ioppr_resync_pipeline(dev_src, 0, NULL, FALSE);
599}
600
601static int _styles_rebuild_history_from_items(dt_develop_t *dev_src, GList *applied_items)
602{
604
605 for(GList *l = applied_items; l; l = g_list_next(l))
606 {
607 dt_style_item_t *style_item = (dt_style_item_t *)l->data;
608 const char *multi_name = _dt_styles_normalize_multi_name(style_item->multi_name);
609 dt_iop_module_t *module
610 = dt_dev_get_module_instance(dev_src, style_item->operation, multi_name, style_item->multi_priority);
611 if(IS_NULL_PTR(module)) continue;
612
614 if(IS_NULL_PTR(hist)) return 1;
615
616 dev_src->history = g_list_append(dev_src->history, hist);
617 if(!dt_dev_history_item_update_from_params(dev_src, hist, module, module->enabled, NULL, 0, NULL, NULL))
618 {
620 return 1;
621 }
622 }
623
624 dt_dev_set_history_end_ext(dev_src, g_list_length(dev_src->history));
625
628
629 return 0;
630}
631
632static int _styles_prepare_source_dev(dt_develop_t *dev_src, const char *name, const int style_id,
633 const int32_t imgid, GList **out_si_list, GHashTable **out_style_ids,
634 GList **out_mod_list)
635{
636 gboolean has_iop_list = FALSE;
637 if(_styles_init_source_dev(dev_src, name, imgid, &has_iop_list)) return 1;
638
639 GList *si_list = _dt_styles_get_apply_items(style_id);
640 if(!has_iop_list)
641 {
642 // Without a stored iop_list, add order entries before creating the style modules;
643 // otherwise update_for_style_items() sees the new modules as already present.
644 dt_ioppr_update_for_style_items(dev_src, si_list, FALSE);
645 }
646
647 GHashTable *style_ids = g_hash_table_new_full(g_str_hash, g_str_equal, dt_free_gpointer, NULL);
648 GList *applied_items = _styles_collect_applied_items(dev_src, si_list, style_ids);
649
650 if(IS_NULL_PTR(applied_items))
651 {
652 g_hash_table_destroy(style_ids);
653 g_list_free_full(si_list, dt_style_item_free);
654 si_list = NULL;
655 return 1;
656 }
657
658 _styles_sync_pipeline_from_items(dev_src, applied_items, has_iop_list);
659 if(_styles_rebuild_history_from_items(dev_src, applied_items))
660 {
661 g_list_free(applied_items);
662 applied_items = NULL;
663 g_hash_table_destroy(style_ids);
664 g_list_free_full(si_list, dt_style_item_free);
665 si_list = NULL;
666 return 1;
667 }
668
669 // Build module list from the compressed history to guarantee a matching history entry
670 GList *mod_list = _dt_styles_build_mod_list_from_history(dev_src, style_ids);
671 g_list_free(applied_items);
672 applied_items = NULL;
673
674 if(!mod_list)
675 {
676 g_hash_table_destroy(style_ids);
677 g_list_free_full(si_list, dt_style_item_free);
678 si_list = NULL;
679 return 1;
680 }
681
682 *out_si_list = si_list;
683 *out_style_ids = style_ids;
684 *out_mod_list = mod_list;
685 return 0;
686}
687
688int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid,
690{
691 int ret_val = 1;
692
693 // Init source history + pipeline (style content)
694 dt_develop_t dev_src = { 0 };
695
696 GList *si_list = NULL;
697 GHashTable *style_ids = NULL;
698 GList *mod_list = NULL;
699
700 if(_styles_prepare_source_dev(&dev_src, name, style_id, newimgid, &si_list, &style_ids, &mod_list))
701 {
702 dt_dev_cleanup(&dev_src);
703 return 1;
704 }
705
706 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));
707
708 if(mode == DT_HISTORY_MERGE_REPLACE)
709 {
710 ret_val = dt_dev_replace_history_on_image(&dev_src, newimgid, TRUE, "_styles_apply_to_image_merge");
711 }
712 else
713 {
714 ret_val = dt_dev_merge_history_into_image(&dev_src, newimgid, mod_list,
715 dt_conf_get_bool("history/style/copy_iop_order"), mode,
716 dt_conf_get_bool("history/paste_instances"), name, batch);
717 }
718
719 g_list_free(mod_list);
720 mod_list = NULL;
721 g_hash_table_destroy(style_ids);
722 g_list_free_full(si_list, dt_style_item_free);
723 si_list = NULL;
724 dt_dev_cleanup(&dev_src);
725
726 return ret_val;
727}
728
730{
732
733 dt_iop_module_t *module = _dt_styles_tmp_module_from_style_item(dev, style_item);
734 if(module)
735 {
736 dt_history_merge_module_into_history(dev, NULL, module);
737 dt_ioppr_resync_pipeline(dev, 0, NULL, FALSE);
740 }
741
743}
744
745void dt_styles_apply_to_image(const char *name, const gboolean duplicate, const int32_t imgid)
746{
748 dt_history_style_on_image(imgid, name, duplicate);
750}
751
752void dt_styles_delete_by_name_adv(const char *name, const gboolean raise)
753{
754 int id = 0;
755 if((id = dt_styles_get_id_by_name(name)) != 0)
756 {
758
759 if(raise)
761 }
762}
763
768
769typedef struct _item_list_ctx_t
770{
771 GList *result;
772 gboolean params;
773 int32_t imgid;
775
776static void _prepend_item(void *user_data, const int num, const int multi_priority,
777 const int module_version, const char *operation, const int enabled,
778 const void *params, const int32_t params_size,
779 const void *blendop_params, const int32_t blendop_params_size,
780 const int blendop_version, const char *multi_name,
781 const int selimg_num, const double iop_order)
782{
783 _item_list_ctx_t *ctx = (_item_list_ctx_t *)user_data;
784
785 if(strcmp(operation, "mask_manager") == 0) return;
786
787 // name of current item of style
788 char iname[512] = { 0 };
789 dt_style_item_t *item = calloc(1, sizeof(dt_style_item_t));
790
791 item->num = num;
792 item->multi_priority = multi_priority;
793 item->selimg_num = -1;
794 item->module_version = module_version;
795 item->enabled = enabled;
796
797 const gboolean has_multi_name = multi_name && *multi_name && (strcmp(multi_name, "0") != 0);
798
799 if(ctx->params)
800 {
801 // when we get the parameters we do not want to get the operation localized as this
802 // is used to compare against the internal module name.
803
804 if(has_multi_name)
805 g_snprintf(iname, sizeof(iname), "%s %s", operation, multi_name);
806 else
807 g_snprintf(iname, sizeof(iname), "%s", operation);
808
809 item->params = malloc(params_size);
810 item->params_size = params_size;
811 memcpy(item->params, params, params_size);
812
813 item->blendop_params = malloc(blendop_params_size);
814 item->blendop_params_size = blendop_params_size;
815 item->blendop_version = blendop_version;
816 memcpy(item->blendop_params, blendop_params, blendop_params_size);
817 }
818 else
819 {
820 const gchar *itname = dt_iop_get_localized_name(operation);
821
822 if(has_multi_name)
823 g_snprintf(iname, sizeof(iname), "%s %s", itname, multi_name);
824 else
825 g_snprintf(iname, sizeof(iname), "%s", itname);
826
827 item->params = NULL;
828 item->blendop_params = NULL;
829 item->params_size = 0;
830 item->blendop_params_size = 0;
831 item->blendop_version = 0;
832 if(ctx->imgid != UNKNOWN_IMAGE) item->selimg_num = selimg_num;
833 }
834 item->name = g_strdup(iname);
835 item->operation = g_strdup(operation);
836 item->multi_name = g_strdup(multi_name);
837 item->iop_order = iop_order;
838 ctx->result = g_list_prepend(ctx->result, item);
839}
840
841GList *dt_styles_get_item_list(const char *name, gboolean params, int32_t imgid)
842{
843 _item_list_ctx_t ctx = { .result = NULL, .params = params, .imgid = imgid };
844 int id = 0;
845 if((id = dt_styles_get_id_by_name(name)) != 0)
846 {
847 if(params)
849 else if(imgid != UNKNOWN_IMAGE)
851 else
853 }
854 return g_list_reverse(ctx.result); // list was built in reverse order, so un-reverse it
855}
856
858{
860 if(IS_NULL_PTR(items)) return NULL;
861
862 GList *names = NULL;
863 for(GList *items_iter = items; items_iter; items_iter = g_list_next(items_iter))
864 {
865 dt_style_item_t *item = (dt_style_item_t *)items_iter->data;
866 names = g_list_prepend(names, g_strdup(item->name));
867 }
868 names = g_list_reverse(names); // list was built in reverse order, so un-reverse it
869
870 char *result = dt_util_glist_to_str("\n", names);
871 g_list_free_full(names, dt_free_gpointer);
872 names = NULL;
873 g_list_free_full(items, dt_style_item_free);
874 items = NULL;
875 return result;
876}
877
878static void _prepend_style(void *user_data, const char *name, const char *description)
879{
880 GList **result = (GList **)user_data;
881 dt_style_t *s = g_malloc(sizeof(dt_style_t));
882 s->name = g_strdup(name);
883 s->description = g_strdup(description);
884 *result = g_list_prepend(*result, s);
885}
886
887GList *dt_styles_get_list(const char *filter)
888{
889 GList *result = NULL;
891 return g_list_reverse(result); // list was built in reverse order, so un-reverse it
892}
893
894static void _write_item(void *user_data, const int num, const int multi_priority,
895 const int module_version, const char *operation, const int enabled,
896 const void *params, const int32_t params_size,
897 const void *blendop_params, const int32_t blendop_params_size,
898 const int blendop_version, const char *multi_name,
899 const int selimg_num, const double iop_order)
900{
901 xmlTextWriterPtr writer = (xmlTextWriterPtr)user_data;
902 char *op_params_txt = dt_exif_xmp_encode((const unsigned char *)params, params_size, NULL);
903 char *blendop_params_txt = dt_exif_xmp_encode((const unsigned char *)blendop_params, blendop_params_size, NULL);
904
905 xmlTextWriterStartElement(writer, BAD_CAST "plugin");
906 xmlTextWriterWriteFormatElement(writer, BAD_CAST "num", "%d", num);
907 xmlTextWriterWriteFormatElement(writer, BAD_CAST "module", "%d", module_version);
908 xmlTextWriterWriteFormatElement(writer, BAD_CAST "operation", "%s", operation);
909 xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_params", "%s", op_params_txt);
910 xmlTextWriterWriteFormatElement(writer, BAD_CAST "enabled", "%d", enabled);
911 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_params", "%s", blendop_params_txt);
912 xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_version", "%d", blendop_version);
913 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_priority", "%d", multi_priority);
914 xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_name", "%s", multi_name);
915 xmlTextWriterEndElement(writer);
916
917 // dt_style_encode() used to leak both of these on every item of every style ever saved
918 dt_free(op_params_txt);
919 dt_free(blendop_params_txt);
920}
921
922void dt_styles_save_to_file(const char *style_name, const char *filedir, gboolean overwrite)
923{
924 char stylesdir[DT_PATH_MAX] = { 0 };
925 if(IS_NULL_PTR(filedir))
926 {
927 dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir));
928 g_strlcat(stylesdir, "/styles", sizeof(stylesdir));
929 g_mkdir_with_parents(stylesdir, 00755);
930 filedir = stylesdir;
931 }
932
933 int rc = 0;
934 char stylename[DT_PATH_MAX];
935
936 // generate filename based on name of style
937 // convert all characters to underscore which are not allowed in filenames
938 char *filename = g_strdup_printf("%s.dtstyle", style_name);
939 g_strdelimit(filename, "/<>:\"\\|*?[]", '_');
940 dt_concat_path_file(stylename, filedir, filename);
941 dt_free(filename);
942
943 // check if file exists
944 if(g_file_test(stylename, G_FILE_TEST_EXISTS) == TRUE)
945 {
946 if(overwrite)
947 {
948 if(g_unlink(stylename))
949 {
950 dt_history_message(_("failed to overwrite style file for %s"), style_name);
951 return;
952 }
953 }
954 else
955 {
956 dt_history_message(_("style file for %s exists"), style_name);
957 return;
958 }
959 }
960
961 if(!dt_styles_exists(style_name)) return;
962
963 xmlTextWriterPtr writer = xmlNewTextWriterFilename(stylename, 0);
964 if(IS_NULL_PTR(writer))
965 {
966 fprintf(stderr, "[dt_styles_save_to_file] Error creating the xml writer\n, path: %s", stylename);
967 return;
968 }
969 rc = xmlTextWriterStartDocument(writer, NULL, "UTF-8", NULL);
970 if(rc < 0)
971 {
972 fprintf(stderr, "[dt_styles_save_to_file]: Error on encoding setting");
973 return;
974 }
975 xmlTextWriterStartElement(writer, BAD_CAST "darktable_style");
976 xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0");
977
978 xmlTextWriterStartElement(writer, BAD_CAST "info");
979 xmlTextWriterWriteFormatElement(writer, BAD_CAST "name", "%s", style_name);
980 gchar *style_description = dt_styles_get_description(style_name);
981 xmlTextWriterWriteFormatElement(writer, BAD_CAST "description", "%s", style_description);
982 dt_free(style_description);
983 GList *iop_list = dt_styles_module_order_list(style_name);
984 if(iop_list)
985 {
986 char *iop_list_text = dt_ioppr_serialize_text_iop_order_list(iop_list);
987 xmlTextWriterWriteFormatElement(writer, BAD_CAST "iop_list", "%s", iop_list_text);
988 dt_free(iop_list_text);
989 g_list_free_full(iop_list, dt_free_gpointer);
990 iop_list = NULL;
991 }
992 xmlTextWriterEndElement(writer);
993
994 xmlTextWriterStartElement(writer, BAD_CAST "style");
996 xmlTextWriterEndDocument(writer);
997 xmlFreeTextWriter(writer);
998}
999
1001{
1002 StyleInfoData *info = g_new0(StyleInfoData, 1);
1003 info->name = g_string_new("");
1004 info->description = g_string_new("");
1005
1006 StyleData *data = g_new0(StyleData, 1);
1007 data->info = info;
1008 data->in_plugin = FALSE;
1009 data->plugins = NULL;
1010
1011 return data;
1012}
1013
1015{
1016 StylePluginData *plugin = g_new0(StylePluginData, 1);
1017 plugin->operation = g_string_new("");
1018 plugin->op_params = g_string_new("");
1019 plugin->blendop_params = g_string_new("");
1020 plugin->multi_name = g_string_new("");
1021 plugin->iop_order = -1.0;
1022 return plugin;
1023}
1024
1025static void dt_styles_style_data_free(StyleData *style, gboolean free_segments)
1026{
1027 g_string_free(style->info->name, free_segments);
1028 g_string_free(style->info->description, free_segments);
1029 g_list_free_full(style->info->iop_list, dt_free_gpointer);
1030 style->info->iop_list = NULL;
1031 g_list_free(style->plugins);
1032 style->plugins = NULL;
1033 dt_free(style);
1034}
1035
1036static void dt_styles_start_tag_handler(GMarkupParseContext *context, const gchar *element_name,
1037 const gchar **attribute_names, const gchar **attribute_values,
1038 gpointer user_data, GError **error)
1039{
1040 StyleData *style = user_data;
1041 const gchar *elt = g_markup_parse_context_get_element(context);
1042
1043 // We need to append the contents of any subtags to the content field
1044 // for this we need to know when we are inside the note-content tag
1045 if(g_ascii_strcasecmp(elt, "plugin") == 0)
1046 {
1047 style->in_plugin = TRUE;
1048 style->plugins = g_list_prepend(style->plugins, dt_styles_style_plugin_new());
1049 }
1050}
1051
1052static void dt_styles_end_tag_handler(GMarkupParseContext *context, const gchar *element_name,
1053 gpointer user_data, GError **error)
1054{
1055 StyleData *style = user_data;
1056 const gchar *elt = g_markup_parse_context_get_element(context);
1057
1058 // We need to append the contents of any subtags to the content field
1059 // for this we need to know when we are inside the note-content tag
1060 if(g_ascii_strcasecmp(elt, "plugin") == 0)
1061 {
1062 style->in_plugin = FALSE;
1063 }
1064}
1065
1066static void dt_styles_style_text_handler(GMarkupParseContext *context, const gchar *text, gsize text_len,
1067 gpointer user_data, GError **error)
1068{
1069 StyleData *style = user_data;
1070 const gchar *elt = g_markup_parse_context_get_element(context);
1071
1072 if(g_ascii_strcasecmp(elt, "name") == 0)
1073 {
1074 g_string_append_len(style->info->name, text, text_len);
1075 }
1076 else if(g_ascii_strcasecmp(elt, "description") == 0)
1077 {
1078 g_string_append_len(style->info->description, text, text_len);
1079 }
1080 else if(g_ascii_strcasecmp(elt, "iop_list") == 0)
1081 {
1083 if(style->info->iop_list)
1085 }
1086 else if(style->in_plugin)
1087 {
1088 StylePluginData *plug = style->plugins->data;
1089 if(g_ascii_strcasecmp(elt, "operation") == 0)
1090 {
1091 g_string_append_len(plug->operation, text, text_len);
1092 }
1093 else if(g_ascii_strcasecmp(elt, "op_params") == 0)
1094 {
1095 g_string_append_len(plug->op_params, text, text_len);
1096 }
1097 else if(g_ascii_strcasecmp(elt, "blendop_params") == 0)
1098 {
1099 g_string_append_len(plug->blendop_params, text, text_len);
1100 }
1101 else if(g_ascii_strcasecmp(elt, "blendop_version") == 0)
1102 {
1103 plug->blendop_version = atoi(text);
1104 }
1105 else if(g_ascii_strcasecmp(elt, "multi_priority") == 0)
1106 {
1107 plug->multi_priority = atoi(text);
1108 }
1109 else if(g_ascii_strcasecmp(elt, "multi_name") == 0)
1110 {
1111 g_string_append_len(plug->multi_name, text, text_len);
1112 }
1113 else if(g_ascii_strcasecmp(elt, "num") == 0)
1114 {
1115 plug->num = atoi(text);
1116 }
1117 else if(g_ascii_strcasecmp(elt, "module") == 0)
1118 {
1119 plug->module = atoi(text);
1120 }
1121 else if(g_ascii_strcasecmp(elt, "enabled") == 0)
1122 {
1123 plug->enabled = atoi(text);
1124 }
1125 else if(g_ascii_strcasecmp(elt, "iop_order") == 0)
1126 {
1127 plug->iop_order = atof(text);
1128 }
1129 }
1130}
1131
1132static GMarkupParser dt_style_parser = {
1133 dt_styles_start_tag_handler, // Start element handler
1134 dt_styles_end_tag_handler, // End element handler
1135 dt_styles_style_text_handler, // Text element handler
1136 NULL, // Passthrough handler
1137 NULL // Error handler
1138};
1139
1140static void dt_style_plugin_save(StylePluginData *plugin, gpointer styleId)
1141{
1142 int id = GPOINTER_TO_INT(styleId);
1143
1144 const char *param_c = plugin->op_params->str;
1145 const int param_c_len = strlen(param_c);
1146 int params_len = 0;
1147 unsigned char *params = dt_exif_xmp_decode(param_c, param_c_len, &params_len);
1148
1149 /* decode and store blendop params */
1150 int blendop_params_len = 0;
1151 unsigned char *blendop_params = dt_exif_xmp_decode(
1152 plugin->blendop_params->str, strlen(plugin->blendop_params->str), &blendop_params_len);
1153
1154 dt_style_repository_insert_item(id, plugin->num, plugin->module, plugin->operation->str, params,
1155 params_len, plugin->enabled, blendop_params, blendop_params_len,
1156 plugin->blendop_version, plugin->multi_priority,
1157 plugin->multi_name->str);
1158
1159 dt_free(params);
1160}
1161
1162static void dt_style_save(StyleData *style)
1163{
1164 int id = 0;
1165 if(IS_NULL_PTR(style)) return;
1166
1167 /* first create the style header */
1168 if(!dt_styles_create_style_header(style->info->name->str, style->info->description->str, style->info->iop_list)) return;
1169
1170 if((id = dt_styles_get_id_by_name(style->info->name->str)) != 0)
1171 {
1172 g_list_foreach(style->plugins, (GFunc)dt_style_plugin_save, GINT_TO_POINTER(id));
1173 dt_history_message(_("style %s was successfully imported"), style->info->name->str);
1174 }
1175}
1176
1177void dt_styles_import_from_file(const char *style_path)
1178{
1179 FILE *style_file;
1180 StyleData *style;
1181 GMarkupParseContext *parser;
1182 gchar buf[1024];
1183
1184 style = dt_styles_style_data_new();
1185 parser = g_markup_parse_context_new(&dt_style_parser, 0, style, NULL);
1186
1187 if((style_file = g_fopen(style_path, "r")))
1188 {
1189
1190 while(!feof(style_file))
1191 {
1192 const size_t num_read = fread(buf, sizeof(gchar), sizeof(buf), style_file);
1193
1194 if(num_read == 0)
1195 {
1196 break;
1197 }
1198 else if(num_read == -1)
1199 {
1200 // FIXME: ferror?
1201 // ERROR !
1202 break;
1203 }
1204
1205 if(!g_markup_parse_context_parse(parser, buf, num_read, NULL))
1206 {
1207 g_markup_parse_context_free(parser);
1209 fclose(style_file);
1210 return;
1211 }
1212 }
1213 }
1214 else
1215 {
1216 // Failed to open file, clean up.
1217 dt_history_message(_("could not read file `%s'"), style_path);
1218 g_markup_parse_context_free(parser);
1220 return;
1221 }
1222
1223 if(!g_markup_parse_context_end_parse(parser, NULL))
1224 {
1225 g_markup_parse_context_free(parser);
1227 fclose(style_file);
1228 return;
1229 }
1230 g_markup_parse_context_free(parser);
1231 // save data
1232 dt_style_save(style);
1233 //
1235 fclose(style_file);
1236
1238}
1239
1241{
1242 const int id = dt_styles_get_id_by_name(name);
1243 if(id == 0) return NULL;
1245}
1246
1247int32_t dt_styles_get_id_by_name(const char *name)
1248{
1250}
1251
1252static void _collect_style(void *user_data, const char *name, const char *description)
1253{
1254 dt_style_t **out = (dt_style_t **)user_data;
1255 dt_style_t *s = g_malloc(sizeof(dt_style_t));
1256 s->name = g_strdup(name);
1257 s->description = g_strdup(description);
1258 *out = s;
1259}
1260
1262{
1263 dt_style_t *s = NULL;
1265 return s;
1266}
1267
1269{
1271}
1272
1273#undef DT_IOP_ORDER_INFO
1274// clang-format off
1275// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1276// vim: shiftwidth=2 expandtab tabstop=2 cindent
1277// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1278// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:168
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
size_t params_size(dt_imageio_module_format_t *self)
Definition avif.c:571
int dt_develop_blend_version(void)
Definition blend.c:1714
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:1778
const dt_colormatrix_t dt_aligned_pixel_t out
int dt_conf_get_bool(const char *name)
void dt_dev_pop_history_items_ext(dt_develop_t *dev) REQUIRES_SHARED(dev -> history_mutex)
Apply history items to module params up to dev->history_end.
dt_dev_history_item_t * dt_dev_history_item_create(void)
Allocate a fresh, blank history item with refcount 1.
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.
int dt_history_merge_module_into_history(dt_develop_t *dev_dest, dt_develop_t *dev_src, dt_iop_module_t *mod_src) REQUIRES(dev_dest -> history_mutex)
Merge a single module instance into a destination history.
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) REQUIRES(dev -> history_mutex)
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.
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:1905
int32_t dt_dev_get_history_end_ext(struct dt_develop_t *dev)
Get the current history end index (GUI perspective).
Definition develop.c:1899
void dt_dev_cleanup(dt_develop_t *dev)
Definition develop.c:237
void dt_dev_init(dt_develop_t *dev, int32_t gui_attached)
Definition develop.c:143
dt_dev_image_storage_t dt_dev_ensure_image_storage(dt_develop_t *dev, const int32_t imgid)
Definition develop.c:956
GHashTable * names
GtkWidget* -> the name the application knows it by.
gboolean enabled
–doc was passed on the command line
static int dt_pthread_rwlock_wrlock(dt_pthread_rwlock_t *rwlock) ACQUIRE(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:299
static int dt_pthread_rwlock_unlock(dt_pthread_rwlock_t *rwlock) RELEASE_GENERIC(rwlock) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:217
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
Definition exif.cc:2207
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:2116
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
const dt_collection_sort_t items[]
Definition filter.c:102
void dt_history_message(const char *format,...)
void dt_history_changed(const dt_history_change_t what)
Raise it. Internal to this code.
Everything the history, styles and presets code says to the outside world: messages for the user,...
@ DT_HISTORY_CHANGE_STYLES
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
#define UNKNOWN_IMAGE
Definition image.h:78
void dt_iop_cleanup_module(dt_iop_module_t *module)
Definition imageop.c:1113
const gchar * dt_iop_get_localized_name(const gchar *op)
Definition imageop.c:1757
int dt_iop_load_module(dt_iop_module_t *module, dt_iop_module_so_t *module_so, dt_develop_t *dev)
Definition imageop.c:1102
dt_iop_module_t * dt_iop_get_module_by_op_priority(GList *modules, const char *operation, const int multi_priority)
Definition imageop.c:1839
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:1100
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:913
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:1721
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:1309
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:1241
char * dt_ioppr_serialize_text_iop_order_list(GList *iop_order_list)
Serialize an order list to a text representation.
Definition iop_order.c:2507
GList * dt_ioppr_deserialize_text_iop_order_list(const char *buf)
Deserialize an order list from a text representation.
Definition iop_order.c:2562
GList * dt_ioppr_insert_missing_modules(GList *iop_order_list)
Insert modules that postdate a deserialized/custom order list.
Definition iop_order.c:773
#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:96
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
void dt_concat_path_file(char destination[4096], const char path[4096], const char *const file)
Append a constant filename to a variable, stack-based, fixed-sized, directory, and add a / in-between...
Definition darktable.c:2674
const char * name
Definition pdf.h:90
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 void _prepend_item(void *user_data, const int num, const int multi_priority, const int module_version, const char *operation, const int enabled, const void *params, const int32_t params_size, const void *blendop_params, const int32_t blendop_params_size, const int blendop_version, const char *multi_name, const int selimg_num, const double iop_order)
static const char * _dt_styles_normalize_multi_name(const char *multi_name)
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)
static void _prepend_style(void *user_data, const char *name, const char *description)
static void _prepend_apply_item(void *user_data, const int num, const int multi_priority, const int module_version, const char *operation, const int enabled, const void *params, const int32_t params_size, const void *blendop_params, const int32_t blendop_params_size, const int blendop_version, const char *multi_name, const int selimg_num, const double 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)
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 void _write_item(void *user_data, const int num, const int multi_priority, const int module_version, const char *operation, const int enabled, const void *params, const int32_t params_size, const void *blendop_params, const int32_t blendop_params_size, const int blendop_version, const char *multi_name, const int selimg_num, const double iop_order)
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)
static GMarkupParser dt_style_parser
void dt_styles_import_from_file(const char *style_path)
static void _collect_style(void *user_data, const char *name, const char *description)
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
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_iop_module_t *gboolean enabled
Definition dev_history.h:52
GList * iop_order_list
Definition develop.h:275
GList * iop
Definition develop.h:269
dt_pthread_rwlock_t history_mutex
Definition develop.h:247
GList * history
Definition develop.h:259
dt_iop_params_t * default_params
Definition imageop.h:333
struct dt_develop_blend_params_t * blend_params
Definition imageop.h:349
char multi_name[128]
Definition imageop.h:387
gboolean enabled
Definition imageop.h:313
dt_iop_module_so_t * so
Definition imageop.h:376
struct dt_develop_blend_params_t * default_blendop_params
Definition imageop.h:349
int32_t params_size
Definition imageop.h:335
dt_dev_operation_t op
Definition imageop.h:259
dt_iop_params_t * params
Definition imageop.h:333
dt_iop_params_t * params
dt_develop_blend_params_t * blendop_params
int32_t blendop_params_size
gchar * description
gchar * name
gboolean dt_style_repository_delete_items_except(const int32_t styleid, GList *nums)
gboolean dt_style_repository_copy_items_from_history(const int32_t styleid, const int32_t imgid, GList *nums)
void dt_style_repository_foreach_style(const char *filter, dt_style_repository_style_cb cb, void *user_data)
gboolean dt_style_repository_get_style(const char *name, dt_style_repository_style_cb cb, void *user_data)
int32_t dt_style_repository_get_id_by_name(const char *name)
char * dt_style_repository_get_iop_list(const char *name)
void dt_style_repository_foreach_item_with_params(const int32_t styleid, dt_style_repository_item_cb cb, void *user_data)
gboolean dt_style_repository_normalize_multi_priority(const int32_t styleid)
void dt_style_repository_foreach_item(const int32_t styleid, dt_style_repository_item_cb cb, void *user_data)
gboolean dt_style_repository_insert_item(const int32_t styleid, const int num, const int module_version, const char *operation, const void *params, const int32_t params_size, const int enabled, const void *blendop_params, const int32_t blendop_params_size, const int blendop_version, const int multi_priority, const char *multi_name)
gboolean dt_style_repository_set_iop_list(const int32_t styleid, const char *iop_list_txt)
void dt_style_repository_cleanup(void)
void dt_style_repository_foreach_item_against_image(const int32_t styleid, const int32_t imgid, dt_style_repository_item_cb cb, void *user_data)
void dt_style_repository_foreach_apply_item(const int32_t styleid, dt_style_repository_item_cb cb, void *user_data)
gboolean dt_style_repository_update_header(const int32_t styleid, const char *newname, const char *description)
gboolean dt_style_repository_insert_header(const char *name, const char *description, const char *iop_list_txt)
void dt_style_repository_append_item_from_history(const int32_t styleid, const int32_t imgid, const int history_num)
char * dt_style_repository_get_description(const int32_t styleid)
gboolean dt_style_repository_delete(const int32_t styleid)
void dt_style_repository_foreach_item_for_export(const int32_t styleid, dt_style_repository_item_cb cb, void *user_data)
void dt_style_repository_update_item_from_history(const int32_t styleid, const int item_num, const int32_t imgid, const int history_num)
gboolean dt_style_repository_copy_items_from_style(const int32_t dest_styleid, const int32_t source_styleid, GList *nums)
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:49
dt_undo_t * dt_undo_get_global(void)
Definition darktable.c:611
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)
Definition utility.c:170