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