1 /* GIMP - The GNU Image Manipulation Program
2 *
3 * file-pdf-load.c - PDF file loader
4 *
5 * Copyright (C) 2005 Nathan Summers
6 *
7 * Some code in render_page_to_surface() borrowed from
8 * poppler.git/glib/poppler-page.cc.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include <libgimp/gimp.h>
29 #include <libgimp/gimpui.h>
30
31 #undef GTK_DISABLE_SINGLE_INCLUDES
32 #include <poppler.h>
33 #define GTK_DISABLE_SINGLE_INCLUDES
34
35 #include "libgimp/stdplugins-intl.h"
36
37
38 #define LOAD_PROC "file-pdf-load"
39 #define LOAD2_PROC "file-pdf-load2"
40 #define LOAD_THUMB_PROC "file-pdf-load-thumb"
41 #define PLUG_IN_BINARY "file-pdf-load"
42 #define PLUG_IN_ROLE "gimp-file-pdf-load"
43
44 #define THUMBNAIL_SIZE 128
45
46 #define GIMP_PLUGIN_PDF_LOAD_ERROR gimp_plugin_pdf_load_error_quark ()
47 static GQuark
gimp_plugin_pdf_load_error_quark(void)48 gimp_plugin_pdf_load_error_quark (void)
49 {
50 return g_quark_from_static_string ("gimp-plugin-pdf-load-error-quark");
51 }
52
53 /* Structs for the load dialog */
54 typedef struct
55 {
56 GimpPageSelectorTarget target;
57 gdouble resolution;
58 gboolean antialias;
59 gboolean reverse_order;
60 gchar *PDF_password;
61 } PdfLoadVals;
62
63 static PdfLoadVals loadvals =
64 {
65 GIMP_PAGE_SELECTOR_TARGET_LAYERS,
66 100.00, /* resolution in dpi */
67 TRUE, /* antialias */
68 FALSE, /* reverse_order */
69 NULL /* pdf_password */
70 };
71
72 typedef struct
73 {
74 gint n_pages;
75 gint *pages;
76 } PdfSelectedPages;
77
78 /* Declare local functions */
79 static void query (void);
80 static void run (const gchar *name,
81 gint nparams,
82 const GimpParam *param,
83 gint *nreturn_vals,
84 GimpParam **return_vals);
85
86 static gint32 load_image (PopplerDocument *doc,
87 const gchar *filename,
88 GimpRunMode run_mode,
89 GimpPageSelectorTarget target,
90 gdouble resolution,
91 gboolean antialias,
92 gboolean reverse_order,
93 PdfSelectedPages *pages);
94
95 static GimpPDBStatusType load_dialog (PopplerDocument *doc,
96 PdfSelectedPages *pages);
97
98 static PopplerDocument * open_document (const gchar *filename,
99 const gchar *PDF_password,
100 GimpRunMode run_mode,
101 GError **error);
102
103 static cairo_surface_t * get_thumb_surface (PopplerDocument *doc,
104 gint page,
105 gint preferred_size);
106
107 static GdkPixbuf * get_thumb_pixbuf (PopplerDocument *doc,
108 gint page,
109 gint preferred_size);
110
111 static gint32 layer_from_surface (gint32 image,
112 const gchar *layer_name,
113 gint position,
114 cairo_surface_t *surface,
115 gdouble progress_start,
116 gdouble progress_scale);
117
118 /**
119 ** the following was formerly part of
120 ** gimpresolutionentry.h and gimpresolutionentry.c,
121 ** moved here because this is the only thing that uses
122 ** it, and it is undesirable to maintain all that api.
123 ** Most unused functions have been removed.
124 **/
125 #define GIMP_TYPE_RESOLUTION_ENTRY (gimp_resolution_entry_get_type ())
126 #define GIMP_RESOLUTION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_RESOLUTION_ENTRY, GimpResolutionEntry))
127 #define GIMP_RESOLUTION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_RESOLUTION_ENTRY, GimpResolutionEntryClass))
128 #define GIMP_IS_RESOLUTION_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_RESOLUTION_ENTRY))
129 #define GIMP_IS_RESOLUTION_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_RESOLUTION_ENTRY))
130 #define GIMP_RESOLUTION_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_RESOLUTION_ENTRY, GimpResolutionEntryClass))
131
132
133 typedef struct _GimpResolutionEntry GimpResolutionEntry;
134 typedef struct _GimpResolutionEntryClass GimpResolutionEntryClass;
135
136 typedef struct _GimpResolutionEntryField GimpResolutionEntryField;
137
138 struct _GimpResolutionEntryField
139 {
140 GimpResolutionEntry *gre;
141 GimpResolutionEntryField *corresponding;
142
143 gboolean size;
144
145 GtkWidget *label;
146
147 guint changed_signal;
148
149 GtkAdjustment *adjustment;
150 GtkWidget *spinbutton;
151
152 gdouble phy_size;
153
154 gdouble value;
155 gdouble min_value;
156 gdouble max_value;
157
158 gint stop_recursion;
159 };
160
161
162 struct _GimpResolutionEntry
163 {
164 GtkTable parent_instance;
165
166 GimpUnit size_unit;
167 GimpUnit unit;
168
169 GtkWidget *unitmenu;
170 GtkWidget *chainbutton;
171
172 GimpResolutionEntryField width;
173 GimpResolutionEntryField height;
174 GimpResolutionEntryField x;
175 GimpResolutionEntryField y;
176
177 };
178
179 struct _GimpResolutionEntryClass
180 {
181 GtkTableClass parent_class;
182
183 void (* value_changed) (GimpResolutionEntry *gse);
184 void (* refval_changed) (GimpResolutionEntry *gse);
185 void (* unit_changed) (GimpResolutionEntry *gse);
186 };
187
188
189 GType gimp_resolution_entry_get_type (void) G_GNUC_CONST;
190
191 GtkWidget * gimp_resolution_entry_new (const gchar *width_label,
192 gdouble width,
193 const gchar *height_label,
194 gdouble height,
195 GimpUnit size_unit,
196 const gchar *res_label,
197 gdouble initial_res,
198 GimpUnit initial_unit);
199
200 GtkWidget * gimp_resolution_entry_attach_label (GimpResolutionEntry *gre,
201 const gchar *text,
202 gint row,
203 gint column,
204 gfloat alignment);
205
206 gdouble gimp_resolution_entry_get_x_in_dpi (GimpResolutionEntry *gre);
207
208 gdouble gimp_resolution_entry_get_y_in_dpi (GimpResolutionEntry *gre);
209
210
211 /* signal callback convenience functions */
212 void gimp_resolution_entry_update_x_in_dpi (GimpResolutionEntry *gre,
213 gpointer data);
214
215 void gimp_resolution_entry_update_y_in_dpi (GimpResolutionEntry *gre,
216 gpointer data);
217
218
219 enum
220 {
221 WIDTH_CHANGED,
222 HEIGHT_CHANGED,
223 X_CHANGED,
224 Y_CHANGED,
225 UNIT_CHANGED,
226 LAST_SIGNAL
227 };
228
229 static void gimp_resolution_entry_class_init (GimpResolutionEntryClass *class);
230 static void gimp_resolution_entry_init (GimpResolutionEntry *gre);
231
232 static void gimp_resolution_entry_update_value (GimpResolutionEntryField *gref,
233 gdouble value);
234 static void gimp_resolution_entry_value_callback (GtkWidget *widget,
235 gpointer data);
236 static void gimp_resolution_entry_update_unit (GimpResolutionEntry *gre,
237 GimpUnit unit);
238 static void gimp_resolution_entry_unit_callback (GtkWidget *widget,
239 GimpResolutionEntry *gre);
240
241 static void gimp_resolution_entry_field_init (GimpResolutionEntry *gre,
242 GimpResolutionEntryField *gref,
243 GimpResolutionEntryField *corresponding,
244 guint changed_signal,
245 gdouble initial_val,
246 GimpUnit initial_unit,
247 gboolean size,
248 gint spinbutton_width);
249
250 static void gimp_resolution_entry_format_label (GimpResolutionEntry *gre,
251 GtkWidget *label,
252 gdouble size);
253
254 /**
255 ** end of gimpresolutionentry stuff
256 ** the actual code can be found at the end of this file
257 **/
258 const GimpPlugInInfo PLUG_IN_INFO =
259 {
260 NULL, /* init_proc */
261 NULL, /* quit_proc */
262 query, /* query_proc */
263 run, /* run_proc */
264 };
265
266
MAIN()267 MAIN ()
268
269 static void
270 query (void)
271 {
272 static const GimpParamDef load_args[] =
273 {
274 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
275 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
276 { GIMP_PDB_STRING, "raw-filename", "The name entered" }
277 };
278
279 static const GimpParamDef load2_args[] =
280 {
281 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
282 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
283 { GIMP_PDB_STRING, "raw-filename", "The name entered" },
284 { GIMP_PDB_STRING, "pdf-password", "The password to decrypt the encrypted PDF file" },
285 { GIMP_PDB_INT32, "n-pages", "Number of pages to load (0 for all)" },
286 { GIMP_PDB_INT32ARRAY,"pages", "The pages to load in the expected order" },
287 /* XXX: Nice to have API at some point, but needs work
288 { GIMP_PDB_INT32, "resolution", "Resolution to rasterize to (dpi)" },
289 { GIMP_PDB_INT32, "antialiasing", "Use anti-aliasing" }, */
290 };
291
292 static const GimpParamDef load_return_vals[] =
293 {
294 { GIMP_PDB_IMAGE, "image", "Output image" }
295 };
296
297 static const GimpParamDef thumb_args[] =
298 {
299 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
300 { GIMP_PDB_INT32, "thumb-size", "Preferred thumbnail size" }
301 };
302
303 static const GimpParamDef thumb_return_vals[] =
304 {
305 { GIMP_PDB_IMAGE, "image", "Thumbnail image" },
306 { GIMP_PDB_INT32, "image-width", "Width of full-sized image" },
307 { GIMP_PDB_INT32, "image-height", "Height of full-sized image" },
308 { GIMP_PDB_INT32, "image-type", "Image type" },
309 { GIMP_PDB_INT32, "num-layers", "Number of pages" }
310 };
311
312 gimp_install_procedure (LOAD_PROC,
313 "Load file in PDF format",
314 "Loads files in Adobe's Portable Document Format. "
315 "PDF is designed to be easily processed by a variety "
316 "of different platforms, and is a distant cousin of "
317 "PostScript.\n"
318 "If the PDF document has multiple pages, only the first "
319 "page will be loaded. Call file_pdf_load2() to load "
320 "several pages as layers.",
321 "Nathan Summers",
322 "Nathan Summers",
323 "2005",
324 N_("Portable Document Format"),
325 NULL,
326 GIMP_PLUGIN,
327 G_N_ELEMENTS (load_args),
328 G_N_ELEMENTS (load_return_vals),
329 load_args, load_return_vals);
330
331 gimp_install_procedure (LOAD2_PROC,
332 "Load file in PDF format",
333 "Loads files in Adobe's Portable Document Format. "
334 "PDF is designed to be easily processed by a variety "
335 "of different platforms, and is a distant cousin of "
336 "PostScript.\n"
337 "This procedure adds extra parameters to "
338 "file-pdf-load to open encrypted PDF and to allow "
339 "multiple page loading.",
340 "Nathan Summers, Lionel N.",
341 "Nathan Summers, Lionel N.",
342 "2005, 2017",
343 N_("Portable Document Format"),
344 NULL,
345 GIMP_PLUGIN,
346 G_N_ELEMENTS (load2_args),
347 G_N_ELEMENTS (load_return_vals),
348 load2_args, load_return_vals);
349
350 gimp_register_file_handler_mime (LOAD2_PROC, "application/pdf");
351 gimp_register_magic_load_handler (LOAD2_PROC,
352 "pdf",
353 "",
354 "0, string,%PDF-");
355
356 gimp_install_procedure (LOAD_THUMB_PROC,
357 "Loads a preview from a PDF file.",
358 "Loads a small preview of the first page of the PDF "
359 "format file. Uses the embedded thumbnail if "
360 "present.",
361 "Nathan Summers",
362 "Nathan Summers",
363 "2005",
364 NULL,
365 NULL,
366 GIMP_PLUGIN,
367 G_N_ELEMENTS (thumb_args),
368 G_N_ELEMENTS (thumb_return_vals),
369 thumb_args, thumb_return_vals);
370
371 gimp_register_thumbnail_loader (LOAD2_PROC, LOAD_THUMB_PROC);
372 }
373
374 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)375 run (const gchar *name,
376 gint nparams,
377 const GimpParam *param,
378 gint *nreturn_vals,
379 GimpParam **return_vals)
380 {
381 static GimpParam values[7];
382 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
383 gint32 image_ID = -1;
384 PopplerDocument *doc = NULL;
385 GError *error = NULL;
386
387 INIT_I18N ();
388 gegl_init (NULL, NULL);
389
390 *nreturn_vals = 1;
391 *return_vals = values;
392
393 values[0].type = GIMP_PDB_STATUS;
394 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
395
396 if (strcmp (name, LOAD_PROC) == 0 || strcmp (name, LOAD2_PROC) == 0)
397 {
398 PdfSelectedPages pages = { 0, NULL };
399 GimpRunMode run_mode;
400
401 run_mode = param[0].data.d_int32;
402 switch (run_mode)
403 {
404 case GIMP_RUN_INTERACTIVE:
405 /* Possibly retrieve last settings */
406 if (strcmp (name, LOAD_PROC) == 0)
407 {
408 gimp_get_data (LOAD_PROC, &loadvals);
409 }
410 else if (strcmp (name, LOAD2_PROC) == 0)
411 {
412 gimp_get_data (LOAD2_PROC, &loadvals);
413 }
414 gimp_ui_init (PLUG_IN_BINARY, FALSE);
415 doc = open_document (param[1].data.d_string,
416 loadvals.PDF_password,
417 run_mode, &error);
418
419 if (!doc)
420 {
421 status = GIMP_PDB_EXECUTION_ERROR;
422 break;
423 }
424
425 status = load_dialog (doc, &pages);
426 if (status == GIMP_PDB_SUCCESS)
427 {
428 if (strcmp (name, LOAD_PROC) == 0)
429 {
430 gimp_set_data (LOAD_PROC, &loadvals, sizeof(loadvals));
431 }
432 else if (strcmp (name, LOAD2_PROC) == 0)
433 {
434 gimp_set_data (LOAD2_PROC, &loadvals, sizeof(loadvals));
435 }
436 }
437 break;
438
439 case GIMP_RUN_WITH_LAST_VALS:
440 /* FIXME: implement last vals mode */
441 status = GIMP_PDB_EXECUTION_ERROR;
442 break;
443
444 case GIMP_RUN_NONINTERACTIVE:
445 if (strcmp (name, LOAD_PROC) == 0)
446 {
447 doc = open_document (param[1].data.d_string,
448 NULL, run_mode, &error);
449 }
450 else if (strcmp (name, LOAD2_PROC) == 0)
451 {
452 doc = open_document (param[1].data.d_string,
453 param[3].data.d_string,
454 run_mode, &error);
455 }
456
457 if (doc)
458 {
459 PopplerPage *test_page = poppler_document_get_page (doc, 0);
460
461 if (test_page)
462 {
463 if (strcmp (name, LOAD2_PROC) != 0)
464 {
465 /* For retrocompatibility, file-pdf-load always
466 * just loads the first page. */
467 pages.n_pages = 1;
468 pages.pages = g_new (gint, 1);
469 pages.pages[0] = 0;
470
471 g_object_unref (test_page);
472 }
473 else
474 {
475 gint i;
476 gint doc_n_pages;
477
478 doc_n_pages = poppler_document_get_n_pages (doc);
479 /* The number of imported pages may be bigger than
480 * the number of pages from the original document.
481 * Indeed it is possible to duplicate some pages
482 * by setting the same number several times in the
483 * "pages" argument.
484 * Not ceiling this value is *not* an error.
485 */
486 pages.n_pages = param[4].data.d_int32;
487 if (pages.n_pages <= 0)
488 {
489 pages.n_pages = doc_n_pages;
490 pages.pages = g_new (gint, pages.n_pages);
491 for (i = 0; i < pages.n_pages; i++)
492 pages.pages[i] = i;
493 }
494 else
495 {
496 pages.pages = g_new (gint, pages.n_pages);
497 for (i = 0; i < pages.n_pages; i++)
498 {
499 if (param[5].data.d_int32array[i] >= doc_n_pages)
500 {
501 status = GIMP_PDB_EXECUTION_ERROR;
502 g_set_error (&error, GIMP_PLUGIN_PDF_LOAD_ERROR, 0,
503 /* TRANSLATORS: first argument is file name,
504 * second is out-of-range page number, third is
505 * number of pages. Specify order as in English if needed.
506 */
507 ngettext ("PDF document '%1$s' has %3$d page. Page %2$d is out of range.",
508 "PDF document '%1$s' has %3$d pages. Page %2$d is out of range.",
509 doc_n_pages),
510 param[1].data.d_string,
511 param[5].data.d_int32array[i],
512 doc_n_pages);
513 break;
514 }
515 else
516 {
517 pages.pages[i] = param[5].data.d_int32array[i];
518 }
519 }
520 }
521 g_object_unref (test_page);
522 }
523 }
524 else
525 {
526 status = GIMP_PDB_EXECUTION_ERROR;
527 g_object_unref (doc);
528 }
529 }
530 else
531 {
532 status = GIMP_PDB_EXECUTION_ERROR;
533 }
534 break;
535 }
536
537 if (status == GIMP_PDB_SUCCESS)
538 {
539 image_ID = load_image (doc, param[1].data.d_string,
540 run_mode,
541 loadvals.target,
542 loadvals.resolution,
543 loadvals.antialias,
544 loadvals.reverse_order,
545 &pages);
546
547 if (image_ID != -1)
548 {
549 *nreturn_vals = 2;
550 values[1].type = GIMP_PDB_IMAGE;
551 values[1].data.d_image = image_ID;
552 }
553 else
554 {
555 status = GIMP_PDB_EXECUTION_ERROR;
556 }
557 }
558
559 if (doc)
560 g_object_unref (doc);
561
562 g_free (pages.pages);
563 }
564 else if (strcmp (name, LOAD_THUMB_PROC) == 0)
565 {
566 if (nparams < 2)
567 {
568 status = GIMP_PDB_CALLING_ERROR;
569 }
570 else
571 {
572 gdouble width = 0;
573 gdouble height = 0;
574 gdouble scale;
575 gint32 image = -1;
576 gint num_pages = 0;
577 cairo_surface_t *surface = NULL;
578
579 /* Possibly retrieve last settings */
580 if (strcmp (name, LOAD_PROC) == 0)
581 {
582 gimp_get_data (LOAD_PROC, &loadvals);
583 }
584 else if (strcmp (name, LOAD2_PROC) == 0)
585 {
586 gimp_get_data (LOAD2_PROC, &loadvals);
587 }
588
589 doc = open_document (param[0].data.d_string,
590 loadvals.PDF_password,
591 GIMP_RUN_NONINTERACTIVE,
592 &error);
593
594 if (doc)
595 {
596 PopplerPage *page = poppler_document_get_page (doc, 0);
597
598 if (page)
599 {
600 poppler_page_get_size (page, &width, &height);
601
602 g_object_unref (page);
603 }
604
605 num_pages = poppler_document_get_n_pages (doc);
606
607 surface = get_thumb_surface (doc, 0, param[1].data.d_int32);
608
609 g_object_unref (doc);
610 }
611
612 if (surface)
613 {
614 image = gimp_image_new (cairo_image_surface_get_width (surface),
615 cairo_image_surface_get_height (surface),
616 GIMP_RGB);
617
618 gimp_image_undo_disable (image);
619
620
621 layer_from_surface (image, "thumbnail", 0, surface, 0.0, 1.0);
622 cairo_surface_destroy (surface);
623
624 gimp_image_undo_enable (image);
625 gimp_image_clean_all (image);
626 }
627
628 scale = loadvals.resolution / gimp_unit_get_factor (GIMP_UNIT_POINT);
629
630 width *= scale;
631 height *= scale;
632
633 if (image != -1)
634 {
635 *nreturn_vals = 6;
636
637 values[1].type = GIMP_PDB_IMAGE;
638 values[1].data.d_image = image;
639 values[2].type = GIMP_PDB_INT32;
640 values[2].data.d_int32 = width;
641 values[3].type = GIMP_PDB_INT32;
642 values[3].data.d_int32 = height;
643 values[4].type = GIMP_PDB_INT32;
644 values[4].data.d_int32 = GIMP_RGB_IMAGE;
645 values[5].type = GIMP_PDB_INT32;
646 values[5].data.d_int32 = num_pages;
647 }
648 else
649 {
650 status = GIMP_PDB_EXECUTION_ERROR;
651 }
652 }
653
654 }
655 else
656 {
657 status = GIMP_PDB_CALLING_ERROR;
658 }
659
660 if (status != GIMP_PDB_SUCCESS && error)
661 {
662 *nreturn_vals = 2;
663 values[1].type = GIMP_PDB_STRING;
664 values[1].data.d_string = error->message;
665 }
666
667 values[0].data.d_status = status;
668
669 gegl_exit ();
670 }
671
672 static PopplerDocument*
open_document(const gchar * filename,const gchar * PDF_password,GimpRunMode run_mode,GError ** load_error)673 open_document (const gchar *filename,
674 const gchar *PDF_password,
675 GimpRunMode run_mode,
676 GError **load_error)
677 {
678 PopplerDocument *doc;
679 GFile *file;
680 GError *error = NULL;
681
682 file = g_file_new_for_path (filename);
683 doc = poppler_document_new_from_gfile (file, PDF_password, NULL, &error);
684
685 if (run_mode == GIMP_RUN_INTERACTIVE)
686 {
687 GtkWidget *label;
688
689 label = gtk_label_new (_("PDF is password protected, please input the password:"));
690 while (error &&
691 error->domain == POPPLER_ERROR &&
692 error->code == POPPLER_ERROR_ENCRYPTED)
693 {
694 GtkWidget *vbox;
695 GtkWidget *dialog;
696 GtkWidget *entry;
697 gint run;
698
699 dialog = gimp_dialog_new (_("Encrypted PDF"), PLUG_IN_ROLE,
700 NULL, 0,
701 NULL, NULL,
702 _("_Cancel"), GTK_RESPONSE_CANCEL,
703 _("_OK"), GTK_RESPONSE_OK,
704 NULL);
705 gimp_window_set_transient (GTK_WINDOW (dialog));
706 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
707 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
708 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
709 vbox, TRUE, TRUE, 0);
710 entry = gtk_entry_new ();
711 gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
712 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
713 gtk_container_add (GTK_CONTAINER (vbox), label);
714 gtk_container_add (GTK_CONTAINER (vbox), entry);
715
716 gtk_widget_show_all (dialog);
717
718 run = gimp_dialog_run (GIMP_DIALOG (dialog));
719 if (run == GTK_RESPONSE_OK)
720 {
721 g_clear_error (&error);
722 doc = poppler_document_new_from_gfile (file,
723 gtk_entry_get_text (GTK_ENTRY (entry)),
724 NULL, &error);
725 }
726 label = gtk_label_new (_("Wrong password! Please input the right one:"));
727 gtk_widget_destroy (dialog);
728 if (run == GTK_RESPONSE_CANCEL || run == GTK_RESPONSE_DELETE_EVENT)
729 {
730 break;
731 }
732 }
733 gtk_widget_destroy (label);
734 }
735 g_object_unref (file);
736
737 /* We can't g_mapped_file_unref(mapped_file) as apparently doc has
738 * references to data in there. No big deal, this is just a
739 * short-lived plug-in.
740 */
741 if (! doc)
742 {
743 g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
744 _("Could not load '%s': %s"),
745 gimp_filename_to_utf8 (filename),
746 error->message);
747 g_error_free (error);
748 return NULL;
749 }
750
751 return doc;
752 }
753
754 /* FIXME: Remove this someday when we depend fully on GTK+ >= 3 */
755
756 #if (!GTK_CHECK_VERSION (3, 0, 0))
757
758 static cairo_format_t
gdk_cairo_format_for_content(cairo_content_t content)759 gdk_cairo_format_for_content (cairo_content_t content)
760 {
761 switch (content)
762 {
763 case CAIRO_CONTENT_COLOR:
764 return CAIRO_FORMAT_RGB24;
765 case CAIRO_CONTENT_ALPHA:
766 return CAIRO_FORMAT_A8;
767 case CAIRO_CONTENT_COLOR_ALPHA:
768 default:
769 return CAIRO_FORMAT_ARGB32;
770 }
771 }
772
773 static cairo_surface_t *
gdk_cairo_surface_coerce_to_image(cairo_surface_t * surface,cairo_content_t content,int src_x,int src_y,int width,int height)774 gdk_cairo_surface_coerce_to_image (cairo_surface_t *surface,
775 cairo_content_t content,
776 int src_x,
777 int src_y,
778 int width,
779 int height)
780 {
781 cairo_surface_t *copy;
782 cairo_t *cr;
783
784 copy = cairo_image_surface_create (gdk_cairo_format_for_content (content),
785 width,
786 height);
787
788 cr = cairo_create (copy);
789 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
790 cairo_set_source_surface (cr, surface, -src_x, -src_y);
791 cairo_paint (cr);
792 cairo_destroy (cr);
793
794 return copy;
795 }
796
797 static void
convert_alpha(guchar * dest_data,int dest_stride,guchar * src_data,int src_stride,int src_x,int src_y,int width,int height)798 convert_alpha (guchar *dest_data,
799 int dest_stride,
800 guchar *src_data,
801 int src_stride,
802 int src_x,
803 int src_y,
804 int width,
805 int height)
806 {
807 int x, y;
808
809 src_data += src_stride * src_y + src_x * 4;
810
811 for (y = 0; y < height; y++) {
812 guint32 *src = (guint32 *) src_data;
813
814 for (x = 0; x < width; x++) {
815 guint alpha = src[x] >> 24;
816
817 if (alpha == 0)
818 {
819 dest_data[x * 4 + 0] = 0;
820 dest_data[x * 4 + 1] = 0;
821 dest_data[x * 4 + 2] = 0;
822 }
823 else
824 {
825 dest_data[x * 4 + 0] = (((src[x] & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
826 dest_data[x * 4 + 1] = (((src[x] & 0x00ff00) >> 8) * 255 + alpha / 2) / alpha;
827 dest_data[x * 4 + 2] = (((src[x] & 0x0000ff) >> 0) * 255 + alpha / 2) / alpha;
828 }
829 dest_data[x * 4 + 3] = alpha;
830 }
831
832 src_data += src_stride;
833 dest_data += dest_stride;
834 }
835 }
836
837 static void
convert_no_alpha(guchar * dest_data,int dest_stride,guchar * src_data,int src_stride,int src_x,int src_y,int width,int height)838 convert_no_alpha (guchar *dest_data,
839 int dest_stride,
840 guchar *src_data,
841 int src_stride,
842 int src_x,
843 int src_y,
844 int width,
845 int height)
846 {
847 int x, y;
848
849 src_data += src_stride * src_y + src_x * 4;
850
851 for (y = 0; y < height; y++) {
852 guint32 *src = (guint32 *) src_data;
853
854 for (x = 0; x < width; x++) {
855 dest_data[x * 3 + 0] = src[x] >> 16;
856 dest_data[x * 3 + 1] = src[x] >> 8;
857 dest_data[x * 3 + 2] = src[x];
858 }
859
860 src_data += src_stride;
861 dest_data += dest_stride;
862 }
863 }
864
865 /**
866 * gdk_pixbuf_get_from_surface:
867 * @surface: surface to copy from
868 * @src_x: Source X coordinate within @surface
869 * @src_y: Source Y coordinate within @surface
870 * @width: Width in pixels of region to get
871 * @height: Height in pixels of region to get
872 *
873 * Transfers image data from a #cairo_surface_t and converts it to an RGB(A)
874 * representation inside a #GdkPixbuf. This allows you to efficiently read
875 * individual pixels from cairo surfaces. For #GdkWindows, use
876 * gdk_pixbuf_get_from_window() instead.
877 *
878 * This function will create an RGB pixbuf with 8 bits per channel.
879 * The pixbuf will contain an alpha channel if the @surface contains one.
880 *
881 * Return value: (transfer full): A newly-created pixbuf with a reference
882 * count of 1, or %NULL on error
883 */
884 static GdkPixbuf *
gdk_pixbuf_get_from_surface(cairo_surface_t * surface,gint src_x,gint src_y,gint width,gint height)885 gdk_pixbuf_get_from_surface (cairo_surface_t *surface,
886 gint src_x,
887 gint src_y,
888 gint width,
889 gint height)
890 {
891 cairo_content_t content;
892 GdkPixbuf *dest;
893
894 /* General sanity checks */
895 g_return_val_if_fail (surface != NULL, NULL);
896 g_return_val_if_fail (width > 0 && height > 0, NULL);
897
898 content = cairo_surface_get_content (surface) | CAIRO_CONTENT_COLOR;
899 dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
900 !!(content & CAIRO_CONTENT_ALPHA),
901 8,
902 width, height);
903
904 surface = gdk_cairo_surface_coerce_to_image (surface, content,
905 src_x, src_y,
906 width, height);
907 cairo_surface_flush (surface);
908 if (cairo_surface_status (surface) || dest == NULL)
909 {
910 cairo_surface_destroy (surface);
911 return NULL;
912 }
913
914 if (gdk_pixbuf_get_has_alpha (dest))
915 convert_alpha (gdk_pixbuf_get_pixels (dest),
916 gdk_pixbuf_get_rowstride (dest),
917 cairo_image_surface_get_data (surface),
918 cairo_image_surface_get_stride (surface),
919 0, 0,
920 width, height);
921 else
922 convert_no_alpha (gdk_pixbuf_get_pixels (dest),
923 gdk_pixbuf_get_rowstride (dest),
924 cairo_image_surface_get_data (surface),
925 cairo_image_surface_get_stride (surface),
926 0, 0,
927 width, height);
928
929 cairo_surface_destroy (surface);
930 return dest;
931 }
932
933 #endif
934
935 static gint32
layer_from_surface(gint32 image,const gchar * layer_name,gint position,cairo_surface_t * surface,gdouble progress_start,gdouble progress_scale)936 layer_from_surface (gint32 image,
937 const gchar *layer_name,
938 gint position,
939 cairo_surface_t *surface,
940 gdouble progress_start,
941 gdouble progress_scale)
942 {
943 gint32 layer;
944
945 layer = gimp_layer_new_from_surface (image, layer_name, surface,
946 progress_start,
947 progress_start + progress_scale);
948 gimp_image_insert_layer (image, layer, -1, position);
949
950 return layer;
951 }
952
953 static cairo_surface_t *
render_page_to_surface(PopplerPage * page,int width,int height,double scale,gboolean antialias)954 render_page_to_surface (PopplerPage *page,
955 int width,
956 int height,
957 double scale,
958 gboolean antialias)
959 {
960 cairo_surface_t *surface;
961 cairo_t *cr;
962
963 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
964 cr = cairo_create (surface);
965
966 cairo_save (cr);
967 cairo_translate (cr, 0.0, 0.0);
968
969 if (scale != 1.0)
970 cairo_scale (cr, scale, scale);
971
972 if (! antialias)
973 {
974 cairo_font_options_t *options = cairo_font_options_create ();
975
976 cairo_get_font_options (cr, options);
977 cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_NONE);
978 cairo_set_font_options (cr, options);
979 cairo_font_options_destroy (options);
980
981 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
982 }
983
984 poppler_page_render (page, cr);
985 cairo_restore (cr);
986
987 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
988 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
989 cairo_paint (cr);
990
991 cairo_destroy (cr);
992
993 return surface;
994 }
995
996 #if 0
997
998 /* This is currently unused, but we'll have it here in case the military
999 wants it. */
1000
1001 static GdkPixbuf *
1002 render_page_to_pixbuf (PopplerPage *page,
1003 int width,
1004 int height,
1005 double scale)
1006 {
1007 GdkPixbuf *pixbuf;
1008 cairo_surface_t *surface;
1009
1010 surface = render_page_to_surface (page, width, height, scale);
1011 pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
1012 cairo_image_surface_get_width (surface),
1013 cairo_image_surface_get_height (surface));
1014 cairo_surface_destroy (surface);
1015
1016 return pixbuf;
1017 }
1018
1019 #endif
1020
1021 static gint32
load_image(PopplerDocument * doc,const gchar * filename,GimpRunMode run_mode,GimpPageSelectorTarget target,gdouble resolution,gboolean antialias,gboolean reverse_order,PdfSelectedPages * pages)1022 load_image (PopplerDocument *doc,
1023 const gchar *filename,
1024 GimpRunMode run_mode,
1025 GimpPageSelectorTarget target,
1026 gdouble resolution,
1027 gboolean antialias,
1028 gboolean reverse_order,
1029 PdfSelectedPages *pages)
1030 {
1031 gint32 image_ID = 0;
1032 gint32 *images = NULL;
1033 gint i;
1034 gdouble scale;
1035 gdouble doc_progress = 0;
1036 gint base_index = 0;
1037 gint sign = 1;
1038
1039 if (reverse_order && pages->n_pages > 0)
1040 {
1041 base_index = pages->n_pages - 1;
1042 sign = -1;
1043 }
1044
1045 if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
1046 images = g_new0 (gint32, pages->n_pages);
1047
1048 gimp_progress_init_printf (_("Opening '%s'"),
1049 gimp_filename_to_utf8 (filename));
1050
1051 scale = resolution / gimp_unit_get_factor (GIMP_UNIT_POINT);
1052
1053 /* read the file */
1054
1055 for (i = 0; i < pages->n_pages; i++)
1056 {
1057 PopplerPage *page;
1058 gchar *page_label;
1059 gdouble page_width;
1060 gdouble page_height;
1061
1062 cairo_surface_t *surface;
1063 gint width;
1064 gint height;
1065 gint page_index;
1066
1067 page_index = base_index + sign * i;
1068
1069 page = poppler_document_get_page (doc, pages->pages[page_index]);
1070
1071 poppler_page_get_size (page, &page_width, &page_height);
1072 width = page_width * scale;
1073 height = page_height * scale;
1074
1075 g_object_get (G_OBJECT (page), "label", &page_label, NULL);
1076
1077 if (! image_ID)
1078 {
1079 gchar *name;
1080
1081 image_ID = gimp_image_new (width, height, GIMP_RGB);
1082 gimp_image_undo_disable (image_ID);
1083
1084 if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
1085 name = g_strdup_printf (_("%s-%s"), filename, page_label);
1086 else
1087 name = g_strdup_printf (_("%s-pages"), filename);
1088
1089 gimp_image_set_filename (image_ID, name);
1090 g_free (name);
1091
1092 gimp_image_set_resolution (image_ID, resolution, resolution);
1093 }
1094
1095 surface = render_page_to_surface (page, width, height, scale, antialias);
1096
1097 layer_from_surface (image_ID, page_label, 0, surface,
1098 doc_progress, 1.0 / pages->n_pages);
1099
1100 g_free (page_label);
1101 cairo_surface_destroy (surface);
1102
1103 doc_progress = (double) (i + 1) / pages->n_pages;
1104 gimp_progress_update (doc_progress);
1105
1106 if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
1107 {
1108 images[i] = image_ID;
1109
1110 gimp_image_undo_enable (image_ID);
1111 gimp_image_clean_all (image_ID);
1112
1113 image_ID = 0;
1114 }
1115 }
1116 gimp_progress_update (1.0);
1117
1118 if (image_ID)
1119 {
1120 gimp_image_undo_enable (image_ID);
1121 gimp_image_clean_all (image_ID);
1122 }
1123
1124 if (target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
1125 {
1126 if (run_mode != GIMP_RUN_NONINTERACTIVE)
1127 {
1128 /* Display images in reverse order. The last will be
1129 * displayed by GIMP itself
1130 */
1131 for (i = pages->n_pages - 1; i > 0; i--)
1132 gimp_display_new (images[i]);
1133 }
1134
1135 image_ID = images[0];
1136
1137 g_free (images);
1138 }
1139
1140 return image_ID;
1141 }
1142
1143 static cairo_surface_t *
get_thumb_surface(PopplerDocument * doc,gint page_num,gint preferred_size)1144 get_thumb_surface (PopplerDocument *doc,
1145 gint page_num,
1146 gint preferred_size)
1147 {
1148 PopplerPage *page;
1149 cairo_surface_t *surface;
1150
1151 page = poppler_document_get_page (doc, page_num);
1152
1153 if (! page)
1154 return NULL;
1155
1156 surface = poppler_page_get_thumbnail (page);
1157
1158 if (! surface)
1159 {
1160 gdouble width;
1161 gdouble height;
1162 gdouble scale;
1163
1164 poppler_page_get_size (page, &width, &height);
1165
1166 scale = (gdouble) preferred_size / MAX (width, height);
1167
1168 width *= scale;
1169 height *= scale;
1170
1171 surface = render_page_to_surface (page, width, height, scale, TRUE);
1172 }
1173
1174 g_object_unref (page);
1175
1176 return surface;
1177 }
1178
1179 static GdkPixbuf *
get_thumb_pixbuf(PopplerDocument * doc,gint page_num,gint preferred_size)1180 get_thumb_pixbuf (PopplerDocument *doc,
1181 gint page_num,
1182 gint preferred_size)
1183 {
1184 cairo_surface_t *surface;
1185 GdkPixbuf *pixbuf;
1186
1187 surface = get_thumb_surface (doc, page_num, preferred_size);
1188 pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0,
1189 cairo_image_surface_get_width (surface),
1190 cairo_image_surface_get_height (surface));
1191 cairo_surface_destroy (surface);
1192
1193 return pixbuf;
1194 }
1195
1196 typedef struct
1197 {
1198 PopplerDocument *document;
1199 GimpPageSelector *selector;
1200 gboolean stop_thumbnailing;
1201 } ThreadData;
1202
1203 typedef struct
1204 {
1205 GimpPageSelector *selector;
1206 gint page_no;
1207 GdkPixbuf *pixbuf;
1208 } IdleData;
1209
1210 static gboolean
idle_set_thumbnail(gpointer data)1211 idle_set_thumbnail (gpointer data)
1212 {
1213 IdleData *idle_data = data;
1214
1215 gimp_page_selector_set_page_thumbnail (idle_data->selector,
1216 idle_data->page_no,
1217 idle_data->pixbuf);
1218 g_object_unref (idle_data->pixbuf);
1219 g_free (idle_data);
1220
1221 return FALSE;
1222 }
1223
1224 static gpointer
thumbnail_thread(gpointer data)1225 thumbnail_thread (gpointer data)
1226 {
1227 ThreadData *thread_data = data;
1228 gint n_pages;
1229 gint i;
1230
1231 n_pages = poppler_document_get_n_pages (thread_data->document);
1232
1233 for (i = 0; i < n_pages; i++)
1234 {
1235 IdleData *idle_data = g_new0 (IdleData, 1);
1236
1237 idle_data->selector = thread_data->selector;
1238 idle_data->page_no = i;
1239
1240 /* FIXME get preferred size from somewhere? */
1241 idle_data->pixbuf = get_thumb_pixbuf (thread_data->document, i,
1242 THUMBNAIL_SIZE);
1243
1244 g_idle_add (idle_set_thumbnail, idle_data);
1245
1246 if (thread_data->stop_thumbnailing)
1247 break;
1248 }
1249
1250 return NULL;
1251 }
1252
1253 static GimpPDBStatusType
load_dialog(PopplerDocument * doc,PdfSelectedPages * pages)1254 load_dialog (PopplerDocument *doc,
1255 PdfSelectedPages *pages)
1256 {
1257 GtkWidget *dialog;
1258 GtkWidget *vbox;
1259 GtkWidget *title;
1260 GtkWidget *selector;
1261 GtkWidget *resolution;
1262 GtkWidget *antialias;
1263 GtkWidget *hbox;
1264 GtkWidget *reverse_order;
1265 GtkWidget *separator;
1266
1267 ThreadData thread_data;
1268 GThread *thread;
1269
1270 gint i;
1271 gint n_pages;
1272
1273 gdouble width;
1274 gdouble height;
1275
1276 gboolean run;
1277
1278 dialog = gimp_dialog_new (_("Import from PDF"), PLUG_IN_ROLE,
1279 NULL, 0,
1280 gimp_standard_help_func, LOAD_PROC,
1281
1282 _("_Cancel"), GTK_RESPONSE_CANCEL,
1283 _("_Import"), GTK_RESPONSE_OK,
1284
1285 NULL);
1286
1287 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
1288 GTK_RESPONSE_OK,
1289 GTK_RESPONSE_CANCEL,
1290 -1);
1291
1292 gimp_window_set_transient (GTK_WINDOW (dialog));
1293
1294 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
1295 gtk_container_set_border_width (GTK_CONTAINER (vbox), 12);
1296 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
1297 vbox, TRUE, TRUE, 0);
1298 gtk_widget_show (vbox);
1299
1300 /* Title */
1301 title = gimp_prop_label_new (G_OBJECT (doc), "title");
1302 gtk_label_set_ellipsize (GTK_LABEL (title), PANGO_ELLIPSIZE_END);
1303 gtk_box_pack_start (GTK_BOX (vbox), title, FALSE, FALSE, 0);
1304 gtk_widget_show (title);
1305
1306 /* Page Selector */
1307 selector = gimp_page_selector_new ();
1308 gtk_widget_set_size_request (selector, 380, 360);
1309 gtk_box_pack_start (GTK_BOX (vbox), selector, TRUE, TRUE, 0);
1310 gtk_widget_show (selector);
1311
1312 n_pages = poppler_document_get_n_pages (doc);
1313
1314 if (n_pages <= 0)
1315 {
1316 g_message (_("Error getting number of pages from the given PDF file."));
1317 return GIMP_PDB_EXECUTION_ERROR;
1318 }
1319
1320 gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (selector), n_pages);
1321 gimp_page_selector_set_target (GIMP_PAGE_SELECTOR (selector),
1322 loadvals.target);
1323
1324 for (i = 0; i < n_pages; i++)
1325 {
1326 PopplerPage *page;
1327 gchar *label;
1328
1329 page = poppler_document_get_page (doc, i);
1330 g_object_get (G_OBJECT (page), "label", &label, NULL);
1331
1332 gimp_page_selector_set_page_label (GIMP_PAGE_SELECTOR (selector), i,
1333 label);
1334
1335 if (i == 0)
1336 poppler_page_get_size (page, &width, &height);
1337
1338 g_object_unref (page);
1339 g_free (label);
1340 }
1341 /* Since selecting none will be equivalent to selecting all, this is
1342 * only useful as a feedback for the default behavior of selecting all
1343 * pages. */
1344 gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (selector));
1345
1346 g_signal_connect_swapped (selector, "activate",
1347 G_CALLBACK (gtk_window_activate_default),
1348 dialog);
1349
1350 thread_data.document = doc;
1351 thread_data.selector = GIMP_PAGE_SELECTOR (selector);
1352 thread_data.stop_thumbnailing = FALSE;
1353
1354 thread = g_thread_new ("thumbnailer", thumbnail_thread, &thread_data);
1355
1356 /* "Load in reverse order" toggle button */
1357 reverse_order = gtk_check_button_new_with_mnemonic (_("Load in reverse order"));
1358 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (reverse_order), loadvals.reverse_order);
1359 gtk_box_pack_start (GTK_BOX (vbox), reverse_order, FALSE, FALSE, 0);
1360
1361 g_signal_connect (reverse_order, "toggled",
1362 G_CALLBACK (gimp_toggle_button_update), &loadvals.reverse_order);
1363 gtk_widget_show (reverse_order);
1364
1365 /* Separator */
1366 separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
1367 gtk_box_pack_start (GTK_BOX (vbox), separator, FALSE, FALSE, 0);
1368 gtk_widget_show (separator);
1369
1370 /* Resolution */
1371 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1372 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
1373 gtk_widget_show (hbox);
1374
1375 resolution = gimp_resolution_entry_new (_("_Width (pixels):"), width,
1376 _("_Height (pixels):"), height,
1377 GIMP_UNIT_POINT,
1378 _("_Resolution:"),
1379 loadvals.resolution, GIMP_UNIT_INCH);
1380
1381 gtk_box_pack_start (GTK_BOX (hbox), resolution, FALSE, FALSE, 0);
1382 gtk_widget_show (resolution);
1383
1384 g_signal_connect (resolution, "x-changed",
1385 G_CALLBACK (gimp_resolution_entry_update_x_in_dpi),
1386 &loadvals.resolution);
1387
1388 /* Antialiasing*/
1389 antialias = gtk_check_button_new_with_mnemonic (_("Use _Anti-aliasing"));
1390 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (antialias), loadvals.antialias);
1391 gtk_box_pack_start (GTK_BOX (vbox), antialias, FALSE, FALSE, 0);
1392
1393 g_signal_connect (antialias, "toggled",
1394 G_CALLBACK (gimp_toggle_button_update), &loadvals.antialias);
1395 gtk_widget_show (antialias);
1396
1397 /* Setup done; display the dialog */
1398 gtk_widget_show (dialog);
1399
1400 /* run the dialog */
1401 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
1402
1403 loadvals.target =
1404 gimp_page_selector_get_target (GIMP_PAGE_SELECTOR (selector));
1405
1406 pages->pages =
1407 gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (selector),
1408 &pages->n_pages);
1409
1410 /* select all if none selected */
1411 if (pages->n_pages == 0)
1412 {
1413 gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (selector));
1414
1415 pages->pages =
1416 gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (selector),
1417 &pages->n_pages);
1418 }
1419
1420 /* cleanup */
1421 thread_data.stop_thumbnailing = TRUE;
1422 g_thread_join (thread);
1423
1424 return run ? GIMP_PDB_SUCCESS : GIMP_PDB_CANCEL;
1425 }
1426
1427
1428 /**
1429 ** code for GimpResolutionEntry widget, formerly in libgimpwidgets
1430 **/
1431
1432 static guint gimp_resolution_entry_signals[LAST_SIGNAL] = { 0 };
1433
1434 static GtkTableClass *parent_class = NULL;
1435
1436
1437 GType
gimp_resolution_entry_get_type(void)1438 gimp_resolution_entry_get_type (void)
1439 {
1440 static GType gre_type = 0;
1441
1442 if (! gre_type)
1443 {
1444 const GTypeInfo gre_info =
1445 {
1446 sizeof (GimpResolutionEntryClass),
1447 (GBaseInitFunc) NULL,
1448 (GBaseFinalizeFunc) NULL,
1449 (GClassInitFunc) gimp_resolution_entry_class_init,
1450 NULL, /* class_finalize */
1451 NULL, /* class_data */
1452 sizeof (GimpResolutionEntry),
1453 0, /* n_preallocs */
1454 (GInstanceInitFunc) gimp_resolution_entry_init,
1455 };
1456
1457 gre_type = g_type_register_static (GTK_TYPE_TABLE,
1458 "GimpResolutionEntry",
1459 &gre_info, 0);
1460 }
1461
1462 return gre_type;
1463 }
1464
1465 static void
gimp_resolution_entry_class_init(GimpResolutionEntryClass * klass)1466 gimp_resolution_entry_class_init (GimpResolutionEntryClass *klass)
1467 {
1468 parent_class = g_type_class_peek_parent (klass);
1469
1470 gimp_resolution_entry_signals[HEIGHT_CHANGED] =
1471 g_signal_new ("height-changed",
1472 G_TYPE_FROM_CLASS (klass),
1473 G_SIGNAL_RUN_FIRST,
1474 G_STRUCT_OFFSET (GimpResolutionEntryClass, value_changed),
1475 NULL, NULL,
1476 g_cclosure_marshal_VOID__VOID,
1477 G_TYPE_NONE, 0);
1478
1479 gimp_resolution_entry_signals[WIDTH_CHANGED] =
1480 g_signal_new ("width-changed",
1481 G_TYPE_FROM_CLASS (klass),
1482 G_SIGNAL_RUN_FIRST,
1483 G_STRUCT_OFFSET (GimpResolutionEntryClass, value_changed),
1484 NULL, NULL,
1485 g_cclosure_marshal_VOID__VOID,
1486 G_TYPE_NONE, 0);
1487
1488 gimp_resolution_entry_signals[X_CHANGED] =
1489 g_signal_new ("x-changed",
1490 G_TYPE_FROM_CLASS (klass),
1491 G_SIGNAL_RUN_FIRST,
1492 G_STRUCT_OFFSET (GimpResolutionEntryClass, value_changed),
1493 NULL, NULL,
1494 g_cclosure_marshal_VOID__VOID,
1495 G_TYPE_NONE, 0);
1496
1497 gimp_resolution_entry_signals[Y_CHANGED] =
1498 g_signal_new ("y-changed",
1499 G_TYPE_FROM_CLASS (klass),
1500 G_SIGNAL_RUN_FIRST,
1501 G_STRUCT_OFFSET (GimpResolutionEntryClass, refval_changed),
1502 NULL, NULL,
1503 g_cclosure_marshal_VOID__VOID,
1504 G_TYPE_NONE, 0);
1505
1506 gimp_resolution_entry_signals[UNIT_CHANGED] =
1507 g_signal_new ("unit-changed",
1508 G_TYPE_FROM_CLASS (klass),
1509 G_SIGNAL_RUN_FIRST,
1510 G_STRUCT_OFFSET (GimpResolutionEntryClass, unit_changed),
1511 NULL, NULL,
1512 g_cclosure_marshal_VOID__VOID,
1513 G_TYPE_NONE, 0);
1514
1515 klass->value_changed = NULL;
1516 klass->refval_changed = NULL;
1517 klass->unit_changed = NULL;
1518 }
1519
1520 static void
gimp_resolution_entry_init(GimpResolutionEntry * gre)1521 gimp_resolution_entry_init (GimpResolutionEntry *gre)
1522 {
1523 gre->unitmenu = NULL;
1524 gre->unit = GIMP_UNIT_INCH;
1525
1526 gtk_table_set_col_spacings (GTK_TABLE (gre), 4);
1527 gtk_table_set_row_spacings (GTK_TABLE (gre), 2);
1528 }
1529
1530 static void
gimp_resolution_entry_field_init(GimpResolutionEntry * gre,GimpResolutionEntryField * gref,GimpResolutionEntryField * corresponding,guint changed_signal,gdouble initial_val,GimpUnit initial_unit,gboolean size,gint spinbutton_width)1531 gimp_resolution_entry_field_init (GimpResolutionEntry *gre,
1532 GimpResolutionEntryField *gref,
1533 GimpResolutionEntryField *corresponding,
1534 guint changed_signal,
1535 gdouble initial_val,
1536 GimpUnit initial_unit,
1537 gboolean size,
1538 gint spinbutton_width)
1539 {
1540 gint digits;
1541
1542 g_return_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre));
1543
1544 gref->gre = gre;
1545 gref->corresponding = corresponding;
1546 gref->changed_signal = gimp_resolution_entry_signals[changed_signal];
1547
1548 if (size)
1549 {
1550 gref->value = initial_val /
1551 gimp_unit_get_factor (initial_unit) *
1552 corresponding->value *
1553 gimp_unit_get_factor (gre->unit);
1554
1555 gref->phy_size = initial_val /
1556 gimp_unit_get_factor (initial_unit);
1557 }
1558 else
1559 {
1560 gref->value = initial_val;
1561 }
1562
1563 gref->min_value = GIMP_MIN_RESOLUTION;
1564 gref->max_value = GIMP_MAX_RESOLUTION;
1565 gref->adjustment = NULL;
1566
1567 gref->stop_recursion = 0;
1568
1569 gref->size = size;
1570
1571 if (size)
1572 {
1573 gref->label = g_object_new (GTK_TYPE_LABEL,
1574 "xalign", 0.0,
1575 "yalign", 0.5,
1576 NULL);
1577 gimp_label_set_attributes (GTK_LABEL (gref->label),
1578 PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
1579 -1);
1580
1581 gimp_resolution_entry_format_label (gre, gref->label, gref->phy_size);
1582 }
1583
1584 digits = size ? 0 : MIN (gimp_unit_get_digits (initial_unit), 5) + 1;
1585
1586 gref->adjustment = (GtkAdjustment *)
1587 gtk_adjustment_new (gref->value,
1588 gref->min_value,
1589 gref->max_value,
1590 1.0, 10.0, 0.0);
1591 gref->spinbutton = gimp_spin_button_new (gref->adjustment,
1592 1.0, digits);
1593 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (gref->spinbutton), TRUE);
1594
1595 if (spinbutton_width > 0)
1596 {
1597 if (spinbutton_width < 17)
1598 gtk_entry_set_width_chars (GTK_ENTRY (gref->spinbutton),
1599 spinbutton_width);
1600 else
1601 gtk_widget_set_size_request (gref->spinbutton,
1602 spinbutton_width, -1);
1603 }
1604 }
1605
1606 /**
1607 * gimp_resolution_entry_new:
1608 * @width_label: Optional label for the width control.
1609 * @width: Width of the item, specified in terms of @size_unit.
1610 * @height_label: Optional label for the height control.
1611 * @height: Height of the item, specified in terms of @size_unit.
1612 * @size_unit: Unit used to specify the width and height.
1613 * @res_label: Optional label for the resolution entry.
1614 * @initial_res: The initial resolution.
1615 * @initial_unit: The initial unit.
1616 *
1617 * Creates a new #GimpResolutionEntry widget.
1618 *
1619 * The #GimpResolutionEntry is derived from #GtkTable and will have
1620 * an empty border of one cell width on each side plus an empty column left
1621 * of the #GimpUnitMenu to allow the caller to add labels or other widgets.
1622 *
1623 * A #GimpChainButton is displayed if independent is set to %TRUE.
1624 *
1625 * Returns: A pointer to the new #GimpResolutionEntry widget.
1626 **/
1627 GtkWidget *
gimp_resolution_entry_new(const gchar * width_label,gdouble width,const gchar * height_label,gdouble height,GimpUnit size_unit,const gchar * res_label,gdouble initial_res,GimpUnit initial_unit)1628 gimp_resolution_entry_new (const gchar *width_label,
1629 gdouble width,
1630 const gchar *height_label,
1631 gdouble height,
1632 GimpUnit size_unit,
1633 const gchar *res_label,
1634 gdouble initial_res,
1635 GimpUnit initial_unit)
1636 {
1637 GimpResolutionEntry *gre;
1638 GtkTreeModel *model;
1639
1640 gre = g_object_new (GIMP_TYPE_RESOLUTION_ENTRY, NULL);
1641
1642 gre->unit = initial_unit;
1643
1644 gtk_table_resize (GTK_TABLE (gre), 4, 4);
1645
1646 gimp_resolution_entry_field_init (gre, &gre->x,
1647 &gre->width,
1648 X_CHANGED,
1649 initial_res, initial_unit,
1650 FALSE, 0);
1651
1652 gtk_table_attach_defaults (GTK_TABLE (gre), gre->x.spinbutton,
1653 1, 2,
1654 3, 4);
1655
1656 g_signal_connect (gre->x.adjustment, "value-changed",
1657 G_CALLBACK (gimp_resolution_entry_value_callback),
1658 &gre->x);
1659
1660 gtk_widget_show (gre->x.spinbutton);
1661
1662 gre->unitmenu = gimp_unit_combo_box_new ();
1663 model = gtk_combo_box_get_model (GTK_COMBO_BOX (gre->unitmenu));
1664 gimp_unit_store_set_has_pixels (GIMP_UNIT_STORE (model), FALSE);
1665 gimp_unit_store_set_has_percent (GIMP_UNIT_STORE (model), FALSE);
1666 g_object_set (model,
1667 "short-format", _("pixels/%a"),
1668 "long-format", _("pixels/%a"),
1669 NULL);
1670 gimp_unit_combo_box_set_active (GIMP_UNIT_COMBO_BOX (gre->unitmenu),
1671 initial_unit);
1672
1673 gtk_table_attach (GTK_TABLE (gre), gre->unitmenu,
1674 3, 4, 3, 4,
1675 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1676 g_signal_connect (gre->unitmenu, "changed",
1677 G_CALLBACK (gimp_resolution_entry_unit_callback),
1678 gre);
1679 gtk_widget_show (gre->unitmenu);
1680
1681 gimp_resolution_entry_field_init (gre, &gre->width,
1682 &gre->x,
1683 WIDTH_CHANGED,
1684 width, size_unit,
1685 TRUE, 0);
1686
1687 gtk_table_attach_defaults (GTK_TABLE (gre), gre->width.spinbutton,
1688 1, 2,
1689 1, 2);
1690
1691 gtk_table_attach_defaults (GTK_TABLE (gre), gre->width.label,
1692 3, 4,
1693 1, 2);
1694
1695 g_signal_connect (gre->width.adjustment, "value-changed",
1696 G_CALLBACK (gimp_resolution_entry_value_callback),
1697 &gre->width);
1698
1699 gtk_widget_show (gre->width.spinbutton);
1700 gtk_widget_show (gre->width.label);
1701
1702 gimp_resolution_entry_field_init (gre, &gre->height, &gre->x,
1703 HEIGHT_CHANGED,
1704 height, size_unit,
1705 TRUE, 0);
1706
1707 gtk_table_attach_defaults (GTK_TABLE (gre), gre->height.spinbutton,
1708 1, 2, 2, 3);
1709
1710 gtk_table_attach_defaults (GTK_TABLE (gre), gre->height.label,
1711 3, 4, 2, 3);
1712
1713 g_signal_connect (gre->height.adjustment, "value-changed",
1714 G_CALLBACK (gimp_resolution_entry_value_callback),
1715 &gre->height);
1716
1717 gtk_widget_show (gre->height.spinbutton);
1718 gtk_widget_show (gre->height.label);
1719
1720 if (width_label)
1721 gimp_resolution_entry_attach_label (gre, width_label, 1, 0, 0.0);
1722
1723 if (height_label)
1724 gimp_resolution_entry_attach_label (gre, height_label, 2, 0, 0.0);
1725
1726 if (res_label)
1727 gimp_resolution_entry_attach_label (gre, res_label, 3, 0, 0.0);
1728
1729 return GTK_WIDGET (gre);
1730 }
1731
1732 /**
1733 * gimp_resolution_entry_attach_label:
1734 * @gre: The #GimpResolutionEntry you want to add a label to.
1735 * @text: The text of the label.
1736 * @row: The row where the label will be attached.
1737 * @column: The column where the label will be attached.
1738 * @alignment: The horizontal alignment of the label.
1739 *
1740 * Attaches a #GtkLabel to the #GimpResolutionEntry (which is a #GtkTable).
1741 *
1742 * Returns: A pointer to the new #GtkLabel widget.
1743 **/
1744 GtkWidget *
gimp_resolution_entry_attach_label(GimpResolutionEntry * gre,const gchar * text,gint row,gint column,gfloat alignment)1745 gimp_resolution_entry_attach_label (GimpResolutionEntry *gre,
1746 const gchar *text,
1747 gint row,
1748 gint column,
1749 gfloat alignment)
1750 {
1751 GtkWidget *label;
1752
1753 g_return_val_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre), NULL);
1754 g_return_val_if_fail (text != NULL, NULL);
1755
1756 label = gtk_label_new_with_mnemonic (text);
1757
1758 if (column == 0)
1759 {
1760 GList *children;
1761 GList *list;
1762
1763 children = gtk_container_get_children (GTK_CONTAINER (gre));
1764
1765 for (list = children; list; list = g_list_next (list))
1766 {
1767 GtkWidget *child = list->data;
1768 gint left_attach;
1769 gint top_attach;
1770
1771 gtk_container_child_get (GTK_CONTAINER (gre), child,
1772 "left-attach", &left_attach,
1773 "top-attach", &top_attach,
1774 NULL);
1775
1776 if (left_attach == 1 && top_attach == row)
1777 {
1778 gtk_label_set_mnemonic_widget (GTK_LABEL (label), child);
1779 break;
1780 }
1781 }
1782
1783 g_list_free (children);
1784 }
1785
1786 gtk_label_set_xalign (GTK_LABEL (label), alignment);
1787
1788 gtk_table_attach (GTK_TABLE (gre), label, column, column+1, row, row+1,
1789 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
1790 gtk_widget_show (label);
1791
1792 return label;
1793 }
1794
1795 /**
1796 * gimp_resolution_entry_get_x_in_dpi;
1797 * @gre: The #GimpResolutionEntry you want to know the resolution of.
1798 *
1799 * Returns the X resolution of the #GimpResolutionEntry in pixels per inch.
1800 **/
1801 gdouble
gimp_resolution_entry_get_x_in_dpi(GimpResolutionEntry * gre)1802 gimp_resolution_entry_get_x_in_dpi (GimpResolutionEntry *gre)
1803 {
1804 g_return_val_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre), 0);
1805
1806 /* dots_in_one_unit * units_in_one_inch -> dpi */
1807 return gre->x.value * gimp_unit_get_factor (gre->unit);
1808 }
1809
1810 /**
1811 * gimp_resolution_entry_get_y_in_dpi;
1812 * @gre: The #GimpResolutionEntry you want to know the resolution of.
1813 *
1814 * Returns the Y resolution of the #GimpResolutionEntry in pixels per inch.
1815 **/
1816 gdouble
gimp_resolution_entry_get_y_in_dpi(GimpResolutionEntry * gre)1817 gimp_resolution_entry_get_y_in_dpi (GimpResolutionEntry *gre)
1818 {
1819 g_return_val_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre), 0);
1820
1821 return gre->y.value * gimp_unit_get_factor (gre->unit);
1822 }
1823
1824
1825 static void
gimp_resolution_entry_update_value(GimpResolutionEntryField * gref,gdouble value)1826 gimp_resolution_entry_update_value (GimpResolutionEntryField *gref,
1827 gdouble value)
1828 {
1829 if (gref->stop_recursion > 0)
1830 return;
1831
1832 gref->value = value;
1833
1834 gref->stop_recursion++;
1835
1836 if (gref->size)
1837 gimp_resolution_entry_update_value (gref->corresponding,
1838 gref->value /
1839 gref->phy_size /
1840 gimp_unit_get_factor (gref->gre->unit));
1841 else
1842 {
1843 gdouble factor = gimp_unit_get_factor (gref->gre->unit);
1844
1845 gimp_resolution_entry_update_value (&gref->gre->width,
1846 gref->value *
1847 gref->gre->width.phy_size *
1848 factor);
1849
1850 gimp_resolution_entry_update_value (&gref->gre->height,
1851 gref->value *
1852 gref->gre->height.phy_size *
1853 factor);
1854 }
1855
1856 gtk_adjustment_set_value (gref->adjustment, value);
1857
1858 gref->stop_recursion--;
1859
1860 g_signal_emit (gref->gre, gref->changed_signal, 0);
1861 }
1862
1863 static void
gimp_resolution_entry_value_callback(GtkWidget * widget,gpointer data)1864 gimp_resolution_entry_value_callback (GtkWidget *widget,
1865 gpointer data)
1866 {
1867 GimpResolutionEntryField *gref = (GimpResolutionEntryField *) data;
1868 gdouble new_value;
1869
1870 new_value = gtk_adjustment_get_value (GTK_ADJUSTMENT (widget));
1871
1872 if (gref->value != new_value)
1873 gimp_resolution_entry_update_value (gref, new_value);
1874 }
1875
1876 static void
gimp_resolution_entry_update_unit(GimpResolutionEntry * gre,GimpUnit unit)1877 gimp_resolution_entry_update_unit (GimpResolutionEntry *gre,
1878 GimpUnit unit)
1879 {
1880 GimpUnit old_unit;
1881 gint digits;
1882 gdouble factor;
1883
1884 old_unit = gre->unit;
1885 gre->unit = unit;
1886
1887 digits = (gimp_unit_get_digits (GIMP_UNIT_INCH) -
1888 gimp_unit_get_digits (unit));
1889
1890 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (gre->x.spinbutton),
1891 MAX (3 + digits, 3));
1892
1893 factor = gimp_unit_get_factor (old_unit) / gimp_unit_get_factor (unit);
1894
1895 gre->x.min_value *= factor;
1896 gre->x.max_value *= factor;
1897 gre->x.value *= factor;
1898
1899 gtk_adjustment_set_value (GTK_ADJUSTMENT (gre->x.adjustment),
1900 gre->x.value);
1901
1902 gimp_resolution_entry_format_label (gre,
1903 gre->width.label, gre->width.phy_size);
1904 gimp_resolution_entry_format_label (gre,
1905 gre->height.label, gre->height.phy_size);
1906
1907 g_signal_emit (gre, gimp_resolution_entry_signals[UNIT_CHANGED], 0);
1908 }
1909
1910 static void
gimp_resolution_entry_unit_callback(GtkWidget * widget,GimpResolutionEntry * gre)1911 gimp_resolution_entry_unit_callback (GtkWidget *widget,
1912 GimpResolutionEntry *gre)
1913 {
1914 GimpUnit new_unit;
1915
1916 new_unit = gimp_unit_combo_box_get_active (GIMP_UNIT_COMBO_BOX (widget));
1917
1918 if (gre->unit != new_unit)
1919 gimp_resolution_entry_update_unit (gre, new_unit);
1920 }
1921
1922 /**
1923 * gimp_resolution_entry_update_x_in_dpi:
1924 * @gre: the #GimpResolutionEntry
1925 * @data: a pointer to a gdouble
1926 *
1927 * Convenience function to set a double to the X resolution, suitable
1928 * for use as a signal callback.
1929 */
1930 void
gimp_resolution_entry_update_x_in_dpi(GimpResolutionEntry * gre,gpointer data)1931 gimp_resolution_entry_update_x_in_dpi (GimpResolutionEntry *gre,
1932 gpointer data)
1933 {
1934 gdouble *val;
1935
1936 g_return_if_fail (gre != NULL);
1937 g_return_if_fail (data != NULL);
1938 g_return_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre));
1939
1940 val = (gdouble *) data;
1941
1942 *val = gimp_resolution_entry_get_x_in_dpi (gre);
1943 }
1944
1945 /**
1946 * gimp_resolution_entry_update_y_in_dpi:
1947 * @gre: the #GimpResolutionEntry
1948 * @data: a pointer to a gdouble
1949 *
1950 * Convenience function to set a double to the Y resolution, suitable
1951 * for use as a signal callback.
1952 */
1953 void
gimp_resolution_entry_update_y_in_dpi(GimpResolutionEntry * gre,gpointer data)1954 gimp_resolution_entry_update_y_in_dpi (GimpResolutionEntry *gre,
1955 gpointer data)
1956 {
1957 gdouble *val;
1958
1959 g_return_if_fail (gre != NULL);
1960 g_return_if_fail (data != NULL);
1961 g_return_if_fail (GIMP_IS_RESOLUTION_ENTRY (gre));
1962
1963 val = (gdouble *) data;
1964
1965 *val = gimp_resolution_entry_get_y_in_dpi (gre);
1966 }
1967
1968 static void
gimp_resolution_entry_format_label(GimpResolutionEntry * gre,GtkWidget * label,gdouble size)1969 gimp_resolution_entry_format_label (GimpResolutionEntry *gre,
1970 GtkWidget *label,
1971 gdouble size)
1972 {
1973 gchar *format = g_strdup_printf ("%%.%df %%s",
1974 gimp_unit_get_digits (gre->unit));
1975 gchar *text = g_strdup_printf (format,
1976 size * gimp_unit_get_factor (gre->unit),
1977 gimp_unit_get_plural (gre->unit));
1978 g_free (format);
1979
1980 gtk_label_set_text (GTK_LABEL (label), text);
1981 g_free (text);
1982 }
1983