~ubuntu-branches/ubuntu/saucy/gimp/saucy

« back to all changes in this revision

Viewing changes to plug-ins/common/file-pdf.c

  • Committer: Package Import Robot
  • Author(s): Micah Gersten
  • Date: 2012-05-20 19:21:01 UTC
  • mfrom: (1.1.26) (0.4.16 sid)
  • Revision ID: package-import@ubuntu.com-20120520192101-bs7zetx8ffoq2nfv
Tags: 2.8.0-2ubuntu1
* Merge from Debian unstable (LP: #908472). Remaining Changes:
  - debian/patches/02_help-message.patch,
    debian/patches/03_gimp.desktop.in.in.patch:
    + Update some strings for Ubuntu
  - debian/control:
    + Update description
  - debian/rules:
    + Set gettext domain and update translation templates
* Drop the following patches that were applied upstream:
  - debian/patches/ghost-cursor.patch: fix Wacom tablet cursor events
  - debian/patches/embed-page-setup-dialog.patch

Show diffs side-by-side

added added

removed removed

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