Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
gallery.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2010 Andrea Purracchio.
4 Copyright (C) 2010-2011, 2013 Henrik Andersson.
5 Copyright (C) 2010-2013, 2016 johannes hanika.
6 Copyright (C) 2010 Stuart Henderson.
7 Copyright (C) 2011 Moritz Lipp.
8 Copyright (C) 2011 Olivier Tribout.
9 Copyright (C) 2011 Robert Bieber.
10 Copyright (C) 2011-2018, 2020 Tobias Ellinghaus.
11 Copyright (C) 2012 Christian Tellefsen.
12 Copyright (C) 2012-2014 Jérémy Rosen.
13 Copyright (C) 2012 maigl.
14 Copyright (C) 2012 Richard Wonka.
15 Copyright (C) 2012 Valentin Saussois.
16 Copyright (C) 2013, 2018, 2020-2021 Pascal Obry.
17 Copyright (C) 2013 Thomas Pryds.
18 Copyright (C) 2014 Jesper Pedersen.
19 Copyright (C) 2014-2016 Roman Lebedev.
20 Copyright (C) 2015 Pascal de Bruijn.
21 Copyright (C) 2017 parafin.
22 Copyright (C) 2019 Andreas Schneider.
23 Copyright (C) 2019, 2023, 2025 Aurélien PIERRE.
24 Copyright (C) 2019 Denis Dyakov.
25 Copyright (C) 2019 Heiko Bauke.
26 Copyright (C) 2019 jakubfi.
27 Copyright (C) 2019, 2022 Philippe Weyland.
28 Copyright (C) 2020 Marco.
29 Copyright (C) 2020-2021 Ralf Brown.
30 Copyright (C) 2021 Diederik Ter Rahe.
31 Copyright (C) 2021 Hubert Kowalski.
32 Copyright (C) 2021 Marco Carrarini.
33 Copyright (C) 2021 Mark-64.
34 Copyright (C) 2022 Martin Bařinka.
35 Copyright (C) 2022 Miloš Komarčević.
36 Copyright (C) 2023 Ricky Moon.
37
38 darktable is free software: you can redistribute it and/or modify
39 it under the terms of the GNU General Public License as published by
40 the Free Software Foundation, either version 3 of the License, or
41 (at your option) any later version.
42
43 darktable is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 GNU General Public License for more details.
47
48 You should have received a copy of the GNU General Public License
49 along with darktable. If not, see <http://www.gnu.org/licenses/>.
50*/
51
52#include "common/darktable.h"
53#include "common/debug.h"
55#include "common/image.h"
56#include "common/image_cache.h"
57#include "common/imageio.h"
59#include "common/metadata.h"
60#include "common/utility.h"
61#include "common/variables.h"
62#include "control/conf.h"
63#include "control/control.h"
64#include "dtgtk/button.h"
65#include "dtgtk/paint.h"
66#include "gui/gtk.h"
67#include "gui/gtkentry.h"
69#ifdef GDK_WINDOWING_QUARTZ
70#include "osx/osx.h"
71#endif
72#include <stdio.h>
73#include <stdlib.h>
74
75DT_MODULE(2)
76
77// gui data
78typedef struct gallery_t
79{
80 GtkEntry *entry;
81 GtkEntry *title_entry;
83
84// saved params
86{
88 char title[1024];
89 char cached_dirname[DT_MAX_PATH_FOR_PARAMS]; // expanded during first img store, not stored in param struct.
91 GList *l;
93
94// sorted list of all images
95typedef struct pair_t
96{
97 char line[4096];
98 char item[4096];
99 int pos;
101
102
103const char *name(const struct dt_imageio_module_storage_t *self)
104{
105 return _("Static HTML gallery");
106}
107
108void *legacy_params(dt_imageio_module_storage_t *self, const void *const old_params,
109 const size_t old_params_size, const int old_version, const int new_version,
110 size_t *new_size)
111{
112 if(old_version == 1 && new_version == 2)
113 {
114 typedef struct dt_imageio_gallery_v1_t
115 {
116 char filename[1024];
117 char title[1024];
118 char cached_dirname[1024]; // expanded during first img store, not stored in param struct.
120 GList *l;
121 } dt_imageio_gallery_v1_t;
122
124 dt_imageio_gallery_v1_t *o = (dt_imageio_gallery_v1_t *)old_params;
125
126 g_strlcpy(n->filename, o->filename, sizeof(n->filename));
127 g_strlcpy(n->title, o->title, sizeof(n->title));
128 g_strlcpy(n->cached_dirname, o->cached_dirname, sizeof(n->cached_dirname));
129
130 *new_size = self->params_size(self);
131 return n;
132 }
133 return NULL;
134}
135
137{
138 gallery_t *d = (gallery_t *)self->gui_data;
140 GtkFileChooserNative *filechooser = gtk_file_chooser_native_new(
141 _("select directory"), GTK_WINDOW(win), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
142 _("_select as output destination"), _("_cancel"));
143
144 gchar *old = g_strdup(gtk_entry_get_text(d->entry));
145 char *c = g_strstr_len(old, -1, "$");
146 if(c) *c = '\0';
147 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filechooser), old);
148 dt_free(old);
149 if(gtk_native_dialog_run(GTK_NATIVE_DIALOG(filechooser)) == GTK_RESPONSE_ACCEPT)
150 {
151 gchar *dir = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filechooser));
152 char *composed = g_build_filename(dir, "$(FILE_NAME)", NULL);
153
154 // composed can now contain '\': on Windows it's the path separator,
155 // on other platforms it can be part of a regular folder name.
156 // This would later clash with variable substitution, so we have to escape them
157 gchar *escaped = dt_util_str_replace(composed, "\\", "\\\\");
158
159 gtk_entry_set_text(GTK_ENTRY(d->entry), escaped); // the signal handler will write this to conf
160 dt_free(dir);
161 dt_free(composed);
162 dt_free(escaped);
163 }
164 g_object_unref(filechooser);
165}
166
167static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
168{
169 dt_conf_set_string("plugins/imageio/storage/gallery/file_directory", gtk_entry_get_text(entry));
170}
171
172static void title_changed_callback(GtkEntry *entry, gpointer user_data)
173{
174 dt_conf_set_string("plugins/imageio/storage/gallery/title", gtk_entry_get_text(entry));
175}
176
178{
179 gallery_t *d = (gallery_t *)malloc(sizeof(gallery_t));
180 self->gui_data = (void *)d;
181 self->widget = gtk_box_new(GTK_ORIENTATION_VERTICAL, DT_GUI_BOX_SPACING);
182 GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
183 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
184 GtkWidget *widget;
185
186 widget = gtk_entry_new();
188 gtk_entry_set_width_chars(GTK_ENTRY(widget), 0);
189 gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0);
190 const char *dir = dt_conf_get_string_const("plugins/imageio/storage/gallery/file_directory");
191 if(dir)
192 {
193 gtk_entry_set_text(GTK_ENTRY(widget), dir);
194 }
195 d->entry = GTK_ENTRY(widget);
196
198
199 gtk_widget_set_tooltip_text(widget,
200 _("enter the path where to put exported images\nvariables support bash like string manipulation\n"
201 "type '$(' to activate the completion and see the list of variables"));
202 g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK(entry_changed_callback), self);
203
205 gtk_widget_set_tooltip_text(widget, _("select directory"));
206 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
207 g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK(button_clicked), self);
208
209 hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, DT_GUI_BOX_SPACING);
210 gtk_box_pack_start(GTK_BOX(self->widget), hbox, TRUE, TRUE, 0);
211 gtk_box_pack_start(GTK_BOX(hbox), dt_ui_label_new(_("title")), FALSE, FALSE, 0);
212 d->title_entry = GTK_ENTRY(gtk_entry_new());
213 dt_accels_disconnect_on_text_input(GTK_WIDGET(d->title_entry));
214 gtk_entry_set_width_chars(d->title_entry, 0);
215 gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(d->title_entry), TRUE, TRUE, 0);
216 gtk_widget_set_tooltip_text(GTK_WIDGET(d->title_entry), _("enter the title of the website"));
217 dir = dt_conf_get_string_const("plugins/imageio/storage/gallery/title");
218 if(dir)
219 {
220 gtk_entry_set_text(GTK_ENTRY(d->title_entry), dir);
221 }
222 g_signal_connect(G_OBJECT(d->title_entry), "changed", G_CALLBACK(title_changed_callback), self);
223}
224
226{
227 dt_free(self->gui_data);
228}
229
231{
232 gallery_t *d = (gallery_t *)self->gui_data;
233 gtk_entry_set_text(d->entry, dt_confgen_get("plugins/imageio/storage/gallery/file_directory", DT_DEFAULT));
234 gtk_entry_set_text(d->title_entry, dt_confgen_get("plugins/imageio/storage/gallery/title", DT_DEFAULT));
235 dt_conf_set_string("plugins/imageio/storage/gallery/file_directory", gtk_entry_get_text(d->entry));
236 dt_conf_set_string("plugins/imageio/storage/gallery/title", gtk_entry_get_text(d->title_entry));
237}
238
239static gint sort_pos(pair_t *a, pair_t *b)
240{
241 return a->pos - b->pos;
242}
243
244int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid,
245 dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total,
246 const gboolean high_quality, const gboolean export_masks,
247 dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent,
248 dt_export_metadata_t *metadata)
249{
251
252 char filename[PATH_MAX] = { 0 };
253 char dirname[PATH_MAX] = { 0 };
254 gboolean from_cache = FALSE;
255 dt_image_full_path(imgid, dirname, sizeof(dirname), &from_cache, __FUNCTION__);
256
257 char tmp_dir[PATH_MAX] = { 0 };
258
259 // set variable values to expand them afterwards in darktable variables
261
262 d->vp->filename = dirname;
263 d->vp->jobcode = "export";
264 d->vp->imgid = imgid;
265 d->vp->sequence = num;
266
267 gchar *result_tmp_dir = dt_variables_expand(d->vp, d->filename, TRUE);
268 g_strlcpy(tmp_dir, result_tmp_dir, sizeof(tmp_dir));
269 dt_free(result_tmp_dir);
270
271 // if filenamepattern is a directory just let att ${FILE_NAME} as default..
272 if(g_file_test(tmp_dir, G_FILE_TEST_IS_DIR)
273 || ((d->filename + strlen(d->filename) - 1)[0] == '/'
274 || (d->filename + strlen(d->filename) - 1)[0] == '\\'))
275 snprintf(d->filename + strlen(d->filename), sizeof(d->filename) - strlen(d->filename), "/$(FILE_NAME)");
276
277 // avoid braindead export which is bound to overwrite at random:
278 if(total > 1 && !g_strrstr(d->filename, "$"))
279 {
280 snprintf(d->filename + strlen(d->filename), sizeof(d->filename) - strlen(d->filename), "_$(SEQUENCE)");
281 }
282
283 gchar *fixed_path = dt_util_fix_path(d->filename);
284 g_strlcpy(d->filename, fixed_path, sizeof(d->filename));
285 dt_free(fixed_path);
286
287 gchar *result_filename = dt_variables_expand(d->vp, d->filename, TRUE);
288 g_strlcpy(filename, result_filename, sizeof(filename));
289 dt_free(result_filename);
290
291 g_strlcpy(dirname, filename, sizeof(dirname));
292
293 const char *ext = format->extension(fdata);
294 char *c = dirname + strlen(dirname);
295 for(; c > dirname && *c != '/'; c--)
296 ;
297 if(*c == '/') *c = '\0';
298 if(g_mkdir_with_parents(dirname, 0755))
299 {
300 fprintf(stderr, "[imageio_storage_gallery] could not create directory: `%s'!\n", dirname);
301 dt_control_log(_("could not create directory `%s'!"), dirname);
302 return 1;
303 }
304
305 // store away dir.
306 g_strlcpy(d->cached_dirname, dirname, sizeof(d->cached_dirname));
307
308 c = filename + strlen(filename);
309 for(; c > filename && *c != '.' && *c != '/'; c--)
310 ;
311 if(c <= filename || *c == '/') c = filename + strlen(filename);
312
313 sprintf(c, ".%s", ext);
314
315 // save image to list, in order:
316 pair_t *pair = malloc(sizeof(pair_t));
317
318 char *title = NULL, *description = NULL;
319 GList *res_title = NULL, *res_desc = NULL;
320
321 if ((metadata->flags & DT_META_METADATA) && !(metadata->flags & DT_META_CALCULATED))
322 {
323 res_title = dt_metadata_get(imgid, "Xmp.dc.title", NULL);
324 if(res_title)
325 {
326 title = res_title->data;
327 }
328
329 res_desc = dt_metadata_get(imgid, "Xmp.dc.description", NULL);
330 if(res_desc)
331 {
332 description = res_desc->data;
333 }
334 }
335
336 char relfilename[PATH_MAX] = { 0 }, relthumbfilename[PATH_MAX] = { 0 };
337 c = filename + strlen(filename);
338 for(; c > filename && *c != '/'; c--)
339 ;
340 if(*c == '/') c++;
341 if(c <= filename) c = filename;
342 g_strlcpy(relfilename, c, sizeof(relfilename));
343 g_strlcpy(relthumbfilename, relfilename, sizeof(relthumbfilename));
344 c = relthumbfilename + strlen(relthumbfilename);
345 for(; c > relthumbfilename && *c != '.'; c--)
346 ;
347 if(c <= relthumbfilename) c = relthumbfilename + strlen(relthumbfilename);
348 sprintf(c, "-thumb.%s", ext);
349
350 char subfilename[PATH_MAX] = { 0 }, relsubfilename[PATH_MAX] = { 0 };
351 g_strlcpy(subfilename, d->cached_dirname, sizeof(subfilename));
352 char *sc = subfilename + strlen(subfilename);
353 sprintf(sc, "/img_%d.html", num);
354 snprintf(relsubfilename, sizeof(relsubfilename), "img_%d.html", num);
355
356 // escape special character and especially " which is used in <img> and below in src and msrc
357
358 gchar *esc_relfilename = g_strescape(relfilename, NULL);
359 gchar *esc_relthumbfilename = g_strescape(relthumbfilename, NULL);
360
361 snprintf(pair->line, sizeof(pair->line),
362 "\n"
363 " <div><div class=\"dia\">\n"
364 " <img src=\"%s\" alt=\"img%d\" class=\"img\" onclick=\"openSwipe(%d)\"/></div>\n"
365 " <h1>%s</h1>\n"
366 " %s</div>\n",
367 esc_relthumbfilename,
368 num, num-1, title ? title : "&nbsp;", description ? description : "&nbsp;");
369
370 if(res_title)
371 {
372 g_list_free_full(res_title, dt_free_gpointer);
373 res_title = NULL;
374 }
375 if(res_desc)
376 {
377 g_list_free_full(res_desc, dt_free_gpointer);
378 res_desc = NULL;
379 }
380
381 // export image to file. need this to be able to access meaningful
382 // fdata->width and height below.
383 if(dt_imageio_export(imgid, filename, format, fdata, TRUE, TRUE, export_masks, icc_type,
384 icc_filename, icc_intent, self, sdata, num, total, metadata) != 0)
385 {
386 fprintf(stderr, "[imageio_storage_gallery] could not export to file: `%s'!\n", filename);
387 dt_control_log(_("could not export to file `%s'!"), filename);
388 dt_free(pair);
389 dt_free(esc_relfilename);
390 dt_free(esc_relthumbfilename);
391 return 1;
392 }
393
394 snprintf(pair->item, sizeof(pair->item),
395 "{\n"
396 "src: \"%s\",\n"
397 "w: %d,\n"
398 "h: %d,\n"
399 "msrc: \"%s\",\n"
400 "},\n",
401 esc_relfilename, fdata->width, fdata->height, esc_relthumbfilename);
402
403 dt_free(esc_relfilename);
404 dt_free(esc_relthumbfilename);
405
406 pair->pos = num;
407 d->l = g_list_insert_sorted(d->l, pair, (GCompareFunc)sort_pos);
408 dt_free(pair);
409
410 /* also export thumbnail: */
411 // write with reduced resolution:
412 const int save_max_width = fdata->max_width;
413 const int save_max_height = fdata->max_height;
414 fdata->max_width = 200;
415 fdata->max_height = 200;
416 // alter filename with -thumb:
417 c = filename + strlen(filename);
418 for(; c > filename && *c != '.' && *c != '/'; c--)
419 ;
420 if(c <= filename || *c == '/') c = filename + strlen(filename);
421 ext = format->extension(fdata);
422 sprintf(c, "-thumb.%s", ext);
423 if(dt_imageio_export(imgid, filename, format, fdata, FALSE, FALSE, export_masks, icc_type, icc_filename,
424 icc_intent, self, sdata, num, total, NULL) != 0)
425 {
426 fprintf(stderr, "[imageio_storage_gallery] could not export to file: `%s'!\n", filename);
427 dt_control_log(_("could not export to file `%s'!"), filename);
428 return 1;
429 }
430 // restore for next image:
431 fdata->max_width = save_max_width;
432 fdata->max_height = save_max_height;
433
434 printf("[export_job] exported to `%s'\n", filename);
435 dt_control_log(ngettext("%d/%d exported to `%s'", "%d/%d exported to `%s'", num),
436 num, total, filename);
437 return 0;
438}
439
441{
443 char filename[PATH_MAX] = { 0 };
444 g_strlcpy(filename, d->cached_dirname, sizeof(filename));
445 char *c = filename + strlen(filename);
446
447 // also create style/ subdir:
448 sprintf(c, "/style");
449 g_mkdir_with_parents(filename, 0755);
450 sprintf(c, "/style/style.css");
451 dt_copy_resource_file("/style/style.css", filename);
452 sprintf(c, "/style/favicon.ico");
453 dt_copy_resource_file("/style/favicon.ico", filename);
454
455 // create subdir pswp for photoswipe scripts
456 sprintf(c, "/pswp/default-skin/");
457 g_mkdir_with_parents(filename, 0755);
458 sprintf(c, "/pswp/photoswipe.js");
459 dt_copy_resource_file("/pswp/photoswipe.js", filename);
460 sprintf(c, "/pswp/photoswipe.min.js");
461 dt_copy_resource_file("/pswp/photoswipe.min.js", filename);
462 sprintf(c, "/pswp/photoswipe-ui-default.js");
463 dt_copy_resource_file("/pswp/photoswipe-ui-default.js", filename);
464 sprintf(c, "/pswp/photoswipe.css");
465 dt_copy_resource_file("/pswp/photoswipe.css", filename);
466 sprintf(c, "/pswp/photoswipe-ui-default.min.js");
467 dt_copy_resource_file("/pswp/photoswipe-ui-default.min.js", filename);
468 sprintf(c, "/pswp/default-skin/default-skin.css");
469 dt_copy_resource_file("/pswp/default-skin/default-skin.css", filename);
470 sprintf(c, "/pswp/default-skin/default-skin.png");
471 dt_copy_resource_file("/pswp/default-skin/default-skin.png", filename);
472 sprintf(c, "/pswp/default-skin/default-skin.svg");
473 dt_copy_resource_file("/pswp/default-skin/default-skin.svg", filename);
474 sprintf(c, "/pswp/default-skin/preloader.gif");
475 dt_copy_resource_file("/pswp/default-skin/preloader.gif", filename);
476
477 sprintf(c, "/index.html");
478
479 const char *title = d->title;
480
481 FILE *f = g_fopen(filename, "wb");
482 if(IS_NULL_PTR(f)) return;
483 fprintf(f,
484 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" "
485 "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
486 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
487 " <head>\n"
488 " <meta http-equiv=\"Content-type\" content=\"text/html;charset=UTF-8\" />\n"
489 " <link rel=\"shortcut icon\" href=\"style/favicon.ico\" />\n"
490 " <link rel=\"stylesheet\" href=\"style/style.css\" type=\"text/css\" />\n"
491 " <link rel=\"stylesheet\" href=\"pswp/photoswipe.css\">\n"
492 " <link rel=\"stylesheet\" href=\"pswp/default-skin/default-skin.css\">\n"
493 " <script src=\"pswp/photoswipe.min.js\"></script>\n"
494 " <script src=\"pswp/photoswipe-ui-default.min.js\"></script>\n"
495 " <title>%s</title>\n"
496 " </head>\n"
497 " <body>\n"
498 " <div class=\"title\">%s</div>\n"
499 " <div class=\"page\">\n",
500 title, title);
501
502 size_t count = 0;
503 for(GList *tmp = d->l; tmp; tmp = g_list_next(tmp))
504 {
505 pair_t *p = (pair_t *)tmp->data;
506 fprintf(f, "%s", p->line);
507 count++;
508 }
509
510 fprintf(f, " <p style=\"clear:both;\"></p>\n"
511 " </div>\n"
512 " <div class=\"footer\">\n"
513 " <script language=\"JavaScript\" type=\"text/javascript\">\n"
514 " document.write(\"download all: <em>curl -O# \" + document.documentURI.replace( /\\\\/g, '/' ).replace( /\\/[^\\/]*$/, '' ) + \"/img_[0000-%04zu].jpg</em>\")\n"
515 " </script><br />\n"
516 " created with %s\n"
517 " </div>\n"
518 " <div class=\"pswp\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\">\n"
519 " <div class=\"pswp__bg\"></div>\n"
520 " <div class=\"pswp__scroll-wrap\">\n"
521 " <div class=\"pswp__container\">\n"
522 " <div class=\"pswp__item\"></div>\n"
523 " <div class=\"pswp__item\"></div>\n"
524 " <div class=\"pswp__item\"></div>\n"
525 " </div>\n"
526 " <div class=\"pswp__ui pswp__ui--hidden\">\n"
527 " <div class=\"pswp__top-bar\">\n"
528 " <div class=\"pswp__counter\"></div>\n"
529 " <button class=\"pswp__button pswp__button--close\" title=\"Close (Esc)\"></button>\n"
530 " <button class=\"pswp__button pswp__button--share\" title=\"Share\"></button>\n"
531 " <button class=\"pswp__button pswp__button--fs\" title=\"Toggle fullscreen\"></button>\n"
532 " <button class=\"pswp__button pswp__button--zoom\" title=\"Zoom in/out\"></button>\n"
533 " <div class=\"pswp__preloader\">\n"
534 " <div class=\"pswp__preloader__icn\">\n"
535 " <div class=\"pswp__preloader__cut\">\n"
536 " <div class=\"pswp__preloader__donut\"></div>\n"
537 " </div>\n"
538 " </div>\n"
539 " </div>\n"
540 " </div>\n"
541 " <div class=\"pswp__share-modal pswp__share-modal--hidden pswp__single-tap\">\n"
542 " <div class=\"pswp__share-tooltip\"></div>\n"
543 " </div>\n"
544 " <button class=\"pswp__button pswp__button--arrow--left\" title=\"Previous (arrow left)\">\n"
545 " </button>\n"
546 " <button class=\"pswp__button pswp__button--arrow--right\" title=\"Next (arrow right)\">\n"
547 " </button>\n"
548 " <div class=\"pswp__caption\">\n"
549 " <div class=\"pswp__caption__center\"></div>\n"
550 " </div>\n"
551 " </div>\n"
552 " </div>\n"
553 " </div>\n"
554 " </body>\n"
555 "<script>\n"
556 "var pswpElement = document.querySelectorAll('.pswp')[0];\n"
557 "var items = [\n",
558 count,
560 while(d->l)
561 {
562 pair_t *p = (pair_t *)d->l->data;
563 fprintf(f, "%s", p->item);
564 dt_free(p);
565 d->l = g_list_delete_link(d->l, d->l);
566 }
567 fprintf(f, "];\n"
568 "function openSwipe(img)\n"
569 "{\n"
570 " // define options (if needed)\n"
571 " var options = {\n"
572 " // optionName: 'option value'\n"
573 " index: img // start at first slide\n"
574 " };\n"
575 " var gallery = new PhotoSwipe( pswpElement, PhotoSwipeUI_Default, items, options);\n"
576 " gallery.init();\n"
577 "}\n"
578 "</script>\n"
579 "</html>\n");
580 fclose(f);
581}
582
584{
585 return sizeof(dt_imageio_gallery_t) - 2 * sizeof(void *) - DT_MAX_PATH_FOR_PARAMS;
586}
587
589{
590}
591
593{
595 d->vp = NULL;
596 d->l = NULL;
598
599 const char *text = dt_conf_get_string_const("plugins/imageio/storage/gallery/file_directory");
600 g_strlcpy(d->filename, text, sizeof(d->filename));
601
602 text = dt_conf_get_string_const("plugins/imageio/storage/gallery/title");
603 g_strlcpy(d->title, text, sizeof(d->title));
604
605 return d;
606}
607
609{
610 if(IS_NULL_PTR(params)) return;
613 dt_free(params);
614}
615
616int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
617{
618 if(size != self->params_size(self)) return 1;
620 gallery_t *g = (gallery_t *)self->gui_data;
621 gtk_entry_set_text(GTK_ENTRY(g->entry), d->filename);
622 dt_conf_set_string("plugins/imageio/storage/gallery/file_directory", d->filename);
623 gtk_entry_set_text(GTK_ENTRY(g->title_entry), d->title);
624 dt_conf_set_string("plugins/imageio/storage/gallery/title", d->title);
625 return 0;
626}
627
629{
630 const char *mime = format->mime(NULL);
631 if(strcmp(mime, "image/jpeg") == 0)
632 return 1;
633 if(strcmp(mime, "image/png") == 0)
634 return 1;
635 if(strcmp(mime, "image/webp") == 0)
636 return 1;
637 if (strcmp(mime, "image/avif") == 0) return 1;
638
639 return 0;
640}
641
642// clang-format off
643// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
644// vim: shiftwidth=2 expandtab tabstop=2 cindent
645// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
646// clang-format on
const char ** description(struct dt_iop_module_t *self)
Definition ashift.c:160
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
const char * mime(dt_imageio_module_data_t *data)
Definition avif.c:640
GtkWidget * dtgtk_button_new(DTGTKCairoPaintIconFunc paint, gint paintflags, void *paintdata)
Definition button.c:134
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
dt_iop_color_intent_t
Definition colorspaces.h:63
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
const dt_aligned_pixel_t f
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
char * name
@ DT_DEFAULT
Definition conf.h:96
const char darktable_package_string[]
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
darktable_t darktable
Definition darktable.c:181
#define DT_MODULE(MODVER)
Definition darktable.h:140
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
#define DT_MAX_PATH_FOR_PARAMS
Definition darktable.h:1071
#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
void dtgtk_cairo_paint_directory(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
@ CPF_NONE
Definition dtgtk/paint.h:60
void * get_params(dt_imageio_module_storage_t *self)
Definition gallery.c:592
int supported(dt_imageio_module_storage_t *storage, dt_imageio_module_format_t *format)
Definition gallery.c:628
static void title_changed_callback(GtkEntry *entry, gpointer user_data)
Definition gallery.c:172
void gui_cleanup(dt_imageio_module_storage_t *self)
Definition gallery.c:225
void free_params(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *params)
Definition gallery.c:608
size_t params_size(dt_imageio_module_storage_t *self)
Definition gallery.c:583
void gui_init(dt_imageio_module_storage_t *self)
Definition gallery.c:177
void finalize_store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *dd)
Definition gallery.c:440
void init(dt_imageio_module_storage_t *self)
Definition gallery.c:588
void gui_reset(dt_imageio_module_storage_t *self)
Definition gallery.c:230
void * legacy_params(dt_imageio_module_storage_t *self, const void *const old_params, const size_t old_params_size, const int old_version, const int new_version, size_t *new_size)
Definition gallery.c:108
int set_params(dt_imageio_module_storage_t *self, const void *params, const int size)
Definition gallery.c:616
static void button_clicked(GtkWidget *widget, dt_imageio_module_storage_t *self)
Definition gallery.c:136
static void entry_changed_callback(GtkEntry *entry, gpointer user_data)
Definition gallery.c:167
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
Definition gallery.c:244
static gint sort_pos(pair_t *a, pair_t *b)
Definition gallery.c:239
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
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
void dt_gtkentry_setup_completion(GtkEntry *entry, const dt_gtkentry_completion_spec *compl_list, const char *trigger_char)
Definition gtkentry.c:173
const dt_gtkentry_completion_spec * dt_gtkentry_get_default_path_compl_list()
Definition gtkentry.c:197
int dt_imageio_export(const int32_t imgid, const char *filename, dt_imageio_module_format_t *format, dt_imageio_module_data_t *format_params, const gboolean high_quality, const gboolean copy_metadata, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_imageio_module_storage_t *storage, dt_imageio_module_data_t *storage_params, int num, int total, dt_export_metadata_t *metadata)
Definition imageio.c:765
@ DT_META_CALCULATED
@ DT_META_METADATA
size_t size
Definition mipmap_cache.c:3
struct _GtkWidget GtkWidget
Definition splash.h:29
char * dt_variables_expand(dt_variables_params_t *params, gchar *source, gboolean iterate)
void dt_variables_params_destroy(dt_variables_params_t *params)
void dt_variables_set_max_width_height(dt_variables_params_t *params, int max_width, int max_height)
void dt_variables_params_init(dt_variables_params_t **params)
struct dt_gui_gtk_t * gui
Definition darktable.h:775
dt_ui_t * ui
Definition gtk.h:164
GModule *GtkWidget * widget
GtkEntry * entry
Definition gallery.c:80
GtkEntry * title_entry
Definition gallery.c:81
int pos
Definition gallery.c:99
char item[4096]
Definition gallery.c:98
char line[4096]
Definition gallery.c:97
gchar * dt_util_str_replace(const gchar *string, const gchar *pattern, const gchar *substitute)
Definition utility.c:136
void dt_copy_resource_file(const char *src, const char *dst)
Definition utility.c:941
gchar * dt_util_fix_path(const gchar *path)
Definition utility.c:222