Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
imageio/format/pdf.c
Go to the documentation of this file.
1/*
2 * This file is part of darktable,
3 * Copyright (C) 2015 Jérémy Rosen.
4 * Copyright (C) 2015-2017, 2019-2020 Tobias Ellinghaus.
5 * Copyright (C) 2016 Roman Lebedev.
6 * Copyright (C) 2019, 2022, 2025-2026 Aurélien PIERRE.
7 * Copyright (C) 2019 jakubfi.
8 * Copyright (C) 2019 Philippe Weyland.
9 * Copyright (C) 2020 Andreas Schneider.
10 * Copyright (C) 2020-2022 Diederik Ter Rahe.
11 * Copyright (C) 2020 Hubert Kowalski.
12 * Copyright (C) 2020-2021 Pascal Obry.
13 * Copyright (C) 2021 Ralf Brown.
14 * Copyright (C) 2022 Martin Bařinka.
15 * Copyright (C) 2024 Alynx Zhou.
16 *
17 * darktable is free software: you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation, either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * darktable is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with darktable. If not, see <http://www.gnu.org/licenses/>.
29 */
30
31#include "common/pdf.h"
32#include "bauhaus/bauhaus.h"
33#include "common/colorspaces.h"
34#include "common/darktable.h"
35#include "common/imageio.h"
37#include "common/variables.h"
38#include "control/control.h"
39#include "dtgtk/button.h"
40#include "gui/gtkentry.h"
42
43#include <strings.h>
44
45DT_MODULE(1)
46
47// clang-format off
48
49// gui data
64
70
77
84
85static const struct
86{
87 char *name;
88 int bpp;
89} _pdf_bpp[] =
90{
91 { N_("8 bit"), 8 },
92 { N_("16 bit"), 16 },
93 { NULL, 0 }
94};
95
101
102// saved params -- just there to get the sizeof() without worrying about padding, ...
121
122// the real type used in the code
132
133// clang-format on
134
136{
137}
138
142
143static int _paper_size(dt_imageio_pdf_params_t *d, float *page_width, float *page_height, float *page_border)
144{
145 float width, height, border;
146
147 if(!dt_pdf_parse_paper_size(d->size, &width, &height))
148 {
149 fprintf(stderr, "[imageio_format_pdf] invalid paper size: `%s'!\n", d->size);
150 dt_control_log(_("invalid paper size"));
151 return 1;
152 }
153
154 if(!dt_pdf_parse_length(d->border, &border))
155 {
156 fprintf(stderr, "[imageio_format_pdf] invalid border size: `%s'! using 0\n", d->border);
157 dt_control_log(_("invalid border size, using 0"));
158// return 1;
159 border = 0.0;
160 }
161
162 if(d->orientation == ORIENTATION_LANDSCAPE)
163 {
164 float w = width, h = height;
165 width = MAX(w, h);
166 height = MIN(w, h);
167 }
168 else
169 {
170 float w = width, h = height;
171 width = MIN(w, h);
172 height = MAX(w, h);
173 }
174
175 *page_width = width;
176 *page_height = height;
177 *page_border = border;
178
179 return 0;
180}
181
182
183int write_image(dt_imageio_module_data_t *data, const char *filename, const void *in,
184 dt_colorspaces_color_profile_type_t over_type, const char *over_filename,
185 void *exif, int exif_len, int32_t imgid, int num, int total, struct dt_dev_pixelpipe_t *pipe,
186 const gboolean export_masks)
187{
189
190 // init the pdf. we start counting with 1.
191 if(num == 1)
192 {
193 float page_width, page_height, page_border;
194 float page_dpi = d->params.dpi;
195
196 if(_paper_size(&d->params, &page_width, &page_height, &page_border))
197 return 1;
198
199 unsigned int compression = d->params.compression;
200 compression = MIN(compression, DT_PDF_STREAM_ENCODER_FLATE);
201
202
203 dt_pdf_t *pdf = dt_pdf_start(filename, page_width, page_height, page_dpi, compression);
204 if(IS_NULL_PTR(pdf))
205 {
206 fprintf(stderr, "[imageio_format_pdf] could not export to file: `%s'!\n", filename);
207 dt_control_log(_("could not export to file `%s'!"), filename);
208 return 1;
209 }
210
211 // TODO: escape ')' and maybe also '('
212 pdf->title = *d->params.title ? d->params.title : NULL;
213
214 d->pdf = pdf;
215 d->actual_filename = g_strdup(filename);
216 d->page_border = page_border;
217 } // init the pdf
218
219 // add the icc profile
220 int icc_id = 0;
221 if(imgid > 0 && d->params.icc && d->params.mode == MODE_NORMAL)
222 {
223 // get the id of the profile
224 const dt_colorspaces_color_profile_t *profile = dt_colorspaces_get_output_profile(imgid, &over_type, over_filename);
225
226 // look it up in the list
227 for(GList *iter = d->icc_profiles; iter; iter = g_list_next(iter))
228 {
229 _pdf_icc_t *icc = (_pdf_icc_t *)iter->data;
230 if(icc->profile == profile)
231 {
232 icc_id = icc->icc_id;
233 break;
234 }
235 }
236 if(icc_id == 0)
237 {
238 uint32_t len = 0;
239 cmsSaveProfileToMem(profile->profile, 0, &len);
240 if(len > 0)
241 {
242 unsigned char *buf = malloc(sizeof(unsigned char) * len);
243 cmsSaveProfileToMem(profile->profile, buf, &len);
244 icc_id = dt_pdf_add_icc_from_data(d->pdf, buf, len);
245 dt_free(buf);
246 _pdf_icc_t *icc = (_pdf_icc_t *)malloc(sizeof(_pdf_icc_t));
247 icc->profile = profile;
248 icc->icc_id = icc_id;
249 d->icc_profiles = g_list_append(d->icc_profiles, icc);
250 }
251 }
252 }
253
254 void *image_data = NULL;
255
256 // TODO
257 // decide if we want to push that conversion step into the pdf lib and maybe do it on the fly while writing.
258 // that would get rid of one buffer in the case of ASCII_HEX
259 if(d->params.mode == MODE_NORMAL)
260 {
261 if(d->params.bpp == 8)
262 {
264 (size_t)3 * data->width * data->height,
265 0);
266 const uint8_t *in_ptr = (const uint8_t *)in;
267 uint8_t *out_ptr = (uint8_t *)image_data;
268 for(int y = 0; y < data->height; y++)
269 {
270 for(int x = 0; x < data->width; x++, in_ptr += 4, out_ptr += 3)
271 memcpy(out_ptr, in_ptr, 3);
272 }
273 }
274 else
275 {
277 sizeof(uint16_t) * 3 * data->width * data->height,
278 0);
279 const uint16_t *in_ptr = (const uint16_t *)in;
280 uint16_t *out_ptr = (uint16_t *)image_data;
281 for(int y = 0; y < data->height; y++)
282 {
283 for(int x = 0; x < data->width; x++, in_ptr += 4, out_ptr += 3)
284 {
285 for(int c = 0; c < 3; c++)
286 out_ptr[c] = (0xff00 & (in_ptr[c] << 8)) | (in_ptr[c] >> 8);
287 }
288 }
289 }
290 }
291
292 dt_pdf_image_t *image = dt_pdf_add_image(d->pdf, image_data, d->params.global.width, d->params.global.height, d->params.bpp, icc_id, d->page_border);
293
295
296 d->images = g_list_append(d->images, image);
297
298
299 // finish the pdf
300 if(num == total)
301 {
302 int n_images = g_list_length(d->images);
303 dt_pdf_page_t **pages = malloc(sizeof(dt_pdf_page_t *) * n_images);
304
305 gboolean outline_mode = d->params.mode != MODE_NORMAL;
306 gboolean show_bb = d->params.mode == MODE_DEBUG;
307
308 // add a page for every image
309 int i = 0;
310 for(const GList *iter = d->images; iter; iter = g_list_next(iter))
311 {
312 dt_pdf_image_t *page = (dt_pdf_image_t *)iter->data;
313 page->outline_mode = outline_mode;
314 page->show_bb = show_bb;
315 page->rotate_to_fit = d->params.rotate;
316 pages[i] = dt_pdf_add_page(d->pdf, &page, 1);
317 i++;
318 }
319
320 // add the contact sheet(s)
321 // TODO
322
323 dt_pdf_finish(d->pdf, pages, n_images);
324
325 // we allocated the images and pages. the main pdf object gets free'ed in dt_pdf_finish().
326 g_list_free_full(d->images, dt_free_gpointer);
327 d->images = NULL;
328 for(i = 0; i < n_images; i++) dt_free(pages[i]);
329 dt_free(pages);
330 dt_free(d->actual_filename);
331 g_list_free_full(d->icc_profiles, dt_free_gpointer);
332 d->icc_profiles = NULL;
333
334 d->pdf = NULL;
335 d->images = NULL;
336 d->actual_filename = NULL;
337 d->icc_profiles = NULL;
338 } // finish the pdf
339
340 return 0;
341}
342
344{
345 return ((dt_imageio_pdf_params_t *)p)->bpp;
346}
347
352
354{
355 return "application/pdf";
356}
357
359{
360 return "pdf";
361}
362
363const char *name()
364{
365 return _("PDF");
366}
367
372
373int dimension(struct dt_imageio_module_format_t *self, dt_imageio_module_data_t *data, uint32_t *width, uint32_t *height)
374{
375 if(data)
376 {
378
379 float page_width, page_height, page_border;
380 float page_dpi = d->params.dpi;
381
382 if(_paper_size(&d->params, &page_width, &page_height, &page_border))
383 return 1;
384
385 *width = dt_pdf_point_to_pixel(page_width - 2 * page_border, page_dpi) + 0.5;
386 *height = dt_pdf_point_to_pixel(page_height - 2 * page_border, page_dpi) + 0.5;
387
388 if(d->params.rotate)
389 *width = *height = MAX(*width, *height);
390 }
391 return 0;
392}
393
394static void size_toggle_callback(GtkWidget *widget, gpointer user_data);
395
396// set the paper size dropdown from the UNTRANSLATED string
397static void _set_paper_size(dt_imageio_module_format_t *self, const char *text)
398{
399 pdf_t *d = (pdf_t *)self->gui_data;
400
401 if(IS_NULL_PTR(text) || *text == '\0')
402 {
404 return;
405 }
406
407 g_signal_handlers_block_by_func(d->size, size_toggle_callback, self);
408
409 int pos = 0;
410 for(; pos < dt_bauhaus_combobox_length(d->size); pos++)
411 {
412 if((pos < dt_pdf_paper_sizes_n && !strcasecmp(text, dt_pdf_paper_sizes[pos].name))
413 || !strcasecmp(text, dt_bauhaus_combobox_get_entry(d->size, pos)))
414 break;
415 }
416
417 if(pos < dt_bauhaus_combobox_length(d->size))
418 {
419 // we jumped out of the loop -> found it
420 dt_bauhaus_combobox_set(d->size, pos);
421 dt_conf_set_string("plugins/imageio/format/pdf/size", text);
422 }
423 else
424 {
425 // newly seen -- check if it is valid
426 float width, height;
428 {
429 // seems to be ok
430 dt_bauhaus_combobox_add(d->size, text);
431 dt_bauhaus_combobox_set(d->size, pos);
432 dt_conf_set_string("plugins/imageio/format/pdf/size", text);
433 }
434 else
435 {
436 dt_control_log(_("invalid paper size"));
437 gchar *old_size = dt_conf_get_string("plugins/imageio/format/pdf/size");
438 if(old_size)
439 {
440 // safeguard against strange stuff in config
441 if(dt_pdf_parse_paper_size(old_size, &width, &height))
442 _set_paper_size(self, old_size);
443 else
445
446 dt_free(old_size);
447 }
448 }
449 }
450
451 g_signal_handlers_unblock_by_func(d->size, size_toggle_callback, self);
452
453}
454
455static void title_changed_callback(GtkWidget *widget, gpointer user_data)
456{
457 dt_conf_set_string("plugins/imageio/format/pdf/title", gtk_entry_get_text(GTK_ENTRY(widget)));
458}
459
460static void border_changed_callback(GtkWidget *widget, gpointer user_data)
461{
462 dt_conf_set_string("plugins/imageio/format/pdf/border", gtk_entry_get_text(GTK_ENTRY(widget)));
463}
464
465static void size_toggle_callback(GtkWidget *widget, gpointer user_data)
466{
467 unsigned int pos = dt_bauhaus_combobox_get(widget);
468 if(pos < dt_pdf_paper_sizes_n)
469 _set_paper_size(user_data, dt_pdf_paper_sizes[pos].name); // has to be untranslated
470 else
472}
473
474static void orientation_toggle_callback(GtkWidget *widget, gpointer user_data)
475{
476 dt_conf_set_int("plugins/imageio/format/pdf/orientation", dt_bauhaus_combobox_get(widget));
477}
478
479static void dpi_changed_callback(GtkWidget *widget, gpointer user_data)
480{
481 dt_conf_set_float("plugins/imageio/format/pdf/dpi", gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget)));
482}
483
484static void rotate_toggle_callback(GtkWidget *widget, gpointer user_data)
485{
486 dt_conf_set_bool("plugins/imageio/format/pdf/rotate", dt_bauhaus_combobox_get(widget) == 1);
487}
488
489static void pages_toggle_callback(GtkWidget *widget, gpointer user_data)
490{
491 dt_conf_set_int("plugins/imageio/format/pdf/pages", dt_bauhaus_combobox_get(widget));
492}
493
494static void icc_toggle_callback(GtkWidget *widget, gpointer user_data)
495{
496 dt_conf_set_bool("plugins/imageio/format/pdf/icc", dt_bauhaus_combobox_get(widget) == 1);
497}
498
499static void mode_toggle_callback(GtkWidget *widget, gpointer user_data)
500{
501 dt_conf_set_int("plugins/imageio/format/pdf/mode", dt_bauhaus_combobox_get(widget));
502}
503
504static void bpp_toggle_callback(GtkWidget *widget, gpointer user_data)
505{
506 const int sel = dt_bauhaus_combobox_get(widget);
507 // we don't allow typing in that dropdown so -1 shouldn't happen, but coverity doesn't know that
508 if(sel >= 0)
509 dt_conf_set_int("plugins/imageio/format/pdf/bpp", _pdf_bpp[sel].bpp);
510}
511
512static void compression_toggle_callback(GtkWidget *widget, gpointer user_data)
513{
514 dt_conf_set_int("plugins/imageio/format/pdf/compression", dt_bauhaus_combobox_get(widget));
515}
516
518{
519 pdf_t *d = calloc(1, sizeof(pdf_t));
520 self->gui_data = (void *)d;
521 self->widget = gtk_grid_new();
522 GtkGrid *grid = GTK_GRID(self->widget);
523 gtk_grid_set_row_spacing(grid, DT_GUI_BOX_SPACING);
524 gtk_grid_set_column_spacing(grid, DT_GUI_BOX_SPACING);
525
526 int line = 0;
527
528 // title
529
530 gtk_grid_attach(grid, dt_ui_label_new(_("title")), 0, ++line, 1, 1);
531
532 d->title = GTK_ENTRY(gtk_entry_new());
533 dt_accels_disconnect_on_text_input(GTK_WIDGET(d->title));
534 gtk_entry_set_placeholder_text(d->title, "untitled");
535 gtk_entry_set_width_chars(d->title, 5);
536 gtk_widget_set_hexpand(GTK_WIDGET(d->title), TRUE);
537 gtk_grid_attach(grid, GTK_WIDGET(d->title), 1, line, 1, 1);
538 gtk_widget_set_tooltip_text(GTK_WIDGET(d->title), _("enter the title of the pdf"));
539 const char *str = dt_conf_get_string_const("plugins/imageio/format/pdf/title");
540 if(str)
541 {
542 gtk_entry_set_text(GTK_ENTRY(d->title), str);
543 }
544 g_signal_connect(G_OBJECT(d->title), "changed", G_CALLBACK(title_changed_callback), self);
545
546 // paper size
547
550 dt_bauhaus_widget_set_label(d->size, N_("paper size"));
551 for(int i = 0; dt_pdf_paper_sizes[i].name; i++)
553 gtk_grid_attach(grid, GTK_WIDGET(d->size), 0, ++line, 2, 1);
554 g_signal_connect(G_OBJECT(d->size), "value-changed", G_CALLBACK(size_toggle_callback), self);
555 gtk_widget_set_tooltip_text(d->size, _("paper size of the pdf\neither one from the list or "
556 "\"<width> [unit] x <height> <unit>\n"
557 "example: 210 mm x 2.97 cm"));
558 gchar *size_str = dt_conf_get_string("plugins/imageio/format/pdf/size");
559 _set_paper_size(self, size_str);
560 dt_free(size_str);
561
562 // orientation
563
565 dt_bauhaus_widget_set_label(d->orientation, N_("page orientation"));
566 dt_bauhaus_combobox_add(d->orientation, _("portrait"));
567 dt_bauhaus_combobox_add(d->orientation, _("landscape"));
568 gtk_grid_attach(grid, GTK_WIDGET(d->orientation), 0, ++line, 2, 1);
569 g_signal_connect(G_OBJECT(d->orientation), "value-changed", G_CALLBACK(orientation_toggle_callback), self);
570 gtk_widget_set_tooltip_text(d->orientation, _("paper orientation of the pdf"));
571 dt_bauhaus_combobox_set(d->orientation, dt_conf_get_int("plugins/imageio/format/pdf/orientation"));
572
573 // border
574
575 gtk_grid_attach(grid, dt_ui_label_new(_("border")), 0, ++line, 1, 1);
576
577 d->border = GTK_ENTRY(gtk_entry_new());
578 dt_accels_disconnect_on_text_input(GTK_WIDGET(d->border));
579 gtk_entry_set_width_chars(d->border, 5);
580 gtk_entry_set_max_length(d->border, sizeof(((dt_imageio_pdf_params_t *)NULL)->border) - 1);
581 gtk_entry_set_placeholder_text(d->border, "0 mm");
582 gtk_grid_attach(grid, GTK_WIDGET(d->border), 1, line, 1, 1);
583 gtk_widget_set_tooltip_text(GTK_WIDGET(d->border), _("empty space around the pdf\n"
584 "format: size + unit\nexamples: 10 mm, 1 inch"));
585 str = dt_conf_get_string_const("plugins/imageio/format/pdf/border");
586 if(str)
587 {
588 gtk_entry_set_text(GTK_ENTRY(d->border), str);
589 }
590 g_signal_connect(G_OBJECT(d->border), "changed", G_CALLBACK(border_changed_callback), self);
591
592 // dpi
593
594 gtk_grid_attach(grid, dt_ui_label_new(_("dpi")), 0, ++line, 1, 1);
595
596 d->dpi = GTK_SPIN_BUTTON(gtk_spin_button_new_with_range(1, 5000, 1));
597 gtk_grid_attach(grid, GTK_WIDGET(d->dpi), 1, line, 1, 1);
598 gtk_widget_set_tooltip_text(GTK_WIDGET(d->dpi), _("dpi of the images inside the pdf"));
599 gtk_spin_button_set_value(d->dpi, dt_conf_get_float("plugins/imageio/format/pdf/dpi"));
600 g_signal_connect(G_OBJECT(d->dpi), "value-changed", G_CALLBACK(dpi_changed_callback), self);
601
602 // rotate images yes|no
603
605 dt_bauhaus_widget_set_label(d->rotate, N_("rotate images"));
606 dt_bauhaus_combobox_add(d->rotate, _("no"));
607 dt_bauhaus_combobox_add(d->rotate, _("yes"));
608 gtk_grid_attach(grid, GTK_WIDGET(d->rotate), 0, ++line, 2, 1);
609 g_signal_connect(G_OBJECT(d->rotate), "value-changed", G_CALLBACK(rotate_toggle_callback), self);
610 gtk_widget_set_tooltip_text(d->rotate, _("images can be rotated to match the pdf orientation "
611 "to waste less space when printing"));
612 dt_bauhaus_combobox_set(d->rotate, dt_conf_get_bool("plugins/imageio/format/pdf/rotate"));
613
614 // pages all|single images|contact sheet
615
617 dt_bauhaus_widget_set_label(d->pages, N_("TODO: pages"));
618 dt_bauhaus_combobox_add(d->pages, _("all"));
619 dt_bauhaus_combobox_add(d->pages, _("single images"));
620 dt_bauhaus_combobox_add(d->pages, _("contact sheet"));
621// gtk_grid_attach(grid, GTK_WIDGET(d->pages), 0, ++line, 2, 1);
622// g_signal_connect(G_OBJECT(d->pages), "value-changed", G_CALLBACK(pages_toggle_callback), self);
623 gtk_widget_set_tooltip_text(d->pages, _("what pages should be added to the pdf"));
624 dt_bauhaus_combobox_set(d->pages, dt_conf_get_int("plugins/imageio/format/pdf/pages"));
625 gtk_widget_set_sensitive(d->pages, FALSE); // TODO
626
627 // embedded icc profile yes|no
628
630 dt_bauhaus_widget_set_label(d->icc, N_("embed icc profiles"));
631 dt_bauhaus_combobox_add(d->icc, _("no"));
632 dt_bauhaus_combobox_add(d->icc, _("yes"));
633 gtk_grid_attach(grid, GTK_WIDGET(d->icc), 0, ++line, 2, 1);
634 g_signal_connect(G_OBJECT(d->icc), "value-changed", G_CALLBACK(icc_toggle_callback), self);
635 gtk_widget_set_tooltip_text(d->icc, _("images can be tagged with their icc profile"));
636 dt_bauhaus_combobox_set(d->icc, dt_conf_get_bool("plugins/imageio/format/pdf/icc"));
637
638 // bpp
639
641 dt_bauhaus_widget_set_label(d->bpp, N_("bit depth"));
642 int sel = 0;
643 int bpp = dt_conf_get_int("plugins/imageio/format/pdf/bpp");
644 for(int i = 0; _pdf_bpp[i].name; i++)
645 {
647 if(_pdf_bpp[i].bpp == bpp) sel = i;
648 }
649 gtk_grid_attach(grid, GTK_WIDGET(d->bpp), 0, ++line, 2, 1);
650 g_signal_connect(G_OBJECT(d->bpp), "value-changed", G_CALLBACK(bpp_toggle_callback), self);
651 gtk_widget_set_tooltip_text(d->bpp, _("bits per channel of the embedded images"));
652 dt_bauhaus_combobox_set(d->bpp, sel);
653
654 // compression
655
657 dt_bauhaus_widget_set_label(d->compression, N_("compression"));
658 dt_bauhaus_combobox_add(d->compression, _("uncompressed"));
659 dt_bauhaus_combobox_add(d->compression, _("deflate"));
660 gtk_grid_attach(grid, GTK_WIDGET(d->compression), 0, ++line, 2, 1);
661 g_signal_connect(G_OBJECT(d->compression), "value-changed", G_CALLBACK(compression_toggle_callback), self);
662 gtk_widget_set_tooltip_text(d->compression, _("method used for image compression\n"
663 "uncompressed -- fast but big files\n"
664 "deflate -- smaller files but slower"));
665 dt_bauhaus_combobox_set(d->compression, dt_conf_get_int("plugins/imageio/format/pdf/compression"));
666
667 // image mode normal|draft|debug
668
670 dt_bauhaus_widget_set_label(d->mode, N_("image mode"));
671 dt_bauhaus_combobox_add(d->mode, _("normal"));
672 dt_bauhaus_combobox_add(d->mode, _("draft"));
673 dt_bauhaus_combobox_add(d->mode, _("debug"));
674 gtk_grid_attach(grid, GTK_WIDGET(d->mode), 0, ++line, 2, 1);
675 g_signal_connect(G_OBJECT(d->mode), "value-changed", G_CALLBACK(mode_toggle_callback), self);
676 gtk_widget_set_tooltip_text(d->mode, _("normal -- just put the images into the pdf\n"
677 "draft -- images are replaced with boxes\n"
678 "debug -- only show the outlines and bounding boxen"));
679 dt_bauhaus_combobox_set(d->mode, dt_conf_get_int("plugins/imageio/format/pdf/mode"));
680}
681
683{
684 dt_free(self->gui_data);
685}
686
688{
689 pdf_t *d = (pdf_t *)self->gui_data;
690
691 dpi_changed_callback(GTK_WIDGET(d->dpi), self);
692 icc_toggle_callback(GTK_WIDGET(d->icc), self);
693 mode_toggle_callback(GTK_WIDGET(d->mode), self);
694 orientation_toggle_callback(GTK_WIDGET(d->orientation), self);
695 pages_toggle_callback(GTK_WIDGET(d->pages), self);
696 rotate_toggle_callback(GTK_WIDGET(d->rotate), self);
697 size_toggle_callback(GTK_WIDGET(d->size), self);
698 title_changed_callback(GTK_WIDGET(d->title), self);
699 bpp_toggle_callback(GTK_WIDGET(d->bpp), self);
700 compression_toggle_callback(GTK_WIDGET(d->compression), self);
701}
702
704{
705 return sizeof(dt_imageio_pdf_params_t);
706}
707
709{
710 dt_imageio_pdf_t *d = (dt_imageio_pdf_t *)calloc(1, sizeof(dt_imageio_pdf_t));
711
712 if(d)
713 {
714 const char *text = dt_conf_get_string_const("plugins/imageio/format/pdf/title");
715 g_strlcpy(d->params.title, text, sizeof(d->params.title));
716
717 text = dt_conf_get_string_const("plugins/imageio/format/pdf/border");
718 g_strlcpy(d->params.border, text, sizeof(d->params.border));
719
720 text = dt_conf_get_string_const("plugins/imageio/format/pdf/size");
721 g_strlcpy(d->params.size, text, sizeof(d->params.size));
722
723 d->params.bpp = dt_conf_get_int("plugins/imageio/format/pdf/bpp");
724 d->params.compression = dt_conf_get_int("plugins/imageio/format/pdf/compression");
725 d->params.dpi = dt_conf_get_float("plugins/imageio/format/pdf/dpi");
726 d->params.icc = dt_conf_get_bool("plugins/imageio/format/pdf/icc");
727 d->params.mode = dt_conf_get_int("plugins/imageio/format/pdf/mode");
728 d->params.orientation = dt_conf_get_int("plugins/imageio/format/pdf/orientation");
729 d->params.pages = dt_conf_get_int("plugins/imageio/format/pdf/pages");
730 d->params.rotate = dt_conf_get_bool("plugins/imageio/format/pdf/rotate");
731 }
732
733 return d;
734}
735
736// in normal operations we free these after exporting the last image, but when an export
737// gets cancelled that last image doesn't get exported, so we have to take care of it here.
739{
741
742 if(d->pdf)
743 dt_pdf_finish(d->pdf, NULL, 0);
744
745 g_list_free_full(d->images, dt_free_gpointer);
746 d->images = NULL;
747
748 if(d->actual_filename)
749 {
750 g_unlink(d->actual_filename); // no need to leave broken files on disk
751 dt_free(d->actual_filename);
752 }
753
754 g_list_free_full(d->icc_profiles, dt_free_gpointer);
755 d->icc_profiles = NULL;
756
757 d->pdf = NULL;
758 d->images = NULL;
759 d->actual_filename = NULL;
760 d->icc_profiles = NULL;
761
762 dt_free(params);
763}
764
765int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
766{
767 if(size != self->params_size(self)) return 1;
768 const dt_imageio_pdf_t *d = (dt_imageio_pdf_t *)params;
769 pdf_t *g = (pdf_t *)self->gui_data;
770
771 for(int i = 0; _pdf_bpp[i].name; i++)
772 {
773 if(_pdf_bpp[i].bpp == d->params.bpp)
775 }
776
777 gtk_entry_set_text(g->title, d->params.title);
778 gtk_entry_set_text(g->border, d->params.border);
779 dt_bauhaus_combobox_set(g->compression, d->params.compression);
780 gtk_spin_button_set_value(g->dpi, d->params.dpi);
781 dt_bauhaus_combobox_set(g->icc, d->params.icc);
782 dt_bauhaus_combobox_set(g->mode, d->params.mode);
783 dt_bauhaus_combobox_set(g->orientation, d->params.orientation);
784 dt_bauhaus_combobox_set(g->pages, d->params.pages);
785 dt_bauhaus_combobox_set(g->rotate, d->params.rotate);
786 _set_paper_size(self, d->params.size);
787
788 dt_conf_set_string("plugins/imageio/format/pdf/title", d->params.title);
789 dt_conf_set_string("plugins/imageio/format/pdf/border", d->params.border);
790 dt_conf_set_int("plugins/imageio/format/pdf/bpp", d->params.bpp);
791 dt_conf_set_int("plugins/imageio/format/pdf/compression", d->params.compression);
792 dt_conf_set_float("plugins/imageio/format/pdf/dpi", d->params.dpi);
793 dt_conf_set_bool("plugins/imageio/format/pdf/icc", d->params.icc);
794 dt_conf_set_int("plugins/imageio/format/pdf/mode", d->params.mode);
795 dt_conf_set_int("plugins/imageio/format/pdf/orientation", d->params.orientation);
796 dt_conf_set_int("plugins/imageio/format/pdf/pages", d->params.pages);
797 dt_conf_set_bool("plugins/imageio/format/pdf/rotate", d->params.rotate);
798
799 return 0;
800}
801
802// clang-format off
803// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
804// vim: shiftwidth=2 expandtab tabstop=2 cindent
805// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
806// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_bauhaus_combobox_set_editable(GtkWidget *widget, int editable)
Definition bauhaus.c:2074
const char * dt_bauhaus_combobox_get_entry(GtkWidget *widget, int pos)
Definition bauhaus.c:2199
int dt_bauhaus_combobox_get(GtkWidget *widget)
Definition bauhaus.c:2347
int dt_bauhaus_combobox_length(GtkWidget *widget)
Definition bauhaus.c:2155
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
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:2016
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_colorspaces_color_profile_t * dt_colorspaces_get_output_profile(const int32_t imgid, dt_colorspaces_color_profile_type_t *over_type, const char *over_filename)
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
dt_pdf_page_t * dt_pdf_add_page(dt_pdf_t *pdf, dt_pdf_image_t **images, int n_images)
Definition common/pdf.c:458
dt_pdf_image_t * dt_pdf_add_image(dt_pdf_t *pdf, const unsigned char *image, int width, int height, int bpp, int icc_id, float border)
Definition common/pdf.c:376
int dt_pdf_parse_length(const char *str, float *length)
Definition common/pdf.c:70
int dt_pdf_add_icc_from_data(dt_pdf_t *pdf, const unsigned char *data, size_t size)
Definition common/pdf.c:332
int dt_pdf_parse_paper_size(const char *str, float *width, float *height)
Definition common/pdf.c:118
void dt_pdf_finish(dt_pdf_t *pdf, dt_pdf_page_t **pages, int n_pages)
Definition common/pdf.c:640
dt_pdf_t * dt_pdf_start(const char *filename, float width, float height, float dpi, dt_pdf_stream_encoder_t default_encoder)
Definition common/pdf.c:218
void dt_conf_set_bool(const char *name, int val)
int dt_conf_get_bool(const char *name)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
gchar * dt_conf_get_string(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_conf_set_string(const char *name, const char *val)
const char * dt_conf_get_string_const(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:761
darktable_t darktable
Definition darktable.c:181
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:433
#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_pixelpipe_cache_free_align(mem)
Definition darktable.h:453
#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 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
#define DT_GUI_BOX_SPACING
Definition gtk.h:109
static GtkWidget * dt_ui_label_new(const gchar *str)
Definition gtk.h:461
#define DT_GUI_MODULE(x)
int bpp
const char * mime(dt_imageio_module_data_t *data)
size_t params_size(dt_imageio_module_format_t *self)
static void border_changed_callback(GtkWidget *widget, gpointer user_data)
static void _set_paper_size(dt_imageio_module_format_t *self, const char *text)
static void rotate_toggle_callback(GtkWidget *widget, gpointer user_data)
static void dpi_changed_callback(GtkWidget *widget, gpointer user_data)
int dimension(struct dt_imageio_module_format_t *self, dt_imageio_module_data_t *data, uint32_t *width, uint32_t *height)
void gui_reset(dt_imageio_module_format_t *self)
void gui_init(dt_imageio_module_format_t *self)
static void bpp_toggle_callback(GtkWidget *widget, gpointer user_data)
const char * extension(dt_imageio_module_data_t *data)
int set_params(dt_imageio_module_format_t *self, const void *params, const int size)
char * name
void cleanup(dt_imageio_module_format_t *self)
int levels(dt_imageio_module_data_t *p)
@ MODE_DRAFT
@ MODE_DEBUG
@ MODE_NORMAL
void free_params(dt_imageio_module_format_t *self, dt_imageio_module_data_t *params)
static void title_changed_callback(GtkWidget *widget, gpointer user_data)
static void pages_toggle_callback(GtkWidget *widget, gpointer user_data)
static void icc_toggle_callback(GtkWidget *widget, gpointer user_data)
_pdf_orientation_t
@ ORIENTATION_PORTRAIT
@ ORIENTATION_LANDSCAPE
static void mode_toggle_callback(GtkWidget *widget, gpointer user_data)
void init(dt_imageio_module_format_t *self)
static const struct @53 _pdf_bpp[]
void * get_params(dt_imageio_module_format_t *self)
@ PAGES_ALL
@ PAGES_SINGLE
@ PAGES_CONTACT
static int _paper_size(dt_imageio_pdf_params_t *d, float *page_width, float *page_height, float *page_border)
static void compression_toggle_callback(GtkWidget *widget, gpointer user_data)
void gui_cleanup(dt_imageio_module_format_t *self)
static void orientation_toggle_callback(GtkWidget *widget, gpointer user_data)
int write_image(dt_imageio_module_data_t *data, const char *filename, const void *in, dt_colorspaces_color_profile_type_t over_type, const char *over_filename, void *exif, int exif_len, int32_t imgid, int num, int total, struct dt_dev_pixelpipe_t *pipe, const gboolean export_masks)
static void size_toggle_callback(GtkWidget *widget, gpointer user_data)
@ IMAGEIO_INT16
Definition imageio.h:64
@ IMAGEIO_RGB
Definition imageio.h:70
@ IMAGEIO_INT8
Definition imageio.h:62
@ FORMAT_FLAGS_NO_TMPFILE
static const float x
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define dt_pdf_point_to_pixel(pt, dpi)
Definition pdf.h:43
static const int dt_pdf_paper_sizes_n
Definition pdf.h:118
static const struct @11 dt_pdf_paper_sizes[]
dt_pdf_stream_encoder_t
Definition pdf.h:47
@ DT_PDF_STREAM_ENCODER_FLATE
Definition pdf.h:49
struct _GtkWidget GtkWidget
Definition splash.h:29
const dt_colorspaces_color_profile_t * profile
struct dt_bauhaus_t * bauhaus
Definition darktable.h:778
GModule *GtkWidget * widget
dt_imageio_module_data_t global
dt_pdf_stream_encoder_t compression
_pdf_orientation_t orientation
dt_imageio_pdf_params_t params
gboolean rotate_to_fit
Definition pdf.h:75
gboolean show_bb
Definition pdf.h:78
gboolean outline_mode
Definition pdf.h:77
Definition pdf.h:53
char * title
Definition pdf.h:61
GtkWidget * rotate
GtkSpinButton * dpi
GtkWidget * icc
GtkWidget * size
GtkWidget * pages
GtkWidget * compression
GtkWidget * orientation
GtkWidget * mode
GtkWidget * bpp
GtkEntry * title
GtkEntry * border
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29