Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
export.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2013 johannes hanika.
4 Copyright (C) 2010 Alexandre Prokoudine.
5 Copyright (C) 2010-2011, 2013 Henrik Andersson.
6 Copyright (C) 2010 Milan Knížek.
7 Copyright (C) 2010, 2013-2014 Pascal de Bruijn.
8 Copyright (C) 2010 Stuart Henderson.
9 Copyright (C) 2011, 2013 Antony Dovgal.
10 Copyright (C) 2011-2013, 2015 Jérémy Rosen.
11 Copyright (C) 2011 Robert Bieber.
12 Copyright (C) 2011-2017, 2019-2020 Tobias Ellinghaus.
13 Copyright (C) 2012 Christian Tellefsen.
14 Copyright (C) 2012 Moritz Lipp.
15 Copyright (C) 2012-2015, 2019-2021 Pascal Obry.
16 Copyright (C) 2012 Richard Wonka.
17 Copyright (C) 2012-2013 Simon Spannagel.
18 Copyright (C) 2013 José Carlos García Sogo.
19 Copyright (C) 2013-2016 Roman Lebedev.
20 Copyright (C) 2013 Thomas Pryds.
21 Copyright (C) 2017 luzpaz.
22 Copyright (C) 2018 Maurizio Paglia.
23 Copyright (C) 2018 rawfiner.
24 Copyright (C) 2019-2020, 2022-2023, 2025-2026 Aurélien PIERRE.
25 Copyright (C) 2019 Edgardo Hoszowski.
26 Copyright (C) 2019 jakubfi.
27 Copyright (C) 2019 parafin.
28 Copyright (C) 2019-2021 Philippe Weyland.
29 Copyright (C) 2020 a.
30 Copyright (C) 2020-2022 Aldric Renaudin.
31 Copyright (C) 2020-2021 Chris Elston.
32 Copyright (C) 2020-2022 Diederik Ter Rahe.
33 Copyright (C) 2020 Heiko Bauke.
34 Copyright (C) 2020-2021 Hubert Kowalski.
35 Copyright (C) 2020 junkyardsparkle.
36 Copyright (C) 2020 Marco.
37 Copyright (C) 2020-2021 Ralf Brown.
38 Copyright (C) 2021 lhietal.
39 Copyright (C) 2022 Martin Bařinka.
40 Copyright (C) 2022 Miloš Komarčević.
41 Copyright (C) 2022 Nicolas Auffray.
42 Copyright (C) 2022 Victor Forsiuk.
43 Copyright (C) 2023 Luca Zulberti.
44 Copyright (C) 2024 Guillaume Stutin.
45
46 darktable is free software: you can redistribute it and/or modify
47 it under the terms of the GNU General Public License as published by
48 the Free Software Foundation, either version 3 of the License, or
49 (at your option) any later version.
50
51 darktable is distributed in the hope that it will be useful,
52 but WITHOUT ANY WARRANTY; without even the implied warranty of
53 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 GNU General Public License for more details.
55
56 You should have received a copy of the GNU General Public License
57 along with darktable. If not, see <http://www.gnu.org/licenses/>.
58*/
59
60#include "bauhaus/bauhaus.h"
61#include "common/collection.h"
62#include "common/colorspaces.h"
63#include "common/darktable.h"
64#include "common/debug.h"
67#include "common/styles.h"
68#include "control/conf.h"
69#include "control/control.h"
70#include "control/jobs.h"
71#include "control/signal.h"
72#include "dtgtk/button.h"
73
74#include "gui/gtk.h"
75#include "gui/presets.h"
76#include "libs/lib.h"
77#include "libs/lib_api.h"
78#ifdef GDK_WINDOWING_QUARTZ
79#include "osx/osx.h"
80#endif
81#include <gdk/gdkkeysyms.h>
82
83static sqlite3_stmt *_export_presets_stmt = NULL;
84#include <gtk/gtk.h>
85#include <stdlib.h>
86#include <ctype.h>
87
88#include <glib.h>
89
90DT_MODULE(7)
91
92#define EXPORT_MAX_IMAGE_SIZE UINT16_MAX
93#define CONFIG_PREFIX "plugins/lighttable/export/"
94
110
111
113{
114 DT_DIMENSIONS_PIXELS = 0, // set dimensions exactly in pixels
115 DT_DIMENSIONS_CM = 1, // set dimensions from physical size in centimeters * DPI
116 DT_DIMENSIONS_INCH = 2, // set dimensions from physical size in inch
117 DT_DIMENSIONS_SCALE = 3, // set dimensions by scale
118 DT_DIMENSIONS_ORIGINAL = 4 // user-friendly alias for scale = 1
120
121char *dt_lib_export_metadata_configuration_dialog(char *list, const gboolean ondisk);
127static void _get_max_output_dimension(dt_lib_export_t *d, uint32_t *width, uint32_t *height);
130
131#define INCH_TO_CM (2.54f)
132
133static inline float pixels2cm(dt_lib_export_t *self, const uint32_t pix)
134{
135 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(self->print_dpi)));
136 return ((float)pix * INCH_TO_CM) / (float)dpi;
137}
138
139static inline float pixels2inch(dt_lib_export_t *self, const uint32_t pix)
140{
141 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(self->print_dpi)));
142 return (float)pix / (float)dpi;
143}
144
145static inline uint32_t cm2pixels(dt_lib_export_t *self, const float cm)
146{
147 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(self->print_dpi)));
148 return ceilf((cm * (float)dpi) / INCH_TO_CM);
149}
150
151static inline uint32_t inch2pixels(dt_lib_export_t *self, const float inch)
152{
153 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(self->print_dpi)));
154 return ceilf(inch * (float)dpi);
155}
156
157static inline uint32_t print2pixels(dt_lib_export_t *self, const float value)
158{
160 switch(d_type)
161 {
164 return ceilf(value);
165 case(DT_DIMENSIONS_CM):
166 return cm2pixels(self, value);
167 case(DT_DIMENSIONS_INCH):
168 return inch2pixels(self, value);
170 ;
171 }
172
173 // should never run this
174 return ceilf(value);
175}
176
177static inline float pixels2print(dt_lib_export_t *self, const uint32_t pix)
178{
180 switch(d_type)
181 {
184 return (float)pix;
185 case(DT_DIMENSIONS_CM):
186 return pixels2cm(self, pix);
187 case(DT_DIMENSIONS_INCH):
188 return pixels2inch(self, pix);
190 ;
191 }
192
193 // should never run this
194 return (float)pix;
195}
196
197const char *name(struct dt_lib_module_t *self)
198{
199 return _("export");
200}
201
202const char **views(dt_lib_module_t *self)
203{
204 // Not displayed in views, only in popup triggered from main menu
205 static const char *v[] = {"special", NULL};
206 return v;
207}
208
210{
212}
213
214static void _update(dt_lib_module_t *self)
215{
217 const dt_lib_export_t *d = (dt_lib_export_t *)self->data;
218
219 const gboolean has_act_on = (dt_act_on_get_images_nb(TRUE, FALSE) > 0);
220
221 const char *format_name = dt_conf_get_string_const(CONFIG_PREFIX "format_name");
222 const char *storage_name = dt_conf_get_string_const(CONFIG_PREFIX "storage_name");
223 const int format_index = dt_imageio_get_index_of_format(dt_imageio_get_format_by_name(format_name));
224 const int storage_index = dt_imageio_get_index_of_storage(dt_imageio_get_storage_by_name(storage_name));
225
226 gtk_widget_set_sensitive(GTK_WIDGET(d->export_button), has_act_on && format_index != -1 && storage_index != -1);
227}
228
229static void _image_selection_changed_callback(gpointer instance, dt_lib_module_t *self)
230{
231 _update(self);
232}
233
234static void _collection_updated_callback(gpointer instance, dt_collection_change_t query_change,
235 dt_collection_properties_t changed_property, gpointer imgs, int next,
236 dt_lib_module_t *self)
237{
238 _update(self);
239}
240
241gboolean _is_int(double value)
242{
243 return (value == (int)value);
244}
245
246static void _scale_optim()
247{
248 double num = 1.0, denum = 1.0;
250 gchar *scale_str = dt_conf_get_string(CONFIG_PREFIX "resizing_factor");
251 gchar _str[6] = "";
252
253 gchar *pdiv = strchr(scale_str, '/');
254
255 gchar scale_buf[64] = "";
256 if(IS_NULL_PTR(pdiv))
257 {
258 if(_is_int(num) && num > 0.0)
259 {
260 sprintf(_str, "%d", (int) num);
261 g_strlcat(scale_buf, _str, sizeof(scale_buf));
262 }
263 else
264 {
265 g_strlcat(scale_buf, scale_str, sizeof(scale_buf));
266 }
267 }
268 else if(pdiv-scale_str == 0)
269 {
270 if(_is_int(denum) && denum > 0.0)
271 {
272 sprintf(_str, "%d", (int) denum);
273 g_strlcat(scale_buf, _str, sizeof(scale_buf));
274 }
275 else
276 {
277 g_strlcat(scale_buf, "1/", sizeof(scale_buf));
278 g_strlcat(scale_buf, pdiv+1, sizeof(scale_buf));
279 }
280 }
281 else
282 {
283 if(_is_int(num) && num > 0.0)
284 {
285 sprintf(_str, "%d", (int) num);
286 g_strlcat(scale_buf, _str, sizeof(scale_buf));
287 }
288 else
289 {
290 g_strlcat(scale_buf, scale_str, sizeof(scale_buf));
291 }
292 g_strlcat(scale_buf, "/", sizeof(scale_buf));
293 if(_is_int(denum) && denum > 0.0)
294 {
295 sprintf(_str, "%d", (int) denum);
296 g_strlcat(scale_buf, _str, sizeof(scale_buf));
297 }
298 else
299 {
300 g_strlcat(scale_buf, pdiv+1, sizeof(scale_buf));
301 }
302 }
303 dt_conf_set_string(CONFIG_PREFIX "resizing_factor", scale_buf);
304
305 dt_free(scale_str);
306}
307
309{
310 /* write current history changes so nothing gets lost,
311 do that only in the darkroom as there is nothing to be saved
312 when in the lighttable (and it would write over current history stack) */
313 char style[128] = { 0 };
314
315 // get the format_name and storage_name settings which are plug-ins name and not necessary what is displayed on the combobox.
316 // note that we cannot take directly the combobox entry index as depending on the storage some format are not listed.
317 const char *format_name = dt_conf_get_string_const(CONFIG_PREFIX "format_name");
318 const char *storage_name = dt_conf_get_string_const(CONFIG_PREFIX "storage_name");
319 const int format_index = dt_imageio_get_index_of_format(dt_imageio_get_format_by_name(format_name));
320 const int storage_index = dt_imageio_get_index_of_storage(dt_imageio_get_storage_by_name(storage_name));
321
322 if(format_index == -1)
323 {
324 dt_control_log("invalid format for export selected");
325 return;
326 }
327 if(storage_index == -1)
328 {
329 dt_control_log("invalid storage for export selected");
330 return;
331 }
332
333 char *confirm_message = NULL;
335 if(mstorage->ask_user_confirmation)
336 confirm_message = mstorage->ask_user_confirmation(mstorage);
337 if(confirm_message)
338 {
340 GtkWidget *dialog = gtk_message_dialog_new(
341 GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
342 "%s", confirm_message);
343#ifdef GDK_WINDOWING_QUARTZ
345#endif
346
347 gtk_window_set_title(GTK_WINDOW(dialog), _("export to disk"));
348 const gint res = gtk_dialog_run(GTK_DIALOG(dialog));
349 gtk_widget_destroy(dialog);
350 dt_free(confirm_message);
351
352 if(res != GTK_RESPONSE_YES)
353 {
354 return;
355 }
356 }
357
358 // Let's get the max dimension restriction if any...
359 uint32_t max_width = dt_conf_get_int(CONFIG_PREFIX "width");
360 uint32_t max_height = dt_conf_get_int(CONFIG_PREFIX "height");
361
362 const gboolean export_masks = dt_conf_get_bool(CONFIG_PREFIX "export_masks");
363 const char *tmp = dt_conf_get_string_const(CONFIG_PREFIX "style");
364 if(tmp)
365 {
366 g_strlcpy(style, tmp, sizeof(style));
367 }
368
370 gchar *icc_filename = dt_conf_get_string(CONFIG_PREFIX "iccprofile");
371 const dt_iop_color_intent_t icc_intent = dt_conf_get_int(CONFIG_PREFIX "iccintent");
372
373 GList *list = dt_act_on_get_images();
374 dt_control_export(list, max_width, max_height, format_index, storage_index, TRUE, export_masks,
375 style, icc_type, icc_filename, icc_intent, d->metadata_export);
376
377 dt_free(icc_filename);
378
379 _scale_optim();
380 gtk_entry_set_text(GTK_ENTRY(d->scale), dt_conf_get_string_const(CONFIG_PREFIX "resizing_factor"));
381}
382
383static void _scale_changed(GtkEntry *spin, dt_lib_export_t *d)
384{
385 const char *validSign = ",.0123456789";
386 const gchar *value = gtk_entry_get_text(spin);
387
388 const int len = sizeof(value);
389 int i, j = 0, idec = 0, idiv = 0, pdiv = 0;
390 char new_value[30] = "";
391
392 for (i = 0; i < len; i++)
393 {
394 char *val = strchr(validSign, value[i]);
395 if(IS_NULL_PTR(val))
396 {
397 if(idiv==0)
398 {
399 if(i == 0)
400 {
401 new_value[j++] = '1';
402 }
403 else
404 {
405 if(atof(value) == 0.0)
406 {
407 new_value[0] = '1';
408 }
409 idec = 0;
410 idiv = 1;
411 new_value[j++] = '/';
412 pdiv = j;
413 }
414 }
415 }
416 else if((val[0] == '.') || (val[0] == ','))
417 {
418 if(idec == 0)
419 {
420 if((i == 0) || (i == pdiv))
421 {
422 new_value[j++] = '0';
423 }
424 else
425 {
426 idec = 1;
427 new_value[j++] = value[i];
428 }
429 }
430 }
431 else if(value[i] == '\0')
432 {
433 break;
434 }
435 else
436 {
437 new_value[j++] = value[i];
438 }
439 }
440 dt_conf_set_string(CONFIG_PREFIX "resizing_factor", new_value);
441 gtk_entry_set_text(spin, new_value);
442}
443
444static void _width_changed(GtkEditable *entry, gpointer user_data);
445static void _height_changed(GtkEditable *entry, gpointer user_data);
446
447static gboolean _scale_mdlclick(GtkEntry *spin, GdkEventButton *event, dt_lib_export_t *d)
448{
449 if(event->button == 2)
450 {
451 dt_conf_set_string(CONFIG_PREFIX "resizing_factor", "1");
452 g_signal_handlers_block_by_func(spin, _scale_changed, d);
453 gtk_entry_set_text(GTK_ENTRY(spin), "1");
454 g_signal_handlers_unblock_by_func(spin, _scale_changed, d);
455 }
456 else
457 {
458 _scale_changed(spin, d);
459 }
460 return FALSE;
461}
462
463static void _widht_mdlclick(GtkEntry *spin, GdkEventButton *event, gpointer user_data)
464{
465 if(event->button == 2)
466 {
467 dt_conf_set_int(CONFIG_PREFIX "width", 0);
468 g_signal_handlers_block_by_func(spin, _width_changed, user_data);
469 gtk_entry_set_text(GTK_ENTRY(spin), "0");
470 g_signal_handlers_unblock_by_func(spin, _width_changed, user_data);
471 }
472 else
473 {
474 _width_changed(GTK_EDITABLE(spin), user_data);
475 }
476}
477
478static void _height_mdlclick(GtkEntry *spin, GdkEventButton *event, gpointer user_data)
479{
480 if(event->button == 2)
481 {
482 dt_conf_set_int(CONFIG_PREFIX "height", 0);
483 g_signal_handlers_block_by_func(spin, _height_changed, user_data);
484 gtk_entry_set_text(GTK_ENTRY(spin), "0");
485 g_signal_handlers_unblock_by_func(spin, _height_changed, user_data);
486 }
487 else
488 {
489 _height_changed(GTK_EDITABLE(spin), user_data);
490 }
491}
492
494{
495 const dt_dimensions_type_t d_type = (dt_dimensions_type_t)dt_bauhaus_combobox_get(d->dimensions_type);
496
497 if((d_type == DT_DIMENSIONS_SCALE) || (d_type == DT_DIMENSIONS_PIXELS) || (d_type == DT_DIMENSIONS_ORIGINAL))
498 {
499 gtk_widget_hide(d->size_in_px);
500 }
501 else
502 {
503 gtk_widget_show(d->size_in_px);
504 gchar size_in_px_txt[120];
505 snprintf(size_in_px_txt, sizeof(size_in_px_txt) / sizeof(size_in_px_txt[0]), _("which is equal to %s \303\227 %s px"),
506 gtk_entry_get_text(GTK_ENTRY(d->width)), gtk_entry_get_text(GTK_ENTRY(d->height)));
507 gtk_label_set_text(GTK_LABEL(d->size_in_px), size_in_px_txt);
508 }
509}
510
511void _set_dimensions(dt_lib_export_t *d, uint32_t max_width, uint32_t max_height)
512{
513 gchar *max_width_char = g_strdup_printf("%d", max_width);
514 gchar *max_height_char = g_strdup_printf("%d", max_height);
515
517 gtk_entry_set_text(GTK_ENTRY(d->width), max_width_char);
518 gtk_entry_set_text(GTK_ENTRY(d->height), max_height_char);
521
522 dt_conf_set_int(CONFIG_PREFIX "width", max_width);
523 dt_conf_set_int(CONFIG_PREFIX "height", max_height);
524
525 dt_free(max_width_char);
526 dt_free(max_height_char);
528}
529
530
532{
534
535 gtk_widget_set_visible(self->px_size, d_type == DT_DIMENSIONS_PIXELS);
536 gtk_widget_set_visible(self->print_size, d_type == DT_DIMENSIONS_CM || d_type == DT_DIMENSIONS_INCH);
537 gtk_widget_set_visible(self->scale, d_type == DT_DIMENSIONS_SCALE);
538
539 gtk_label_set_text(GTK_LABEL(self->unit_label),
540 d_type == DT_DIMENSIONS_CM ? _("cm") : C_("unit", "in"));
541 _size_in_px_update(self);
542}
543
545{
546 // make sure we don't do anything useless:
547 if(!dt_control_running()) return;
549 gtk_entry_set_text(GTK_ENTRY(d->width), dt_confgen_get(CONFIG_PREFIX "width", DT_DEFAULT));
550 gtk_entry_set_text(GTK_ENTRY(d->height), dt_confgen_get(CONFIG_PREFIX "height", DT_DEFAULT));
551 dt_bauhaus_combobox_set(d->dimensions_type, dt_confgen_get_int(CONFIG_PREFIX "dimensions_type", DT_DEFAULT));
553
554 // Set storage
556 dt_bauhaus_combobox_set(d->storage, storage_index);
557
558 dt_bauhaus_combobox_set(d->export_masks, dt_confgen_get_bool(CONFIG_PREFIX "export_masks", DT_DEFAULT) ? 1 : 0);
559
561
562 // iccprofile
563 const int icctype = dt_confgen_get_int(CONFIG_PREFIX "icctype", DT_DEFAULT);
564 gchar *iccfilename = dt_conf_get_string(CONFIG_PREFIX "iccprofile");
565 dt_bauhaus_combobox_set(d->profile, 0);
566 if(icctype != DT_COLORSPACE_NONE)
567 {
568 for(GList *profiles = darktable.color_profiles->profiles; profiles; profiles = g_list_next(profiles))
569 {
571 if(pp->out_pos > -1
572 && icctype == pp->type
573 && (icctype != DT_COLORSPACE_FILE || !strcmp(iccfilename, pp->filename)))
574 {
575 dt_bauhaus_combobox_set(d->profile, pp->out_pos + 1);
576 break;
577 }
578 }
579 }
580
581 dt_free(iccfilename);
582
583 // style
584 // set it to none if the var is not set or the style doesn't exist anymore
585 gboolean rc = FALSE;
586 const char *style = dt_confgen_get(CONFIG_PREFIX "style", DT_DEFAULT);
587 if(!IS_NULL_PTR(style) && strlen(style) > 0)
588 {
589 rc = dt_bauhaus_combobox_set_from_text(d->style, style);
590 if(rc == FALSE) dt_bauhaus_combobox_set(d->style, 0);
591 }
592 else
593 dt_bauhaus_combobox_set(d->style, 0);
594
595 // export metadata presets
596 dt_free(d->metadata_export);
597 d->metadata_export = dt_lib_export_metadata_get_conf();
598
600 if(mformat) mformat->gui_reset(mformat);
602 if(mstorage) mstorage->gui_reset(mstorage);
603
604 _update(self);
605}
606
607static void set_format_by_name(dt_lib_export_t *d, const char *name)
608{
609 // Find the selected format plugin among all existing plugins
610 dt_imageio_module_format_t *module = NULL;
611 for(GList *it = darktable.imageio->plugins_format; it; it = g_list_next(it))
612 {
613 if(g_strcmp0(((dt_imageio_module_format_t *)it->data)->name(), name) == 0
614 || g_strcmp0(((dt_imageio_module_format_t *)it->data)->plugin_name, name) == 0)
615 {
616 module = (dt_imageio_module_format_t *)it->data;
617 break;
618 }
619 }
620
621 if(!module)
622 {
623 gtk_widget_hide(d->format_extra_container);
624 return;
625 }
626 else if(module->widget)
627 {
628 gtk_widget_show_all(d->format_extra_container);
629 gtk_stack_set_visible_child(GTK_STACK(d->format_extra_container), module->widget);
630 }
631 else
632 {
633 gtk_widget_hide(d->format_extra_container);
634 }
635
636 // Store the new format
637 dt_conf_set_string(CONFIG_PREFIX "format_name", module->plugin_name);
638
639 if(dt_bauhaus_combobox_set_from_text(d->format, module->name()) == FALSE)
640 dt_bauhaus_combobox_set(d->format, 0);
641
642 // Let's also update combination of storage/format dimension restrictions
644
645 // only some modules support export of masks
646 // set it to 0 when insensitive and restore when making it sensitive again. this doesn't survive dt restarts.
647 const gboolean support_layers = (module->flags(NULL) & FORMAT_FLAGS_SUPPORT_LAYERS) == FORMAT_FLAGS_SUPPORT_LAYERS;
648 const gboolean is_enabled = gtk_widget_get_sensitive(d->export_masks);
649 if(support_layers && !is_enabled)
650 {
651 // combobox was disabled and shall be enabled. we want to restore the old setting.
652 const gboolean export_masks = dt_conf_get_bool(CONFIG_PREFIX "export_masks");
653 gtk_widget_set_sensitive(GTK_WIDGET(d->export_masks), TRUE);
654 dt_bauhaus_combobox_set(d->export_masks, export_masks ? 1 : 0);
655 }
656 else if(!support_layers && is_enabled)
657 {
658 // combobox was enabled but shall be disabled. we want to save the current setting.
659 const int export_masks = dt_bauhaus_combobox_get(d->export_masks);
660 dt_bauhaus_combobox_set(d->export_masks, 0);
661 dt_conf_set_bool(CONFIG_PREFIX "export_masks", export_masks == 1);
662 gtk_widget_set_sensitive(GTK_WIDGET(d->export_masks), FALSE);
663 }
664}
665
667{
668 const gchar *name = dt_bauhaus_combobox_get_text(d->format);
669 g_signal_handlers_block_by_func(widget, _format_changed, d);
671 g_signal_handlers_unblock_by_func(widget, _format_changed, d);
672}
673
674static void _get_max_output_dimension(dt_lib_export_t *d, uint32_t *width, uint32_t *height)
675{
676 const char *storage_name = dt_conf_get_string_const(CONFIG_PREFIX "storage_name");
678
679 const char *format_name = dt_conf_get_string_const(CONFIG_PREFIX "format_name");
681
682 if(storage && format)
683 {
684 uint32_t fw, fh, sw, sh;
685 fw = fh = sw = sh = 0; // We are all equals!!!
686 storage->dimension(storage, NULL, &sw, &sh);
687 format->dimension(format, NULL, &fw, &fh);
688
689 if(sw == 0 || fw == 0)
690 *width = sw > fw ? sw : fw;
691 else
692 *width = sw < fw ? sw : fw;
693
694 if(sh == 0 || fh == 0)
695 *height = sh > fh ? sh : fh;
696 else
697 *height = sh < fh ? sh : fh;
698 }
699}
700
702{
703 //reset dimensions to previously stored value if they exceed the maximum
704 uint32_t width = atoi(gtk_entry_get_text(GTK_ENTRY(d->width)));
705 uint32_t height = atoi(gtk_entry_get_text(GTK_ENTRY(d->height)));
706 if(width > d->max_allowed_width || height > d->max_allowed_height)
707 {
708 width = width > d->max_allowed_width ? dt_conf_get_int(CONFIG_PREFIX "width") : width;
709 height = height > d->max_allowed_height ? dt_conf_get_int(CONFIG_PREFIX "height") : height;
711 }
712}
713
715{
716 uint32_t max_w = 0, max_h = 0;
717 _get_max_output_dimension(d, &max_w, &max_h);
718 d->max_allowed_width = max_w > 0 ? max_w : EXPORT_MAX_IMAGE_SIZE;
719 d->max_allowed_height = max_h > 0 ? max_h : EXPORT_MAX_IMAGE_SIZE;
721}
722
723static void set_storage_by_name(dt_lib_export_t *d, const char *name)
724{
725 int k = -1;
726 dt_imageio_module_storage_t *module = NULL;
727
728 for(const GList *it = darktable.imageio->plugins_storage; it; it = g_list_next(it))
729 {
731 k++;
732 if(strcmp(storage->name(storage), name) == 0 || strcmp(storage->plugin_name, name) == 0)
733 {
734 module = storage;
735 break;
736 }
737 }
738
739 if(!module)
740 {
741 gtk_widget_hide(d->storage_extra_container);
742 return;
743 }
744 else if(module->widget)
745 {
746 gtk_widget_show_all(d->storage_extra_container);
747 gtk_stack_set_visible_child(GTK_STACK(d->storage_extra_container),module->widget);
748 }
749 else
750 {
751 gtk_widget_hide(d->storage_extra_container);
752 }
753 dt_bauhaus_combobox_set(d->storage, k);
754 dt_conf_set_string(CONFIG_PREFIX "storage_name", module->plugin_name);
755
756
757 // Check if plugin recommends a max dimension and set
758 // if not implemented the stored conf values are used..
759 uint32_t w = 0, h = 0;
760 module->recommended_dimension(module, NULL, &w, &h);
761
762 const uint32_t cw = dt_conf_get_int(CONFIG_PREFIX "width");
763 const uint32_t ch = dt_conf_get_int(CONFIG_PREFIX "height");
764
765 // If user's selected value is below the max, select it
766 if(w > cw || w == 0) w = cw;
767 if(h > ch || h == 0) h = ch;
768
769 // Set the recommended dimension
770 _set_dimensions(d, w, h);
771
772 // Let's update formats combobox with supported formats of selected storage module...
774
775 // Lets try to set selected format if fail select first in list..
776 const char *format_name = dt_conf_get_string_const(CONFIG_PREFIX "format_name");
778
779 if(IS_NULL_PTR(format)
780 || dt_bauhaus_combobox_set_from_text(d->format, format->name()) == FALSE)
781 dt_bauhaus_combobox_set(d->format, 0);
782}
783
785{
786 const gchar *name = dt_bauhaus_combobox_get_text(d->storage);
787 g_signal_handlers_block_by_func(widget, _storage_changed, d);
789 g_signal_handlers_unblock_by_func(widget, _storage_changed, d);
790}
791
793{
794 int pos = dt_bauhaus_combobox_get(widget);
795 if(pos > 0)
796 {
797 pos--;
798 for(GList *profiles = darktable.color_profiles->profiles; profiles; profiles = g_list_next(profiles))
799 {
801 if(pp->out_pos == pos)
802 {
803 dt_conf_set_int(CONFIG_PREFIX "icctype", pp->type);
804 if(pp->type == DT_COLORSPACE_FILE)
805 dt_conf_set_string(CONFIG_PREFIX "iccprofile", pp->filename);
806 else
807 dt_conf_set_string(CONFIG_PREFIX "iccprofile", "");
808 return;
809 }
810 }
811 }
813 dt_conf_set_string(CONFIG_PREFIX "iccprofile", "");
814}
815
817{
818 if(darktable.gui->reset) return;
819
821
822 dt_conf_set_int(CONFIG_PREFIX "dimensions_type", d_type);
824 d_type == DT_DIMENSIONS_SCALE ? "scaling" : "max_size");
825
826 if(d_type == DT_DIMENSIONS_CM || d_type == DT_DIMENSIONS_INCH)
827 {
828 // set dpi to user-set dpi
829 dt_conf_set_int("metadata/resolution", dt_conf_get_int(CONFIG_PREFIX "print_dpi"));
831 }
832 else
833 {
834 // reset export dpi to default value for scale/pixel specific export
835 dt_conf_set_int("metadata/resolution", dt_confgen_get_int("metadata/resolution", DT_DEFAULT));
836 }
837
838 if(d_type == DT_DIMENSIONS_ORIGINAL)
839 {
840 // The "same as original" is really just an user-friendly alias
841 // for size = 0x0 pixels, which we read as "full size"
842 dt_conf_set_int(CONFIG_PREFIX "width", 0);
843 dt_conf_set_int(CONFIG_PREFIX "height", 0);
844 dt_conf_set_string(CONFIG_PREFIX "resizing_factor", "1");
845 }
846
848}
849
851{
852 if(darktable.gui->reset) return;
853
854 const uint32_t width = dt_conf_get_int(CONFIG_PREFIX "width");
855 const uint32_t height = dt_conf_get_int(CONFIG_PREFIX "height");
856 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(self->print_dpi)));
857
858 const float p_width = pixels2print(self, width);
859 const float p_height = pixels2print(self, height);
860
862 gchar *pwidth = g_strdup_printf("%.2f", p_width);
863 gchar *pheight = g_strdup_printf("%.2f", p_height);
864 gchar *pdpi = g_strdup_printf("%d", dpi);
865 gtk_entry_set_text(GTK_ENTRY(self->print_width), pwidth);
866 gtk_entry_set_text(GTK_ENTRY(self->print_height), pheight);
867 gtk_entry_set_text(GTK_ENTRY(self->print_dpi), pdpi);
868 dt_free(pwidth);
869 dt_free(pheight);
870 dt_free(pdpi);
872}
873
875{
876 if(darktable.gui->reset) return;
877
878 const float p_width = atof(gtk_entry_get_text(GTK_ENTRY(self->print_width)));
879 const float p_height = atof(gtk_entry_get_text(GTK_ENTRY(self->print_height)));
880
881 const uint32_t width = print2pixels(self, p_width);
882 const uint32_t height = print2pixels(self, p_height);
883
886
888 gchar *pwidth = g_strdup_printf("%d", width);
889 gchar *pheight = g_strdup_printf("%d", height);
890 gtk_entry_set_text(GTK_ENTRY(self->width), pwidth);
891 gtk_entry_set_text(GTK_ENTRY(self->height), pheight);
892 dt_free(pwidth);
893 dt_free(pheight);
895}
896
897static void _width_changed(GtkEditable *entry, gpointer user_data)
898{
899 if(darktable.gui->reset) return;
900
901 const dt_lib_export_t *d = (dt_lib_export_t *)user_data;
902 const uint32_t width = atoi(gtk_entry_get_text(GTK_ENTRY(d->width)));
904}
905
906static void _print_width_changed(GtkEditable *entry, gpointer user_data)
907{
908 if(darktable.gui->reset) return;
909
910 dt_lib_export_t *d = (dt_lib_export_t *)user_data;
911
912 const float p_width = atof(gtk_entry_get_text(GTK_ENTRY(d->print_width)));
913 const uint32_t width = print2pixels(d, p_width);
915
917 gchar *pwidth = g_strdup_printf("%d", width);
918 gtk_entry_set_text(GTK_ENTRY(d->width), pwidth);
919 dt_free(pwidth);
922}
923
924static void _height_changed(GtkEditable *entry, gpointer user_data)
925{
926 if(darktable.gui->reset) return;
927
928 const dt_lib_export_t *d = (dt_lib_export_t *)user_data;
929 const uint32_t height = atoi(gtk_entry_get_text(GTK_ENTRY(d->height)));
931}
932
933static void _print_height_changed(GtkEditable *entry, gpointer user_data)
934{
935 if(darktable.gui->reset) return;
936
937 dt_lib_export_t *d = (dt_lib_export_t *)user_data;
938
939 const float p_height = atof(gtk_entry_get_text(GTK_ENTRY(d->print_height)));
940 const uint32_t height = print2pixels(d, p_height);
942
944 gchar *pheight = g_strdup_printf("%d", height);
945 gtk_entry_set_text(GTK_ENTRY(d->height), pheight);
946 dt_free(pheight);
949}
950
951static void _print_dpi_changed(GtkWidget *widget, gpointer user_data)
952{
953 if(darktable.gui->reset) return;
954
955 dt_lib_export_t *d = (dt_lib_export_t *)user_data;
956 const int dpi = atoi(gtk_entry_get_text(GTK_ENTRY(d->print_dpi)));
957
958 dt_conf_set_int(CONFIG_PREFIX "print_dpi", dpi);
959 dt_conf_set_int("metadata/resolution", dpi);
960
963}
964
965static void _callback_bool(GtkWidget *widget, gpointer user_data)
966{
967 const char *key = (const char *)user_data;
969}
970
972{
973 const int pos = dt_bauhaus_combobox_get(widget);
974 dt_conf_set_int(CONFIG_PREFIX "iccintent", pos - 1);
975}
976
978{
979 if(dt_bauhaus_combobox_get(d->style) == 0)
980 {
982 }
983 else
984 {
985 const gchar *style = dt_bauhaus_combobox_get_text(d->style);
986 dt_conf_set_string(CONFIG_PREFIX "style", style);
987 }
988}
989
991{
992 return 99;
993}
994
996{
997 // Clear format combo box
999
1000 // Get current selected storage
1001 const char *storage_name = dt_conf_get_string_const(CONFIG_PREFIX "storage_name");
1003
1004 // Add supported formats to combobox
1005 gboolean empty = TRUE;
1006 for(const GList *it = darktable.imageio->plugins_format; it; it = g_list_next(it))
1007 {
1009 if(storage->supported(storage, format))
1010 {
1011 dt_bauhaus_combobox_add(d->format, format->name());
1012 empty = FALSE;
1013 }
1014 }
1015
1016 gtk_widget_set_sensitive(GTK_WIDGET(d->format), !empty);
1017}
1018
1019static void _on_storage_list_changed(gpointer instance, dt_lib_module_t *self)
1020{
1021 dt_lib_export_t *d = self->data;
1023 dt_bauhaus_combobox_clear(d->storage);
1024
1025 dt_gui_container_remove_children(GTK_CONTAINER(d->storage_extra_container));
1026
1027 for(const GList *it = darktable.imageio->plugins_storage; it; it = g_list_next(it))
1028 {
1029 const dt_imageio_module_storage_t *module = (dt_imageio_module_storage_t *)it->data;
1030 dt_bauhaus_combobox_add(d->storage, module->name(module));
1031 if(module->widget)
1032 {
1033 gtk_container_add(GTK_CONTAINER(d->storage_extra_container), module->widget);
1034 }
1035 }
1037}
1038
1039static void _lib_export_styles_changed_callback(gpointer instance, gpointer user_data)
1040{
1041 dt_lib_module_t *self = (dt_lib_module_t *)user_data;
1042 dt_lib_export_t *d = self->data;
1043
1045 dt_bauhaus_combobox_add(d->style, _("none"));
1046
1047 GList *styles = dt_styles_get_list("");
1048 for(const GList *st_iter = styles; st_iter; st_iter = g_list_next(st_iter))
1049 {
1050 const dt_style_t *style = (dt_style_t *)st_iter->data;
1051 dt_bauhaus_combobox_add(d->style, style->name);
1052 }
1053 dt_bauhaus_combobox_set(d->style, 0);
1054
1055 g_list_free_full(styles, dt_style_free);
1056 styles = NULL;
1057}
1058
1059void _menuitem_preferences(GtkMenuItem *menuitem, dt_lib_module_t *self)
1060{
1062 const gchar *name = dt_bauhaus_combobox_get_text(d->storage);
1063 const gboolean ondisk = name && !g_strcmp0(name, _("file on disk")); // FIXME: NO!!!!!one!
1064 d->metadata_export = dt_lib_export_metadata_configuration_dialog(d->metadata_export, ondisk);
1065}
1066
1067void set_preferences(void *menu, dt_lib_module_t *self)
1068{
1069 GtkWidget *mi = gtk_menu_item_new_with_label(_("preferences..."));
1070 g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(_menuitem_preferences), self);
1071 gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
1072}
1073
1075{
1076 dt_lib_export_t *d = (dt_lib_export_t *)malloc(sizeof(dt_lib_export_t));
1077 self->timeout_handle = 0;
1078 self->data = (void *)d;
1079 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
1080
1081 GtkWidget *label = dt_ui_section_label_new(_("Storage options"));
1082 gtk_box_pack_start(GTK_BOX(self->widget), label, FALSE, TRUE, 0);
1083
1085 dt_bauhaus_widget_set_label(d->storage, N_("Target storage"));
1086 gtk_box_pack_start(GTK_BOX(self->widget), d->storage, FALSE, TRUE, 0);
1087
1088 // add all storage widgets to the stack widget
1089 d->storage_extra_container = gtk_stack_new();
1090 gtk_stack_set_homogeneous(GTK_STACK(d->storage_extra_container),FALSE);
1091 gtk_box_pack_start(GTK_BOX(self->widget), d->storage_extra_container, FALSE, TRUE, 0);
1092 for(const GList *it = darktable.imageio->plugins_storage; it; it = g_list_next(it))
1093 {
1094 const dt_imageio_module_storage_t *module = (dt_imageio_module_storage_t *)it->data;
1095 dt_bauhaus_combobox_add(d->storage, module->name(module));
1096 if(module->widget)
1097 {
1098 gtk_container_add(GTK_CONTAINER(d->storage_extra_container), module->widget);
1099 }
1100 }
1101
1102 // postponed so we can do the two steps in one loop
1104 G_CALLBACK(_on_storage_list_changed), self);
1105 g_signal_connect(G_OBJECT(d->storage), "value-changed", G_CALLBACK(_storage_changed), (gpointer)d);
1106
1107 label = dt_ui_section_label_new(_("format options"));
1108 gtk_box_pack_start(GTK_BOX(self->widget), label, FALSE, TRUE, 0);
1109
1111 dt_bauhaus_widget_set_label(d->format, N_("file format"));
1112 gtk_box_pack_start(GTK_BOX(self->widget), d->format, FALSE, TRUE, 0);
1113 g_signal_connect(G_OBJECT(d->format), "value-changed", G_CALLBACK(_format_changed), (gpointer)d);
1114
1115 // add all format widgets to the stack widget
1116 d->format_extra_container = gtk_stack_new();
1117 gtk_stack_set_homogeneous(GTK_STACK(d->format_extra_container),FALSE);
1118 gtk_box_pack_start(GTK_BOX(self->widget), d->format_extra_container, FALSE, TRUE, 0);
1119 for(const GList *it = darktable.imageio->plugins_format; it; it = g_list_next(it))
1120 {
1121 const dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)it->data;
1122 dt_bauhaus_combobox_add(d->format, module->name());
1123 if(module->widget)
1124 {
1125 gtk_container_add(GTK_CONTAINER(d->format_extra_container), module->widget);
1126 }
1127 }
1128
1129 label = dt_ui_section_label_new(_("global options"));
1130 gtk_box_pack_start(GTK_BOX(self->widget), label, FALSE, TRUE, 0);
1131
1132 DT_BAUHAUS_COMBOBOX_NEW_FULL(darktable.bauhaus, d->dimensions_type, NULL, N_("set size (bounding box)"),
1133 _("Choose a method for setting the output size.\n"
1134 "The width and height specified define the bounding box\n"
1135 "in which the image will be proportionnaly fitted.\n"),
1136 dt_conf_get_int(CONFIG_PREFIX "dimensions_type"),
1137 (GtkCallback)_dimensions_type_changed, d,
1138 N_("in pixels (for file)"),
1139 N_("in cm (for print)"),
1140 N_("in inch (for print)"),
1141 N_("by scale (for file)"),
1142 N_("original resolution"));
1143
1144 d->print_width = gtk_entry_new();
1146 gtk_widget_set_tooltip_text(d->print_width, _("maximum output width limit.\n"
1147 "click middle mouse button to reset to 0."));
1148 gtk_entry_set_width_chars(GTK_ENTRY(d->print_width), 5);
1149 d->print_height = gtk_entry_new();
1151 gtk_widget_set_tooltip_text(d->print_height, _("maximum output height limit.\n"
1152 "click middle mouse button to reset to 0."));
1153 gtk_entry_set_width_chars(GTK_ENTRY(d->print_height), 5);
1154 d->print_dpi = gtk_entry_new();
1156 gtk_widget_set_tooltip_text(d->print_dpi, _("resolution in dot per inch"));
1157 gtk_entry_set_width_chars(GTK_ENTRY(d->print_dpi), 4);
1158 const char *dpi = dt_conf_get_string_const(CONFIG_PREFIX "print_dpi");
1159 gtk_entry_set_text(GTK_ENTRY(d->print_dpi), dpi);
1160
1161
1162 d->width = gtk_entry_new();
1164 gtk_widget_set_tooltip_text(d->width, _("maximum output width limit.\n"
1165 "click middle mouse button to reset to 0."));
1166 gtk_entry_set_width_chars(GTK_ENTRY(d->width), 5);
1167 d->height = gtk_entry_new();
1169 gtk_widget_set_tooltip_text(d->height, _("maximum output height limit.\n"
1170 "click middle mouse button to reset to 0."));
1171 gtk_entry_set_width_chars(GTK_ENTRY(d->height), 5);
1172
1173 gtk_widget_add_events(d->width, GDK_BUTTON_PRESS_MASK);
1174 gtk_widget_add_events(d->height, GDK_BUTTON_PRESS_MASK);
1175
1176
1177 d->print_size = gtk_flow_box_new();
1178 gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(d->print_size), 5);
1179 gtk_flow_box_set_column_spacing (GTK_FLOW_BOX(d->print_size), 3);
1180 gtk_container_add(GTK_CONTAINER(d->print_size), d->print_width);
1181 gtk_container_add(GTK_CONTAINER(d->print_size), gtk_label_new(_("x")));
1182 gtk_container_add(GTK_CONTAINER(d->print_size), d->print_height);
1183 d->unit_label = gtk_label_new(_("cm"));
1184 gtk_container_add(GTK_CONTAINER(d->print_size), d->unit_label);
1185 GtkBox *dpi_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1186 gtk_box_pack_start(dpi_box, gtk_label_new(_("@")), FALSE, FALSE, 0);
1187 gtk_box_pack_start(dpi_box, d->print_dpi, TRUE, TRUE, 0);
1188 gtk_box_pack_start(dpi_box, gtk_label_new(_("dpi")), FALSE, FALSE, 0);
1189 gtk_container_add(GTK_CONTAINER(d->print_size), GTK_WIDGET(dpi_box));
1190 gtk_container_foreach(GTK_CONTAINER(d->print_size), (GtkCallback)gtk_widget_set_can_focus, GINT_TO_POINTER(FALSE));
1191
1192 d->px_size = gtk_flow_box_new();
1193 gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(d->px_size), 3);
1194 gtk_flow_box_set_column_spacing (GTK_FLOW_BOX(d->px_size), 3);
1195 gtk_container_add(GTK_CONTAINER(d->px_size), d->width);
1196 gtk_container_add(GTK_CONTAINER(d->px_size), gtk_label_new(_("x")));
1197 GtkBox *px_box = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1198 gtk_box_pack_start(px_box, d->height, TRUE, TRUE, 0);
1199 gtk_box_pack_start(px_box, gtk_label_new(_("px")), FALSE, FALSE, 0);
1200 gtk_container_add(GTK_CONTAINER(d->px_size), GTK_WIDGET(px_box));
1201 gtk_container_foreach(GTK_CONTAINER(d->px_size), (GtkCallback)gtk_widget_set_can_focus, GINT_TO_POINTER(FALSE));
1202
1203 d->scale = gtk_entry_new();
1205 gtk_entry_set_width_chars(GTK_ENTRY(d->scale), 5);
1206 gtk_entry_set_text (GTK_ENTRY(d->scale), dt_conf_get_string_const(CONFIG_PREFIX "resizing_factor"));
1207 gtk_widget_set_tooltip_text(d->scale, _("it can be an integer, decimal number or simple fraction.\n"
1208 "zero or empty values are equal to 1.\n"
1209 "click middle mouse button to reset to 1."));
1210 gtk_widget_set_halign(GTK_WIDGET(d->scale), GTK_ALIGN_END);
1211 gtk_widget_add_events(d->scale, GDK_BUTTON_PRESS_MASK);
1212
1213 d->size_in_px = gtk_label_new("");
1214 gtk_label_set_ellipsize(GTK_LABEL(d->size_in_px), PANGO_ELLIPSIZE_START);
1215 gtk_widget_set_sensitive(GTK_WIDGET(d->size_in_px), FALSE);
1216
1217 gtk_widget_set_halign(GTK_WIDGET(d->scale), GTK_ALIGN_FILL);
1218 gtk_widget_set_halign(GTK_WIDGET(d->size_in_px), GTK_ALIGN_END);
1219
1220 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->dimensions_type), FALSE, FALSE, 0);
1221 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->px_size), FALSE, FALSE, 0);
1222 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->print_size), FALSE, FALSE, 0);
1223 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->scale), FALSE, FALSE, 0);
1224 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(d->size_in_px), FALSE, FALSE, 0);
1225
1227 dt_bauhaus_widget_set_label(d->export_masks, N_("store masks"));
1228 dt_bauhaus_combobox_add(d->export_masks, _("no"));
1229 dt_bauhaus_combobox_add(d->export_masks, _("yes"));
1230 gtk_widget_set_tooltip_text(d->export_masks, _("store masks as layers in exported images. only works for some formats."));
1231 gtk_box_pack_start(GTK_BOX(self->widget), d->export_masks, FALSE, TRUE, 0);
1232
1233 // Add profile combo
1234
1235 char datadir[PATH_MAX] = { 0 };
1236 char confdir[PATH_MAX] = { 0 };
1237 dt_loc_get_user_config_dir(confdir, sizeof(confdir));
1238 dt_loc_get_datadir(datadir, sizeof(datadir));
1239
1241 dt_bauhaus_widget_set_label(d->profile, N_("Color space"));
1242 gtk_box_pack_start(GTK_BOX(self->widget), d->profile, FALSE, TRUE, 0);
1243 dt_bauhaus_combobox_add(d->profile, _("same as original"));
1244 for(GList *l = darktable.color_profiles->profiles; l; l = g_list_next(l))
1245 {
1247 if(prof->out_pos > -1)
1248 dt_bauhaus_combobox_add(d->profile, prof->name);
1249 }
1250
1251 dt_bauhaus_combobox_set(d->profile, 1);
1252
1253 char *system_profile_dir = g_build_filename(datadir, "color", "out", NULL);
1254 char *user_profile_dir = g_build_filename(confdir, "color", "out", NULL);
1255 char *tooltip = g_strdup_printf(_(
1256 "RGB color space used to encode the output files.\n"
1257 "\"same as original\" exports to the same space as the original\n"
1258 "picture, which is linear sensor RGB for raw pictures.\n"
1259 "sRGB is recommended in most cases.\n"
1260 "You can use custom color spaces defined\n"
1261 "by ICC profiles stored in:\n- %s\n- %s"), user_profile_dir, system_profile_dir);
1262 gtk_widget_set_tooltip_text(d->profile, tooltip);
1263 dt_free(system_profile_dir);
1264 dt_free(user_profile_dir);
1266
1267 // Add intent combo
1268
1270 dt_bauhaus_widget_set_label(d->intent, N_("intent"));
1271 dt_bauhaus_combobox_add(d->intent, _("same as original"));
1272 dt_bauhaus_combobox_add(d->intent, _("perceptual"));
1273 dt_bauhaus_combobox_add(d->intent, _("relative colorimetric"));
1274 dt_bauhaus_combobox_add(d->intent, C_("rendering intent", "saturation"));
1275 dt_bauhaus_combobox_add(d->intent, _("absolute colorimetric"));
1276 gtk_box_pack_start(GTK_BOX(self->widget), d->intent, FALSE, TRUE, 0);
1277
1278 tooltip = g_strdup_printf(_("• perceptual: "
1279 "smoothly moves out-of-gamut colors into gamut,"
1280 "preserving gradations, but distorts in-gamut colors in the process."
1281 " note that perceptual is often a proprietary LUT that depends"
1282 " on the destination space."
1283 "\n\n"
1284
1285 "• relative colorimetric: "
1286 "keeps luminance while reducing as little as possible saturation"
1287 " until colors fit in gamut."
1288 "\n\n"
1289
1290 "• saturation: "
1291 "designed to present eye-catching business graphics"
1292 " by preserving the saturation. (not suited for photography)."
1293 "\n\n"
1294
1295 "• absolute colorimetric: "
1296 "adapt white point of the image to the white point of the"
1297 " destination medium and do nothing else. mainly used when"
1298 " proofing colors. (not suited for photography)."
1299 ""
1300 ));
1301 gtk_widget_set_tooltip_text(d->intent, tooltip);
1303
1304 // Add style combo
1305
1307 dt_bauhaus_widget_set_label(d->style, N_("style"));
1309 gtk_box_pack_start(GTK_BOX(self->widget), d->style, FALSE, TRUE, 0);
1310 gtk_widget_set_tooltip_text(d->style, _("temporary style to use while exporting"));
1311
1312 // Set callback signals
1313 g_signal_connect(G_OBJECT(d->export_masks), "value-changed", G_CALLBACK(_callback_bool),
1314 (gpointer)CONFIG_PREFIX "export_masks");
1315 g_signal_connect(G_OBJECT(d->intent), "value-changed", G_CALLBACK(_intent_changed), (gpointer)d);
1316 g_signal_connect(G_OBJECT(d->profile), "value-changed", G_CALLBACK(_profile_changed), (gpointer)d);
1317 g_signal_connect(G_OBJECT(d->style), "value-changed", G_CALLBACK(_style_changed), (gpointer)d);
1318
1320 G_CALLBACK(_lib_export_styles_changed_callback), self);
1321
1322 GtkBox *hbox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING));
1323 gtk_box_pack_start(GTK_BOX(self->widget), GTK_WIDGET(hbox), FALSE, TRUE, 0);
1324
1325 // Export button
1326 d->export_button = GTK_BUTTON(dt_action_button_new(self, N_("export"), _export_button_clicked, d,
1327 _("export with current settings"), GDK_KEY_e, GDK_CONTROL_MASK));
1328 gtk_box_pack_start(hbox, GTK_WIDGET(d->export_button), TRUE, TRUE, 0);
1329
1330 g_signal_connect(G_OBJECT(d->width), "changed", G_CALLBACK(_width_changed), (gpointer)d);
1331 g_signal_connect(G_OBJECT(d->height), "changed", G_CALLBACK(_height_changed), (gpointer)d);
1332 g_signal_connect(G_OBJECT(d->print_width), "changed", G_CALLBACK(_print_width_changed), (gpointer)d);
1333 g_signal_connect(G_OBJECT(d->print_height), "changed", G_CALLBACK(_print_height_changed), (gpointer)d);
1334 g_signal_connect(G_OBJECT(d->print_dpi), "changed", G_CALLBACK(_print_dpi_changed), (gpointer)d);
1335
1336 g_signal_connect(G_OBJECT(d->width), "changed", G_CALLBACK(_width_changed), (gpointer)d);
1337 g_signal_connect(G_OBJECT(d->height), "changed", G_CALLBACK(_height_changed), (gpointer)d);
1338
1339 g_signal_connect(G_OBJECT(d->width), "button-press-event", G_CALLBACK(_widht_mdlclick), (gpointer)d);
1340 g_signal_connect(G_OBJECT(d->height), "button-press-event", G_CALLBACK(_height_mdlclick), (gpointer)d);
1341 g_signal_connect(G_OBJECT(d->print_width), "button-press-event", G_CALLBACK(_widht_mdlclick), (gpointer)d);
1342 g_signal_connect(G_OBJECT(d->print_height), "button-press-event", G_CALLBACK(_height_mdlclick), (gpointer)d);
1343
1344 g_signal_connect(G_OBJECT(d->scale), "button-press-event", G_CALLBACK(_scale_mdlclick), (gpointer)d);
1345 g_signal_connect(G_OBJECT(d->scale), "changed", G_CALLBACK(_scale_changed), (gpointer)d);
1346
1347 // this takes care of keeping hidden widgets hidden
1348 gtk_widget_show_all(self->widget);
1349 gtk_widget_set_no_show_all(self->widget, TRUE);
1350
1351 const char* setting = dt_conf_get_string_const(CONFIG_PREFIX "width");
1352 gtk_entry_set_text(GTK_ENTRY(d->width), setting);
1353 setting = dt_conf_get_string_const(CONFIG_PREFIX "height");
1354 gtk_entry_set_text(GTK_ENTRY(d->height), setting);
1355
1357
1358 // Set storage
1359 setting = dt_conf_get_string_const(CONFIG_PREFIX "storage_name");
1360 const int storage_index = dt_imageio_get_index_of_storage(dt_imageio_get_storage_by_name(setting));
1361 dt_bauhaus_combobox_set(d->storage, storage_index);
1362
1363 // Set format
1364 setting = dt_conf_get_string_const(CONFIG_PREFIX "format_name");
1365 const int format_index = dt_imageio_get_index_of_format(dt_imageio_get_format_by_name(setting));
1366 dt_bauhaus_combobox_set(d->format, format_index);
1367
1368 dt_bauhaus_combobox_set(d->export_masks, dt_conf_get_bool(CONFIG_PREFIX "export_masks") ? 1 : 0);
1369
1370 dt_bauhaus_combobox_set(d->intent, dt_conf_get_int(CONFIG_PREFIX "iccintent") + 1);
1371
1372 // iccprofile
1373 const int icctype = dt_conf_get_int(CONFIG_PREFIX "icctype");
1374 gchar *iccfilename = dt_conf_get_string(CONFIG_PREFIX "iccprofile");
1375 dt_bauhaus_combobox_set(d->profile, 0);
1376
1377 if(icctype != DT_COLORSPACE_NONE)
1378 {
1379 for(GList *profiles = darktable.color_profiles->profiles; profiles; profiles = g_list_next(profiles))
1380 {
1382 if(pp->out_pos > -1
1383 && icctype == pp->type
1384 && (icctype != DT_COLORSPACE_FILE || !strcmp(iccfilename, pp->filename)))
1385 {
1386 dt_bauhaus_combobox_set(d->profile, pp->out_pos + 1);
1387 break;
1388 }
1389 }
1390 }
1391
1392 dt_free(iccfilename);
1393
1394 // style
1395 // set it to none if the var is not set or the style doesn't exist anymore
1396 gboolean rc = FALSE;
1397 setting = dt_conf_get_string_const(CONFIG_PREFIX "style");
1398 if(!IS_NULL_PTR(setting) && strlen(setting) > 0)
1399 {
1400 rc = dt_bauhaus_combobox_set_from_text(d->style, setting);
1401 if(rc == FALSE)
1402 dt_bauhaus_combobox_set(d->style, 0);
1403 }
1404 else
1405 dt_bauhaus_combobox_set(d->style, 0);
1406
1407 // export metadata presets
1408 d->metadata_export = dt_lib_export_metadata_get_conf();
1409
1411 G_CALLBACK(_image_selection_changed_callback), self);
1413 G_CALLBACK(_collection_updated_callback), self);
1414}
1415
1417{
1418 if(IS_NULL_PTR(self->data)) return;
1421
1424
1427
1428 for(const GList *it = darktable.imageio->plugins_storage; it; it = g_list_next(it))
1429 {
1430 dt_imageio_module_storage_t *module = (dt_imageio_module_storage_t *)it->data;
1431 if(module->widget && GTK_IS_CONTAINER(d->storage_extra_container)) gtk_container_remove(GTK_CONTAINER(d->storage_extra_container), module->widget);
1432 }
1433
1434 for(const GList *it = darktable.imageio->plugins_format; it; it = g_list_next(it))
1435 {
1436 dt_imageio_module_format_t *module = (dt_imageio_module_format_t *)it->data;
1437 if(module->widget && GTK_IS_CONTAINER(d->format_extra_container)) gtk_container_remove(GTK_CONTAINER(d->format_extra_container), module->widget);
1438 }
1439
1441 {
1442 sqlite3_finalize(_export_presets_stmt);
1443 _export_presets_stmt = NULL;
1444 }
1445
1446 dt_free(d->metadata_export);
1447
1448 dt_free(self->data);
1449}
1450
1452{
1453 // TODO: store presets in db:
1454 // dt_lib_presets_add(const char *name, const char *plugin_name, const void *params, const int32_t
1455 // params_size)
1456
1457
1458 // I know that it is super ugly to have this inside a module, but then is export not your average module
1459 // since it handles the params blobs of imageio libs.
1460 // - get all existing presets for export from db,
1461 // - extract the versions of the embedded format/storage blob
1462 // - check if it's up to date
1463 // - if older than the module -> call its legacy_params and update the preset
1464 // - drop presets that cannot be updated
1465
1466 const int version = self->version();
1467
1469 {
1472 "SELECT rowid, op_version, op_params, name FROM data.presets WHERE operation='export'", -1,
1473 &_export_presets_stmt, NULL);
1474 }
1475 sqlite3_stmt *stmt = _export_presets_stmt;
1476 sqlite3_reset(stmt);
1477 sqlite3_clear_bindings(stmt);
1478 while(sqlite3_step(stmt) == SQLITE_ROW)
1479 {
1480 const int rowid = sqlite3_column_int(stmt, 0);
1481 const int op_version = sqlite3_column_int(stmt, 1);
1482 const void *op_params = (void *)sqlite3_column_blob(stmt, 2);
1483 const size_t op_params_size = sqlite3_column_bytes(stmt, 2);
1484 const char *name = (char *)sqlite3_column_text(stmt, 3);
1485
1486 if(op_version != version)
1487 {
1488 // shouldn't happen, we run legacy_params on the lib level before calling this
1489 fprintf(stderr, "[export_init_presets] found export preset '%s' with version %d, version %d was "
1490 "expected. dropping preset.\n",
1491 name, op_version, version);
1492 sqlite3_stmt *innerstmt;
1494 "DELETE FROM data.presets WHERE rowid=?1", -1,
1495 &innerstmt, NULL);
1496 DT_DEBUG_SQLITE3_BIND_INT(innerstmt, 1, rowid);
1497 sqlite3_step(innerstmt);
1498 sqlite3_finalize(innerstmt);
1499 }
1500 else
1501 {
1502 // extract the interesting parts from the blob
1503 const char *buf = (const char *)op_params;
1504
1505 // skip 6*int32_t: max_width, max_height, upscale, high_quality and iccintent, icctype
1506 buf += 6 * sizeof(int32_t);
1507 // skip metadata presets string
1508 buf += strlen(buf) + 1;
1509 // next skip iccfilename
1510 buf += strlen(buf) + 1;
1511
1512 // parse both names to '\0'
1513 const char *fname = buf;
1514 buf += strlen(fname) + 1;
1515 const char *sname = buf;
1516 buf += strlen(sname) + 1;
1517
1518 // get module by name and skip if not there.
1521 if(!fmod || !smod) continue;
1522
1523 // next we have fversion, sversion, fsize, ssize, fdata, sdata which is the stuff that might change
1524 size_t copy_over_part = (void *)buf - (void *)op_params;
1525
1526 const int fversion = *(const int *)buf;
1527 buf += sizeof(int32_t);
1528 const int sversion = *(const int *)buf;
1529 buf += sizeof(int32_t);
1530 const int fsize = *(const int *)buf;
1531 buf += sizeof(int32_t);
1532 const int ssize = *(const int *)buf;
1533 buf += sizeof(int32_t);
1534
1535 const void *fdata = buf;
1536 buf += fsize;
1537 const void *sdata = buf;
1538
1539 void *new_fdata = NULL, *new_sdata = NULL;
1540 size_t new_fsize = fsize, new_ssize = ssize;
1541 const int32_t new_fversion = fmod->version(), new_sversion = smod->version();
1542
1543 if(fversion < new_fversion)
1544 {
1545 if(!(fmod->legacy_params
1546 && (new_fdata = fmod->legacy_params(fmod, fdata, fsize, fversion, new_fversion, &new_fsize))
1547 != NULL))
1548 goto delete_preset;
1549 }
1550
1551 if(sversion < new_sversion)
1552 {
1553 if(!(smod->legacy_params
1554 && (new_sdata = smod->legacy_params(smod, sdata, ssize, sversion, new_sversion, &new_ssize))
1555 != NULL))
1556 goto delete_preset;
1557 }
1558
1559 if(new_fdata || new_sdata)
1560 {
1561 // we got an updated blob -> reassemble the parts and update the preset
1562 const size_t new_params_size = op_params_size - (fsize + ssize) + (new_fsize + new_ssize);
1563 void *new_params = malloc(new_params_size);
1564 memcpy(new_params, op_params, copy_over_part);
1565 // next we have fversion, sversion, fsize, ssize, fdata, sdata which is the stuff that might change
1566 size_t pos = copy_over_part;
1567 memcpy((uint8_t *)new_params + pos, &new_fversion, sizeof(int32_t));
1568 pos += sizeof(int32_t);
1569 memcpy((uint8_t *)new_params + pos, &new_sversion, sizeof(int32_t));
1570 pos += sizeof(int32_t);
1571 memcpy((uint8_t *)new_params + pos, &new_fsize, sizeof(int32_t));
1572 pos += sizeof(int32_t);
1573 memcpy((uint8_t *)new_params + pos, &new_ssize, sizeof(int32_t));
1574 pos += sizeof(int32_t);
1575 if(new_fdata)
1576 memcpy((uint8_t *)new_params + pos, new_fdata, new_fsize);
1577 else
1578 memcpy((uint8_t *)new_params + pos, fdata, fsize);
1579 pos += new_fsize;
1580 if(new_sdata)
1581 memcpy((uint8_t *)new_params + pos, new_sdata, new_ssize);
1582 else
1583 memcpy((uint8_t *)new_params + pos, sdata, ssize);
1584
1585 // write the updated preset back to db
1586 fprintf(stderr,
1587 "[export_init_presets] updating export preset '%s' from versions %d/%d to versions %d/%d\n",
1588 name, fversion, sversion, new_fversion, new_sversion);
1589 sqlite3_stmt *innerstmt;
1591 "UPDATE data.presets SET op_params=?1 WHERE rowid=?2",
1592 -1, &innerstmt, NULL);
1593 DT_DEBUG_SQLITE3_BIND_BLOB(innerstmt, 1, new_params, new_params_size, SQLITE_TRANSIENT);
1594 DT_DEBUG_SQLITE3_BIND_INT(innerstmt, 2, rowid);
1595 sqlite3_step(innerstmt);
1596 sqlite3_finalize(innerstmt);
1597
1598 dt_free(new_fdata);
1599 dt_free(new_sdata);
1600 dt_free(new_params);
1601 }
1602
1603 continue;
1604
1605 delete_preset:
1606 dt_free(new_fdata);
1607 dt_free(new_sdata);
1608 fprintf(stderr, "[export_init_presets] export preset '%s' can't be updated from versions %d/%d to "
1609 "versions %d/%d. dropping preset\n",
1610 name, fversion, sversion, new_fversion, new_sversion);
1611 sqlite3_stmt *innerstmt;
1613 "DELETE FROM data.presets WHERE rowid=?1", -1,
1614 &innerstmt, NULL);
1615 DT_DEBUG_SQLITE3_BIND_INT(innerstmt, 1, rowid);
1616 sqlite3_step(innerstmt);
1617 sqlite3_finalize(innerstmt);
1618 }
1619 }
1620 sqlite3_reset(stmt);
1621 sqlite3_clear_bindings(stmt);
1622}
1623
1624void *legacy_params(dt_lib_module_t *self, const void *const old_params, const size_t old_params_size,
1625 const int old_version, int *new_version, size_t *new_size)
1626{
1627 if(old_version == 1)
1628 {
1629 // add version of format & storage to params
1630 const size_t new_params_size = old_params_size + 2 * sizeof(int32_t);
1631 void *new_params = malloc(new_params_size);
1632
1633 const char *buf = (const char *)old_params;
1634
1635 // skip 3*int32_t: max_width, max_height and iccintent
1636 buf += 3 * sizeof(int32_t);
1637 // next skip iccprofile
1638 buf += strlen(buf) + 1;
1639
1640 // parse both names to '\0'
1641 const char *fname = buf;
1642 buf += strlen(fname) + 1;
1643 const char *sname = buf;
1644 buf += strlen(sname) + 1;
1645
1646 // get module by name and fail if not there.
1649 if(!fmod || !smod)
1650 {
1651 dt_free(new_params);
1652 return NULL;
1653 }
1654
1655 // now we are just behind the module/storage names and before their param sizes. this is the place where
1656 // we want their versions
1657 // copy everything until here to the new params
1658 size_t first_half = (void *)buf - (void *)old_params;
1659 memcpy(new_params, old_params, first_half);
1660 // add the versions. at the time this code was added all modules were at version 1, except of picasa which was at 2.
1661 // every newer version of the imageio modules should result in a preset that is not going through this code.
1662 int32_t fversion = 1;
1663 int32_t sversion = (strcmp(sname, "picasa") == 0 ? 2 : 1);
1664 memcpy((uint8_t *)new_params + first_half, &fversion, sizeof(int32_t));
1665 memcpy((uint8_t *)new_params + first_half + sizeof(int32_t), &sversion, sizeof(int32_t));
1666 // copy the rest of the old params over
1667 memcpy((uint8_t *)new_params + first_half + sizeof(int32_t) * 2, buf, old_params_size - first_half);
1668
1669 *new_size = new_params_size;
1670 *new_version = 2;
1671 return new_params;
1672 }
1673 else if(old_version == 2)
1674 {
1675 // add upscale to params
1676 const size_t new_params_size = old_params_size + sizeof(int32_t);
1677 void *new_params = calloc(1, new_params_size);
1678
1679 memcpy(new_params, old_params, sizeof(int32_t) * 2);
1680 memcpy((uint8_t *)new_params + sizeof(int32_t) * 3, (uint8_t *)old_params + sizeof(int32_t) * 2, old_params_size - sizeof(int32_t) * 2);
1681
1682 *new_size = new_params_size;
1683 *new_version = 3;
1684 return new_params;
1685 }
1686 else if(old_version == 3)
1687 {
1688 // replace iccprofile by type + filename
1689 // format of v3:
1690 // - 4 x int32_t (max_width, max_height, upscale, iccintent)
1691 // - char* (iccprofile)
1692 // - rest
1693 // format of v4:
1694 // - 5 x int32_t (max_width, max_height, upscale, iccintent, icctype)
1695 // - char* (iccfilename)
1696 // - old rest
1697
1698 const char *buf = (const char *)old_params;
1699
1700 // first get the old iccprofile to find out how big our new blob has to be
1701 const char *iccprofile = buf + 4 * sizeof(int32_t);
1702
1703 size_t new_params_size = old_params_size - strlen(iccprofile) + sizeof(int32_t);
1704 int icctype;
1705 const char *iccfilename = "";
1706
1707 if(!strcmp(iccprofile, "image"))
1708 icctype = DT_COLORSPACE_NONE;
1709 else if(!strcmp(iccprofile, "sRGB"))
1710 icctype = DT_COLORSPACE_SRGB;
1711 else if(!strcmp(iccprofile, "linear_rec709_rgb") || !strcmp(iccprofile, "linear_rgb"))
1712 icctype = DT_COLORSPACE_LIN_REC709;
1713 else if(!strcmp(iccprofile, "linear_rec2020_rgb"))
1714 icctype = DT_COLORSPACE_LIN_REC2020;
1715 else if(!strcmp(iccprofile, "adobergb"))
1716 icctype = DT_COLORSPACE_ADOBERGB;
1717 else
1718 {
1719 icctype = DT_COLORSPACE_FILE;
1720 iccfilename = iccprofile;
1721 new_params_size += strlen(iccfilename);
1722 }
1723
1724 void *new_params = calloc(1, new_params_size);
1725 size_t pos = 0;
1726 memcpy(new_params, old_params, sizeof(int32_t) * 4);
1727 pos += 4 * sizeof(int32_t);
1728 memcpy((uint8_t *)new_params + pos, &icctype, sizeof(int32_t));
1729 pos += sizeof(int32_t);
1730 memcpy((uint8_t *)new_params + pos, iccfilename, strlen(iccfilename) + 1);
1731 pos += strlen(iccfilename) + 1;
1732 size_t old_pos = 4 * sizeof(int32_t) + strlen(iccprofile) + 1;
1733 memcpy((uint8_t *)new_params + pos, (uint8_t *)old_params + old_pos, old_params_size - old_pos);
1734
1735 *new_size = new_params_size;
1736 *new_version = 4;
1737 return new_params;
1738 }
1739 else if(old_version == 4)
1740 {
1741 // add high_quality to params
1742
1743 // format of v4:
1744 // - 5 x int32_t (max_width, max_height, upscale, iccintent, icctype)
1745 // - char* (iccfilename)
1746 // - old rest
1747 // format of v5:
1748 // - 6 x int32_t (max_width, max_height, upscale, high_quality, iccintent, icctype)
1749 // - char* (iccfilename)
1750 // - old rest
1751
1752 const size_t new_params_size = old_params_size + sizeof(int32_t);
1753 void *new_params = calloc(1, new_params_size);
1754
1755 size_t pos = 0;
1756 memcpy(new_params, old_params, sizeof(int32_t) * 3);
1757 pos += 4 * sizeof(int32_t);
1758 memcpy((uint8_t *)new_params + pos, (uint8_t *)old_params + pos - sizeof(int32_t), old_params_size - sizeof(int32_t) * 3);
1759
1760 *new_size = new_params_size;
1761 *new_version = 5;
1762 return new_params;
1763 }
1764 else if(old_version == 5)
1765 {
1766 // add metadata preset string
1767
1768 // format of v5:
1769 // - 6 x int32_t (max_width, max_height, upscale, high_quality, iccintent, icctype)
1770 // - char* (iccfilename)
1771 // - old rest
1772 // format of v6:
1773 // - 6 x int32_t (max_width, max_height, upscale, high_quality, iccintent, icctype)
1774 // - char* (metadata_export)
1775 // - char* (iccfilename)
1776 // - old rest
1777
1778 const gboolean omit = dt_conf_get_bool("omit_tag_hierarchy");
1779 gchar *flags = g_strdup_printf("%x", dt_lib_export_metadata_default_flags() | (omit ? DT_META_OMIT_HIERARCHY : 0));
1780 const int flags_size = strlen(flags) + 1;
1781 const size_t new_params_size = old_params_size + flags_size;
1782 void *new_params = calloc(1, new_params_size);
1783 size_t pos = 0;
1784 memcpy(new_params, old_params, sizeof(int32_t) * 6);
1785 pos += 6 * sizeof(int32_t);
1786 memcpy((uint8_t *)new_params + pos, flags, flags_size);
1787 pos += flags_size;
1788 memcpy((uint8_t *)new_params + pos, (uint8_t *)old_params + pos - flags_size, old_params_size - sizeof(int32_t) * 6);
1789
1790 dt_free(flags);
1791 *new_size = new_params_size;
1792 *new_version = 6;
1793 return new_params;
1794 }
1795 else if(old_version == 6)
1796 {
1797 // add export_masks
1798
1799 // format of v6:
1800 // - 6 x int32_t (max_width, max_height, upscale, high_quality, iccintent, icctype)
1801 // - old rest
1802 // format of v7:
1803 // - 7 x int32_t (max_width, max_height, upscale, high_quality, export_masks, iccintent, icctype)
1804 // - old rest
1805
1806 const size_t new_params_size = old_params_size + sizeof(int32_t);
1807 void *new_params = calloc(1, new_params_size);
1808
1809 size_t pos = 0;
1810 memcpy(new_params, old_params, sizeof(int32_t) * 4);
1811 pos += 5 * sizeof(int32_t);
1812 memcpy((uint8_t *)new_params + pos, (uint8_t *)old_params + pos - sizeof(int32_t), old_params_size - sizeof(int32_t) * 4);
1813
1814 *new_size = new_params_size;
1815 *new_version = 7;
1816 return new_params;
1817 }
1818
1819 return NULL;
1820}
1821
1823{
1825 // concat storage and format, size is max + header
1828 if(IS_NULL_PTR(mformat) || IS_NULL_PTR(mstorage)) return NULL;
1829
1830 // size will be only as large as needed to remove random pointers from params (stored at the end).
1831 size_t fsize = mformat->params_size(mformat);
1832 dt_imageio_module_data_t *fdata = mformat->get_params(mformat);
1833 size_t ssize = mstorage->params_size(mstorage);
1834 void *sdata = mstorage->get_params(mstorage);
1835 const int32_t fversion = mformat->version();
1836 const int32_t sversion = mstorage->version();
1837 // we allow null pointers (plugin not ready for export in current state), and just don't copy back the
1838 // settings later:
1839 if(IS_NULL_PTR(sdata)) ssize = 0;
1840 if(IS_NULL_PTR(fdata)) fsize = 0;
1841 if(fdata)
1842 {
1843 // clean up format global params (need to set all bytes to reliably detect which preset is active).
1844 // we happen to want to set it all to 0
1845 memset(fdata, 0, sizeof(dt_imageio_module_data_t));
1846 }
1847
1848 // FIXME: also the web preset has to be applied twice to be known as preset! (other dimension magic going on
1849 // here?)
1850 // TODO: get this stuff from gui and not from conf, so it will be sanity-checked (you can never delete an
1851 // insane preset)?
1852 // also store icc profile/intent here.
1853 const int32_t iccintent = dt_conf_get_int(CONFIG_PREFIX "iccintent");
1854 const int32_t icctype = dt_conf_get_int(CONFIG_PREFIX "icctype");
1855 const int32_t max_width = dt_conf_get_int(CONFIG_PREFIX "width");
1856 const int32_t max_height = dt_conf_get_int(CONFIG_PREFIX "height");
1857 const int32_t upscale = FALSE;
1858 const int32_t high_quality = TRUE;
1859 const int32_t export_masks = dt_conf_get_bool(CONFIG_PREFIX "export_masks") ? 1 : 0;
1860 gchar *iccfilename = dt_conf_get_string(CONFIG_PREFIX "iccprofile");
1861 gchar *style = dt_conf_get_string(CONFIG_PREFIX "style");
1862 const char *metadata_export = d->metadata_export;
1863
1864 if(fdata)
1865 {
1866 g_strlcpy(fdata->style, style, sizeof(fdata->style));
1867 }
1868
1869 if(icctype != DT_COLORSPACE_FILE)
1870 {
1871 dt_free(iccfilename);
1872 }
1873
1874 if(!iccfilename) iccfilename = g_strdup("");
1875 if(IS_NULL_PTR(metadata_export)) metadata_export = g_strdup("");
1876
1877 const char *fname = mformat->plugin_name;
1878 const char *sname = mstorage->plugin_name;
1879 const int32_t fname_len = strlen(fname);
1880 const int32_t sname_len = strlen(sname);
1881
1882 *size = fname_len + sname_len + 2 + 4 * sizeof(int32_t) + fsize + ssize + 7 * sizeof(int32_t)
1883 + strlen(iccfilename) + 1 + strlen(metadata_export) + 1;
1884
1885 char *params = (char *)calloc(1, *size);
1886 int pos = 0;
1887 memcpy(params + pos, &max_width, sizeof(int32_t));
1888 pos += sizeof(int32_t);
1889 memcpy(params + pos, &max_height, sizeof(int32_t));
1890 pos += sizeof(int32_t);
1891 memcpy(params + pos, &upscale, sizeof(int32_t));
1892 pos += sizeof(int32_t);
1893 memcpy(params + pos, &high_quality, sizeof(int32_t));
1894 pos += sizeof(int32_t);
1895 memcpy(params + pos, &export_masks, sizeof(int32_t));
1896 pos += sizeof(int32_t);
1897 memcpy(params + pos, &iccintent, sizeof(int32_t));
1898 pos += sizeof(int32_t);
1899 memcpy(params + pos, &icctype, sizeof(int32_t));
1900 pos += sizeof(int32_t);
1901 memcpy(params + pos, metadata_export, strlen(metadata_export) + 1);
1902 pos += strlen(metadata_export) + 1;
1903 memcpy(params + pos, iccfilename, strlen(iccfilename) + 1);
1904 pos += strlen(iccfilename) + 1;
1905 memcpy(params + pos, fname, fname_len + 1);
1906 pos += fname_len + 1;
1907 memcpy(params + pos, sname, sname_len + 1);
1908 pos += sname_len + 1;
1909 memcpy(params + pos, &fversion, sizeof(int32_t));
1910 pos += sizeof(int32_t);
1911 memcpy(params + pos, &sversion, sizeof(int32_t));
1912 pos += sizeof(int32_t);
1913 memcpy(params + pos, &fsize, sizeof(int32_t));
1914 pos += sizeof(int32_t);
1915 memcpy(params + pos, &ssize, sizeof(int32_t));
1916 pos += sizeof(int32_t);
1917 if(!IS_NULL_PTR(fdata)) // otherwise fsize == 0, but clang doesn't like it ...
1918 {
1919 memcpy(params + pos, fdata, fsize);
1920 pos += fsize;
1921 }
1922 if(!IS_NULL_PTR(sdata)) // see above
1923 {
1924 memcpy(params + pos, sdata, ssize);
1925 pos += ssize;
1926 }
1927 g_assert(pos == *size);
1928
1929 dt_free(iccfilename);
1930 dt_free(style);
1931
1932 if(fdata) mformat->free_params(mformat, fdata);
1933 if(sdata) mstorage->free_params(mstorage, sdata);
1934 return params;
1935}
1936
1937int set_params(dt_lib_module_t *self, const void *params, int size)
1938{
1940 // apply these stored presets again (parse blob)
1941 const char *buf = (const char *)params;
1942
1943 const int max_width = *(const int *)buf;
1944 buf += sizeof(int32_t);
1945 const int max_height = *(const int *)buf;
1946 buf += sizeof(int32_t);
1947 // const int upscale = *(const int *)buf; // unused now
1948 buf += sizeof(int32_t);
1949 //const int high_quality = *(const int *)buf; // unused now
1950 buf += sizeof(int32_t);
1951 const int export_masks = *(const int *)buf;
1952 buf += sizeof(int32_t);
1953 const int iccintent = *(const int *)buf;
1954 buf += sizeof(int32_t);
1955 const int icctype = *(const int *)buf;
1956 buf += sizeof(int32_t);
1957 const char *metadata_export = buf;
1958 buf += strlen(metadata_export) + 1;
1959 dt_free(d->metadata_export);
1960 d->metadata_export = g_strdup(metadata_export);
1961 dt_lib_export_metadata_set_conf(d->metadata_export);
1962 const char *iccfilename = buf;
1963 buf += strlen(iccfilename) + 1;
1964
1965 // reverse these by setting the gui, not the conf vars!
1966 dt_bauhaus_combobox_set(d->intent, iccintent + 1);
1967
1968 dt_bauhaus_combobox_set(d->profile, 0);
1969 if(icctype != DT_COLORSPACE_NONE)
1970 {
1971 for(GList *iter = darktable.color_profiles->profiles; iter; iter = g_list_next(iter))
1972 {
1974 if(pp->out_pos > -1
1975 && icctype == pp->type
1976 && (icctype != DT_COLORSPACE_FILE || !strcmp(iccfilename, pp->filename)))
1977 {
1978 dt_bauhaus_combobox_set(d->profile, pp->out_pos + 1);
1979 break;
1980 }
1981 }
1982 }
1983
1984 // parse both names to '\0'
1985 const char *fname = buf;
1986 buf += strlen(fname) + 1;
1987 const char *sname = buf;
1988 buf += strlen(sname) + 1;
1989
1990 // get module by name and fail if not there.
1993 if(!fmod || !smod) return 1;
1994
1995 const int32_t fversion = *(const int32_t *)buf;
1996 buf += sizeof(int32_t);
1997 const int32_t sversion = *(const int32_t *)buf;
1998 buf += sizeof(int32_t);
1999
2000 const int fsize = *(const int *)buf;
2001 buf += sizeof(int32_t);
2002 const int ssize = *(const int *)buf;
2003 buf += sizeof(int32_t);
2004
2005 if(size
2006 != strlen(fname) + strlen(sname) + 2 + 4 * sizeof(int32_t) + fsize + ssize + 7 * sizeof(int32_t)
2007 + strlen(iccfilename) + 1 + strlen(metadata_export) + 1)
2008 return 1;
2009 if(fversion != fmod->version() || sversion != smod->version()) return 1;
2010
2011 const dt_imageio_module_data_t *fdata = (const dt_imageio_module_data_t *)buf;
2012
2013 if(fdata->style[0] == '\0')
2014 dt_bauhaus_combobox_set(d->style, 0);
2015 else
2017
2018 buf += fsize;
2019 const void *sdata = buf;
2020
2021 // switch modules
2022 set_storage_by_name(d, sname);
2023 set_format_by_name(d, fname);
2024
2025 // set dimensions after switching, to have new range ready.
2026 _set_dimensions(d, max_width, max_height);
2027 dt_bauhaus_combobox_set(d->export_masks, export_masks ? 1 : 0);
2028
2029 // propagate to modules
2030 int res = 0;
2031 if(ssize) res += smod->set_params(smod, sdata, ssize);
2032 if(fsize) res += fmod->set_params(fmod, fdata, fsize);
2033 return res;
2034}
2035
2036// clang-format off
2037// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
2038// vim: shiftwidth=2 expandtab tabstop=2 cindent
2039// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
2040// clang-format on
int dt_act_on_get_images_nb(const gboolean only_visible, const gboolean force)
Definition act_on.c:54
GList * dt_act_on_get_images()
Definition act_on.c:39
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_combobox_clear(GtkWidget *widget)
Definition bauhaus.c:2189
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
const char * dt_bauhaus_combobox_get_text(GtkWidget *widget)
Definition bauhaus.c:2162
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2301
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
Definition bauhaus.c:1653
GtkWidget * dt_bauhaus_combobox_new(dt_bauhaus_t *bh, dt_gui_module_t *self)
Definition bauhaus.c:1842
gboolean dt_bauhaus_combobox_set_from_text(GtkWidget *widget, const char *text)
Definition bauhaus.c:2311
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
#define DT_BAUHAUS_COMBOBOX_NEW_FULL(bauhaus, widget, action, label, tip, pos, callback, data,...)
Definition bauhaus.h:392
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
dt_collection_properties_t
Definition collection.h:107
dt_collection_change_t
Definition collection.h:147
static dt_colorspaces_color_profile_type_t sanitize_colorspaces(dt_colorspaces_color_profile_type_t colorspace)
dt_iop_color_intent_t
Definition colorspaces.h:63
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_ADOBERGB
Definition colorspaces.h:85
@ DT_COLORSPACE_FILE
Definition colorspaces.h:83
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
@ DT_COLORSPACE_NONE
Definition colorspaces.h:82
@ DT_COLORSPACE_LIN_REC2020
Definition colorspaces.h:87
@ DT_COLORSPACE_LIN_REC709
Definition colorspaces.h:86
char * key
char * name
@ DT_DEFAULT
Definition conf.h:96
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_int(const char *name, int val)
gboolean dt_confgen_get_bool(const char *name, dt_confgen_value_kind_t kind)
int dt_conf_get_int(const char *name)
int dt_confgen_get_int(const char *name, dt_confgen_value_kind_t kind)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
const char * dt_confgen_get(const char *name, dt_confgen_value_kind_t kind)
void dt_control_log(const char *msg,...)
Definition control.c:761
int dt_control_running()
Definition control.c:423
void dt_control_export(GList *imgid_list, int max_width, int max_height, int format_index, int storage_index, gboolean high_quality, gboolean export_masks, char *style, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, const gchar *metadata_export)
darktable_t darktable
Definition darktable.c:181
#define DT_MODULE(MODVER)
Definition darktable.h:140
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#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_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_INT(a, b, c)
Definition debug.h:115
static float pixels2cm(dt_lib_export_t *self, const uint32_t pix)
Definition export.c:133
static void _format_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:666
void gui_reset(dt_lib_module_t *self)
Definition export.c:544
static void _callback_bool(GtkWidget *widget, gpointer user_data)
Definition export.c:965
void _menuitem_preferences(GtkMenuItem *menuitem, dt_lib_module_t *self)
Definition export.c:1059
int set_params(dt_lib_module_t *self, const void *params, int size)
Definition export.c:1937
static void _update(dt_lib_module_t *self)
Definition export.c:214
static void _height_changed(GtkEditable *entry, gpointer user_data)
Definition export.c:924
#define INCH_TO_CM
Definition export.c:131
char * dt_lib_export_metadata_configuration_dialog(char *list, const gboolean ondisk)
static float pixels2inch(dt_lib_export_t *self, const uint32_t pix)
Definition export.c:139
static void _print_height_changed(GtkEditable *entry, gpointer user_data)
Definition export.c:933
void * get_params(dt_lib_module_t *self, int *size)
Definition export.c:1822
static float pixels2print(dt_lib_export_t *self, const uint32_t pix)
Definition export.c:177
void set_preferences(void *menu, dt_lib_module_t *self)
Definition export.c:1067
static void _intent_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:971
static uint32_t inch2pixels(dt_lib_export_t *self, const float inch)
Definition export.c:151
static void _scale_changed(GtkEntry *spin, dt_lib_export_t *d)
Definition export.c:383
static void _profile_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:792
static void _scale_optim()
Definition export.c:246
static void _print_width_changed(GtkEditable *entry, gpointer user_data)
Definition export.c:906
static gboolean _scale_mdlclick(GtkEntry *spin, GdkEventButton *event, dt_lib_export_t *d)
Definition export.c:447
static sqlite3_stmt * _export_presets_stmt
Definition export.c:83
void gui_cleanup(dt_lib_module_t *self)
Definition export.c:1416
static uint32_t print2pixels(dt_lib_export_t *self, const float value)
Definition export.c:157
static void _print_dpi_changed(GtkWidget *widget, gpointer user_data)
Definition export.c:951
dt_dimensions_type_t
Definition export.c:113
@ DT_DIMENSIONS_PIXELS
Definition export.c:114
@ DT_DIMENSIONS_ORIGINAL
Definition export.c:118
@ DT_DIMENSIONS_SCALE
Definition export.c:117
@ DT_DIMENSIONS_INCH
Definition export.c:116
@ DT_DIMENSIONS_CM
Definition export.c:115
static void _on_storage_list_changed(gpointer instance, dt_lib_module_t *self)
Definition export.c:1019
static void _dimensions_type_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:816
static void _style_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:977
static void set_format_by_name(dt_lib_export_t *d, const char *name)
Definition export.c:607
static void _validate_dimensions(dt_lib_export_t *d)
Definition export.c:701
void _size_update_display(dt_lib_export_t *self)
Definition export.c:531
#define EXPORT_MAX_IMAGE_SIZE
Definition export.c:92
static void _update_formats_combobox(dt_lib_export_t *d)
Definition export.c:995
void init_presets(dt_lib_module_t *self)
Definition export.c:1451
static void _update_dimensions(dt_lib_export_t *d)
Definition export.c:714
static void _resync_print_dimensions(dt_lib_export_t *self)
Definition export.c:850
static void _collection_updated_callback(gpointer instance, dt_collection_change_t query_change, dt_collection_properties_t changed_property, gpointer imgs, int next, dt_lib_module_t *self)
Definition export.c:234
static void _widht_mdlclick(GtkEntry *spin, GdkEventButton *event, gpointer user_data)
Definition export.c:463
uint32_t container(dt_lib_module_t *self)
Definition export.c:209
static void _height_mdlclick(GtkEntry *spin, GdkEventButton *event, gpointer user_data)
Definition export.c:478
#define CONFIG_PREFIX
Definition export.c:93
static void _size_in_px_update(dt_lib_export_t *d)
Definition export.c:493
static void _storage_changed(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:784
void _set_dimensions(dt_lib_export_t *d, uint32_t max_width, uint32_t max_height)
Definition export.c:511
static void _export_button_clicked(GtkWidget *widget, dt_lib_export_t *d)
Definition export.c:308
void gui_init(dt_lib_module_t *self)
Definition export.c:1074
int position()
Definition export.c:990
gboolean _is_int(double value)
Definition export.c:241
const char ** views(dt_lib_module_t *self)
Definition export.c:202
static void _image_selection_changed_callback(gpointer instance, dt_lib_module_t *self)
Definition export.c:229
void * legacy_params(dt_lib_module_t *self, const void *const old_params, const size_t old_params_size, const int old_version, int *new_version, size_t *new_size)
Definition export.c:1624
static uint32_t cm2pixels(dt_lib_export_t *self, const float cm)
Definition export.c:145
static void set_storage_by_name(dt_lib_export_t *d, const char *name)
Definition export.c:723
static void _width_changed(GtkEditable *entry, gpointer user_data)
Definition export.c:897
static void _get_max_output_dimension(dt_lib_export_t *d, uint32_t *width, uint32_t *height)
Definition export.c:674
static void _resync_pixel_dimensions(dt_lib_export_t *self)
Definition export.c:874
static void _lib_export_styles_changed_callback(gpointer instance, gpointer user_data)
Definition export.c:1039
void dt_loc_get_datadir(char *datadir, size_t bufsize)
void dt_loc_get_user_config_dir(char *configdir, size_t bufsize)
void dt_gui_container_remove_children(GtkContainer *container)
Definition gtk.c:2907
void dt_accels_disconnect_on_text_input(GtkWidget *widget)
Disconnects accels when a text or search entry gets the focus, and reconnects them when it looses it....
Definition gtk.c:3225
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
static GtkWidget * dt_ui_section_label_new(const gchar *str)
Definition gtk.h:451
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
#define DT_GUI_MODULE(x)
const char * tooltip
Definition image.h:251
dt_imageio_module_storage_t * dt_imageio_get_storage()
int dt_imageio_get_index_of_format(dt_imageio_module_format_t *format)
int dt_imageio_get_index_of_storage(dt_imageio_module_storage_t *storage)
gchar * dt_imageio_resizing_factor_get_and_parsing(double *num, double *denum)
dt_imageio_module_format_t * dt_imageio_get_format()
dt_imageio_module_format_t * dt_imageio_get_format_by_name(const char *name)
dt_imageio_module_storage_t * dt_imageio_get_storage_by_name(const char *name)
const float v
void dt_lib_cancel_postponed_update(dt_lib_module_t *mod)
Definition lib.c:1536
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
Definition lib.c:1563
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
char * dt_lib_export_metadata_get_conf(void)
uint32_t dt_lib_export_metadata_default_flags(void)
void dt_lib_export_metadata_set_conf(const char *metadata_presets)
@ DT_META_OMIT_HIERARCHY
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
void dt_osx_disallow_fullscreen(GtkWidget *widget)
Definition osx.mm:104
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
Definition signal.h:368
@ DT_SIGNAL_STYLE_CHANGED
This signal is raised when a style is added/deleted/changed
Definition signal.h:147
@ DT_SIGNAL_IMAGEIO_STORAGE_CHANGE
This signal is raised when a new storage module is loaded noparameters no return.
Definition signal.h:267
@ DT_SIGNAL_SELECTION_CHANGED
This signal is raised when the selection is changed no param, no returned value.
Definition signal.h:127
@ DT_SIGNAL_COLLECTION_CHANGED
This signal is raised when collection changed. To avoid leaking the list, dt_collection_t is connecte...
Definition signal.h:122
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
Definition signal.h:357
struct _GtkWidget GtkWidget
Definition splash.h:29
void dt_style_free(gpointer data)
GList * dt_styles_get_list(const char *filter)
struct dt_imageio_t * imageio
Definition darktable.h:784
struct dt_gui_gtk_t * gui
Definition darktable.h:775
struct dt_colorspaces_t * color_profiles
Definition darktable.h:788
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
dt_colorspaces_color_profile_type_t type
int32_t reset
Definition gtk.h:172
dt_ui_t * ui
Definition gtk.h:164
GList * plugins_storage
GList * plugins_format
GtkWidget * storage
Definition export.c:101
GtkWidget * format
Definition export.c:101
GtkWidget * unit_label
Definition export.c:98
int format_lut[128]
Definition export.c:102
GtkWidget * scale
Definition export.c:100
GtkWidget * print_width
Definition export.c:97
GtkButton * export_button
Definition export.c:105
GtkWidget * storage_extra_container
Definition export.c:106
uint32_t max_allowed_width
Definition export.c:103
GtkWidget * export_masks
Definition export.c:107
GtkWidget * size_in_px
Definition export.c:100
GtkWidget * print_dpi
Definition export.c:97
GtkWidget * print_height
Definition export.c:97
GtkWidget * px_size
Definition export.c:100
GtkWidget * style
Definition export.c:104
GtkWidget * profile
Definition export.c:104
GtkWidget * width
Definition export.c:99
GtkWidget * dimensions_type
Definition export.c:97
GtkWidget * print_size
Definition export.c:100
GtkWidget * height
Definition export.c:99
GtkWidget * format_extra_container
Definition export.c:106
uint32_t max_allowed_height
Definition export.c:103
GtkWidget * intent
Definition export.c:104
char * metadata_export
Definition export.c:108
GModule *void * data
Definition lib.h:80
GtkWidget * widget
Definition lib.h:84
guint timeout_handle
Definition lib.h:90
gchar * name
@ DT_UI_CONTAINER_SIZE