1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 /* SVG loader plug-in
19 * (C) Copyright 2003 Dom Lachowicz <cinamod@hotmail.com>
20 *
21 * Largely rewritten in September 2003 by Sven Neumann <sven@gimp.org>
22 */
23
24 #include "config.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <librsvg/rsvg.h>
30
31 #include "libgimp/gimp.h"
32 #include "libgimp/gimpui.h"
33
34 #include "libgimp/stdplugins-intl.h"
35
36
37 #define LOAD_PROC "file-svg-load"
38 #define LOAD_THUMB_PROC "file-svg-load-thumb"
39 #define PLUG_IN_BINARY "file-svg"
40 #define PLUG_IN_ROLE "gimp-file-svg"
41 #define SVG_VERSION "2.5.0"
42 #define SVG_DEFAULT_RESOLUTION 90.0
43 #define SVG_DEFAULT_SIZE 500
44 #define SVG_PREVIEW_SIZE 128
45
46
47 typedef struct
48 {
49 gdouble resolution;
50 gint width;
51 gint height;
52 gboolean import;
53 gboolean merge;
54 } SvgLoadVals;
55
56 static SvgLoadVals load_vals =
57 {
58 SVG_DEFAULT_RESOLUTION,
59 0,
60 0,
61 FALSE,
62 FALSE
63 };
64
65
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 (const gchar *filename,
74 GError **error);
75 static GdkPixbuf * load_rsvg_pixbuf (const gchar *filename,
76 SvgLoadVals *vals,
77 GError **error);
78 static gboolean load_rsvg_size (const gchar *filename,
79 SvgLoadVals *vals,
80 GError **error);
81 static GimpPDBStatusType load_dialog (const gchar *filename,
82 GError **error);
83
84
85 const GimpPlugInInfo PLUG_IN_INFO =
86 {
87 NULL,
88 NULL,
89 query,
90 run,
91 };
92
MAIN()93 MAIN ()
94
95
96 static void
97 query (void)
98 {
99 static const GimpParamDef load_args[] =
100 {
101 { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
102 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
103 { GIMP_PDB_STRING, "raw-filename", "The name of the file to load" },
104 { GIMP_PDB_FLOAT, "resolution",
105 "Resolution to use for rendering the SVG (defaults to 90 dpi)" },
106 { GIMP_PDB_INT32, "width",
107 "Width (in pixels) to load the SVG in. "
108 "(0 for original width, a negative width to specify a maximum width)" },
109 { GIMP_PDB_INT32, "height",
110 "Height (in pixels) to load the SVG in. "
111 "(0 for original height, a negative width to specify a maximum height)"},
112 { GIMP_PDB_INT32, "paths",
113 "Whether to not import paths (0), import paths individually (1) "
114 "or merge all imported paths (2)" }
115 };
116 static const GimpParamDef load_return_vals[] =
117 {
118 { GIMP_PDB_IMAGE, "image", "Output image" }
119 };
120
121 static const GimpParamDef thumb_args[] =
122 {
123 { GIMP_PDB_STRING, "filename", "The name of the file to load" },
124 { GIMP_PDB_INT32, "thumb-size", "Preferred thumbnail size" }
125 };
126 static const GimpParamDef thumb_return_vals[] =
127 {
128 { GIMP_PDB_IMAGE, "image", "Thumbnail image" },
129 { GIMP_PDB_INT32, "image-width", "Width of full-sized image" },
130 { GIMP_PDB_INT32, "image-height", "Height of full-sized image" }
131 };
132
133 gimp_install_procedure (LOAD_PROC,
134 "Loads files in the SVG file format",
135 "Renders SVG files to raster graphics using librsvg.",
136 "Dom Lachowicz, Sven Neumann",
137 "Dom Lachowicz <cinamod@hotmail.com>",
138 SVG_VERSION,
139 N_("SVG image"),
140 NULL,
141 GIMP_PLUGIN,
142 G_N_ELEMENTS (load_args),
143 G_N_ELEMENTS (load_return_vals),
144 load_args, load_return_vals);
145
146 gimp_register_file_handler_mime (LOAD_PROC, "image/svg+xml");
147 gimp_register_magic_load_handler (LOAD_PROC,
148 "svg", "",
149 "0,string,<?xml,0,string,<svg");
150
151 gimp_install_procedure (LOAD_THUMB_PROC,
152 "Generates a thumbnail of an SVG image",
153 "Renders a thumbnail of an SVG file using librsvg.",
154 "Dom Lachowicz, Sven Neumann",
155 "Dom Lachowicz <cinamod@hotmail.com>",
156 SVG_VERSION,
157 NULL,
158 NULL,
159 GIMP_PLUGIN,
160 G_N_ELEMENTS (thumb_args),
161 G_N_ELEMENTS (thumb_return_vals),
162 thumb_args, thumb_return_vals);
163
164 gimp_register_thumbnail_loader (LOAD_PROC, LOAD_THUMB_PROC);
165 }
166
167 static void
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)168 run (const gchar *name,
169 gint nparams,
170 const GimpParam *param,
171 gint *nreturn_vals,
172 GimpParam **return_vals)
173 {
174 static GimpParam values[4];
175 GimpRunMode run_mode;
176 GimpPDBStatusType status = GIMP_PDB_SUCCESS;
177 GError *error = NULL;
178
179 INIT_I18N ();
180
181 run_mode = param[0].data.d_int32;
182
183 *nreturn_vals = 1;
184 *return_vals = values;
185
186 values[0].type = GIMP_PDB_STATUS;
187 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
188
189 if (strcmp (name, LOAD_PROC) == 0)
190 {
191 gimp_get_data (LOAD_PROC, &load_vals);
192
193 switch (run_mode)
194 {
195 case GIMP_RUN_NONINTERACTIVE:
196 if (nparams > 3) load_vals.resolution = param[3].data.d_float;
197 if (nparams > 4) load_vals.width = param[4].data.d_int32;
198 if (nparams > 5) load_vals.height = param[5].data.d_int32;
199 if (nparams > 6)
200 {
201 load_vals.import = param[6].data.d_int32 != FALSE;
202 load_vals.merge = param[6].data.d_int32 > TRUE;
203 }
204 break;
205
206 case GIMP_RUN_INTERACTIVE:
207 status = load_dialog (param[1].data.d_string, &error);
208 break;
209
210 case GIMP_RUN_WITH_LAST_VALS:
211 break;
212 }
213
214 /* Don't clamp this; insane values are probably not meant to be
215 * used as resolution anyway.
216 */
217 if (load_vals.resolution < GIMP_MIN_RESOLUTION ||
218 load_vals.resolution > GIMP_MAX_RESOLUTION)
219 {
220 load_vals.resolution = SVG_DEFAULT_RESOLUTION;
221 }
222
223 if (status == GIMP_PDB_SUCCESS)
224 {
225 const gchar *filename = param[1].data.d_string;
226 gint32 image_ID = load_image (filename, &error);
227
228 if (image_ID != -1)
229 {
230 if (load_vals.import)
231 {
232 gint32 *vectors;
233 gint num_vectors;
234
235 gimp_vectors_import_from_file (image_ID, filename,
236 load_vals.merge, TRUE,
237 &num_vectors, &vectors);
238 if (num_vectors > 0)
239 g_free (vectors);
240 }
241
242 *nreturn_vals = 2;
243
244 values[1].type = GIMP_PDB_IMAGE;
245 values[1].data.d_image = image_ID;
246 }
247 else
248 {
249 status = GIMP_PDB_EXECUTION_ERROR;
250 }
251
252 gimp_set_data (LOAD_PROC, &load_vals, sizeof (load_vals));
253 }
254 }
255 else if (strcmp (name, LOAD_THUMB_PROC) == 0)
256 {
257 if (nparams < 2)
258 {
259 status = GIMP_PDB_CALLING_ERROR;
260 }
261 else
262 {
263 const gchar *filename = param[0].data.d_string;
264 gint width = 0;
265 gint height = 0;
266 gint32 image_ID;
267
268 if (load_rsvg_size (filename, &load_vals, NULL))
269 {
270 width = load_vals.width;
271 height = load_vals.height;
272 }
273
274 load_vals.resolution = SVG_DEFAULT_RESOLUTION;
275 load_vals.width = - param[1].data.d_int32;
276 load_vals.height = - param[1].data.d_int32;
277
278 image_ID = load_image (filename, &error);
279
280 if (image_ID != -1)
281 {
282 *nreturn_vals = 4;
283 values[1].type = GIMP_PDB_IMAGE;
284 values[1].data.d_image = image_ID;
285 values[2].type = GIMP_PDB_INT32;
286 values[2].data.d_int32 = width;
287 values[3].type = GIMP_PDB_INT32;
288 values[3].data.d_int32 = height;
289 }
290 else
291 {
292 status = GIMP_PDB_EXECUTION_ERROR;
293 }
294 }
295 }
296 else
297 {
298 status = GIMP_PDB_CALLING_ERROR;
299 }
300
301 if (status != GIMP_PDB_SUCCESS && error)
302 {
303 *nreturn_vals = 2;
304 values[1].type = GIMP_PDB_STRING;
305 values[1].data.d_string = error->message;
306 }
307
308 values[0].data.d_status = status;
309 }
310
311 static gint32
load_image(const gchar * filename,GError ** load_error)312 load_image (const gchar *filename,
313 GError **load_error)
314 {
315 gint32 image;
316 gint32 layer;
317 GdkPixbuf *pixbuf;
318 gint width;
319 gint height;
320 GError *error = NULL;
321
322 pixbuf = load_rsvg_pixbuf (filename, &load_vals, &error);
323
324 if (! pixbuf)
325 {
326 /* Do not rely on librsvg setting GError on failure! */
327 g_set_error (load_error,
328 error ? error->domain : 0, error ? error->code : 0,
329 _("Could not open '%s' for reading: %s"),
330 gimp_filename_to_utf8 (filename),
331 error ? error->message : _("Unknown reason"));
332 g_clear_error (&error);
333
334 return -1;
335 }
336
337 gimp_progress_init (_("Rendering SVG"));
338
339 width = gdk_pixbuf_get_width (pixbuf);
340 height = gdk_pixbuf_get_height (pixbuf);
341
342 image = gimp_image_new (width, height, GIMP_RGB);
343 gimp_image_undo_disable (image);
344
345 gimp_image_set_filename (image, filename);
346 gimp_image_set_resolution (image,
347 load_vals.resolution, load_vals.resolution);
348
349 layer = gimp_layer_new_from_pixbuf (image, _("Rendered SVG"), pixbuf,
350 100,
351 gimp_image_get_default_new_layer_mode (image),
352 0.0, 1.0);
353 gimp_image_insert_layer (image, layer, -1, 0);
354
355 gimp_image_undo_enable (image);
356
357 return image;
358 }
359
360 /* This is the callback used from load_rsvg_pixbuf(). */
361 static void
load_set_size_callback(gint * width,gint * height,gpointer data)362 load_set_size_callback (gint *width,
363 gint *height,
364 gpointer data)
365 {
366 SvgLoadVals *vals = data;
367
368 if (*width < 1 || *height < 1)
369 {
370 *width = SVG_DEFAULT_SIZE;
371 *height = SVG_DEFAULT_SIZE;
372 }
373
374 if (!vals->width || !vals->height)
375 return;
376
377 /* either both arguments negative or none */
378 if ((vals->width * vals->height) < 0)
379 return;
380
381 if (vals->width > 0)
382 {
383 *width = vals->width;
384 *height = vals->height;
385 }
386 else
387 {
388 gdouble w = *width;
389 gdouble h = *height;
390 gdouble aspect = (gdouble) vals->width / (gdouble) vals->height;
391
392 if (aspect > (w / h))
393 {
394 *height = abs (vals->height);
395 *width = (gdouble) abs (vals->width) * (w / h) + 0.5;
396 }
397 else
398 {
399 *width = abs (vals->width);
400 *height = (gdouble) abs (vals->height) / (w / h) + 0.5;
401 }
402
403 vals->width = *width;
404 vals->height = *height;
405 }
406 }
407
408 /* This function renders a pixbuf from an SVG file according to vals. */
409 static GdkPixbuf *
load_rsvg_pixbuf(const gchar * filename,SvgLoadVals * vals,GError ** error)410 load_rsvg_pixbuf (const gchar *filename,
411 SvgLoadVals *vals,
412 GError **error)
413 {
414 GdkPixbuf *pixbuf = NULL;
415 RsvgHandle *handle;
416 GFile *file;
417
418 file = g_file_new_for_path (filename);
419
420 handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, error);
421
422 g_object_unref (file);
423
424 if (!handle)
425 {
426 return NULL;
427 }
428
429 rsvg_handle_set_dpi (handle, vals->resolution);
430 rsvg_handle_set_size_callback (handle, load_set_size_callback, vals, NULL);
431
432 pixbuf = rsvg_handle_get_pixbuf (handle);
433
434 g_object_unref (handle);
435
436 return pixbuf;
437 }
438
439 static GtkWidget *size_label = NULL;
440
441 /* This function retrieves the pixel size from an SVG file. */
442 static gboolean
load_rsvg_size(const gchar * filename,SvgLoadVals * vals,GError ** error)443 load_rsvg_size (const gchar *filename,
444 SvgLoadVals *vals,
445 GError **error)
446 {
447 RsvgHandle *handle;
448 GFile *file;
449 RsvgDimensionData dim;
450 gboolean has_size;
451
452 file = g_file_new_for_path (filename);
453
454 handle = rsvg_handle_new_from_gfile_sync (file, RSVG_HANDLE_FLAGS_NONE, NULL, error);
455
456 g_object_unref (file);
457
458 if (!handle)
459 {
460 return FALSE;
461 }
462
463 rsvg_handle_set_dpi (handle, vals->resolution);
464
465 rsvg_handle_get_dimensions (handle, &dim);
466
467 if (dim.width > 0 && dim.height > 0)
468 {
469 vals->width = dim.width;
470 vals->height = dim.height;
471 has_size = TRUE;
472 }
473 else
474 {
475 vals->width = SVG_DEFAULT_SIZE;
476 vals->height = SVG_DEFAULT_SIZE;
477 has_size = FALSE;
478 }
479
480 if (size_label)
481 {
482 if (has_size)
483 {
484 gchar *text = g_strdup_printf (_("%d × %d"),
485 vals->width, vals->height);
486 gtk_label_set_text (GTK_LABEL (size_label), text);
487 g_free (text);
488 }
489 else
490 {
491 gtk_label_set_text (GTK_LABEL (size_label),
492 _("SVG file does not\nspecify a size!"));
493 }
494 }
495
496 g_object_unref (handle);
497
498 if (vals->width < 1) vals->width = 1;
499 if (vals->height < 1) vals->height = 1;
500
501 return TRUE;
502 }
503
504
505 /* User interface */
506
507 static GimpSizeEntry *size = NULL;
508 static GtkAdjustment *xadj = NULL;
509 static GtkAdjustment *yadj = NULL;
510 static GtkWidget *constrain = NULL;
511 static gdouble ratio_x = 1.0;
512 static gdouble ratio_y = 1.0;
513 static gint svg_width = 0;
514 static gint svg_height = 0;
515
516 static void load_dialog_set_ratio (gdouble x,
517 gdouble y);
518
519
520 static void
load_dialog_size_callback(GtkWidget * widget,gpointer data)521 load_dialog_size_callback (GtkWidget *widget,
522 gpointer data)
523 {
524 if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (constrain)))
525 {
526 gdouble x = gimp_size_entry_get_refval (size, 0) / (gdouble) svg_width;
527 gdouble y = gimp_size_entry_get_refval (size, 1) / (gdouble) svg_height;
528
529 if (x != ratio_x)
530 {
531 load_dialog_set_ratio (x, x);
532 }
533 else if (y != ratio_y)
534 {
535 load_dialog_set_ratio (y, y);
536 }
537 }
538 }
539
540 static void
load_dialog_ratio_callback(GtkAdjustment * adj,gpointer data)541 load_dialog_ratio_callback (GtkAdjustment *adj,
542 gpointer data)
543 {
544 gdouble x = gtk_adjustment_get_value (xadj);
545 gdouble y = gtk_adjustment_get_value (yadj);
546
547 if (gimp_chain_button_get_active (GIMP_CHAIN_BUTTON (constrain)))
548 {
549 if (x != ratio_x)
550 y = x;
551 else
552 x = y;
553 }
554
555 load_dialog_set_ratio (x, y);
556 }
557
558 static void
load_dialog_resolution_callback(GimpSizeEntry * res,const gchar * filename)559 load_dialog_resolution_callback (GimpSizeEntry *res,
560 const gchar *filename)
561 {
562 SvgLoadVals vals = { 0.0, 0, 0 };
563
564 load_vals.resolution = vals.resolution = gimp_size_entry_get_refval (res, 0);
565
566 if (!load_rsvg_size (filename, &vals, NULL))
567 return;
568
569 g_signal_handlers_block_by_func (size, load_dialog_size_callback, NULL);
570
571 gimp_size_entry_set_resolution (size, 0, load_vals.resolution, FALSE);
572 gimp_size_entry_set_resolution (size, 1, load_vals.resolution, FALSE);
573
574 g_signal_handlers_unblock_by_func (size, load_dialog_size_callback, NULL);
575
576 if (gimp_size_entry_get_unit (size) != GIMP_UNIT_PIXEL)
577 {
578 ratio_x = gimp_size_entry_get_refval (size, 0) / vals.width;
579 ratio_y = gimp_size_entry_get_refval (size, 1) / vals.height;
580 }
581
582 svg_width = vals.width;
583 svg_height = vals.height;
584
585 load_dialog_set_ratio (ratio_x, ratio_y);
586 }
587
588 static void
load_dialog_set_ratio(gdouble x,gdouble y)589 load_dialog_set_ratio (gdouble x,
590 gdouble y)
591 {
592 ratio_x = x;
593 ratio_y = y;
594
595 g_signal_handlers_block_by_func (size, load_dialog_size_callback, NULL);
596
597 gimp_size_entry_set_refval (size, 0, svg_width * x);
598 gimp_size_entry_set_refval (size, 1, svg_height * y);
599
600 g_signal_handlers_unblock_by_func (size, load_dialog_size_callback, NULL);
601
602 g_signal_handlers_block_by_func (xadj, load_dialog_ratio_callback, NULL);
603 g_signal_handlers_block_by_func (yadj, load_dialog_ratio_callback, NULL);
604
605 gtk_adjustment_set_value (xadj, x);
606 gtk_adjustment_set_value (yadj, y);
607
608 g_signal_handlers_unblock_by_func (xadj, load_dialog_ratio_callback, NULL);
609 g_signal_handlers_unblock_by_func (yadj, load_dialog_ratio_callback, NULL);
610 }
611
612 static GimpPDBStatusType
load_dialog(const gchar * filename,GError ** load_error)613 load_dialog (const gchar *filename,
614 GError **load_error)
615 {
616 GtkWidget *dialog;
617 GtkWidget *frame;
618 GtkWidget *hbox;
619 GtkWidget *vbox;
620 GtkWidget *image;
621 GdkPixbuf *preview;
622 GtkWidget *table;
623 GtkWidget *table2;
624 GtkWidget *abox;
625 GtkWidget *res;
626 GtkWidget *label;
627 GtkWidget *spinbutton;
628 GtkWidget *toggle;
629 GtkWidget *toggle2;
630 GtkAdjustment *adj;
631 gboolean run;
632 GError *error = NULL;
633 SvgLoadVals vals =
634 {
635 SVG_DEFAULT_RESOLUTION,
636 - SVG_PREVIEW_SIZE,
637 - SVG_PREVIEW_SIZE
638 };
639
640 preview = load_rsvg_pixbuf (filename, &vals, &error);
641
642 if (! preview)
643 {
644 /* Do not rely on librsvg setting GError on failure! */
645 g_set_error (load_error,
646 error ? error->domain : 0, error ? error->code : 0,
647 _("Could not open '%s' for reading: %s"),
648 gimp_filename_to_utf8 (filename),
649 error ? error->message : _("Unknown reason"));
650 g_clear_error (&error);
651
652 return GIMP_PDB_EXECUTION_ERROR;
653 }
654
655 gimp_ui_init (PLUG_IN_BINARY, FALSE);
656
657 /* Scalable Vector Graphics is SVG, should perhaps not be translated */
658 dialog = gimp_dialog_new (_("Render Scalable Vector Graphics"),
659 PLUG_IN_ROLE,
660 NULL, 0,
661 gimp_standard_help_func, LOAD_PROC,
662
663 _("_Cancel"), GTK_RESPONSE_CANCEL,
664 _("_OK"), GTK_RESPONSE_OK,
665
666 NULL);
667
668 gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
669 GTK_RESPONSE_OK,
670 GTK_RESPONSE_CANCEL,
671 -1);
672
673 gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
674
675 gimp_window_set_transient (GTK_WINDOW (dialog));
676
677 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
678 gtk_container_set_border_width (GTK_CONTAINER (hbox), 12);
679 gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
680 hbox, TRUE, TRUE, 0);
681 gtk_widget_show (hbox);
682
683 /* The SVG preview */
684 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
685 gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
686 gtk_widget_show (vbox);
687
688 abox = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
689 gtk_box_pack_start (GTK_BOX (vbox), abox, FALSE, FALSE, 0);
690 gtk_widget_show (abox);
691
692 frame = gtk_frame_new (NULL);
693 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
694 gtk_container_add (GTK_CONTAINER (abox), frame);
695 gtk_widget_show (frame);
696
697 image = gtk_image_new_from_pixbuf (preview);
698 gtk_container_add (GTK_CONTAINER (frame), image);
699 gtk_widget_show (image);
700
701 size_label = gtk_label_new (NULL);
702 gtk_label_set_justify (GTK_LABEL (size_label), GTK_JUSTIFY_CENTER);
703 gtk_box_pack_start (GTK_BOX (vbox), size_label, TRUE, TRUE, 4);
704 gtk_widget_show (size_label);
705
706 /* query the initial size after the size label is created */
707 vals.resolution = load_vals.resolution;
708
709 load_rsvg_size (filename, &vals, NULL);
710
711 svg_width = vals.width;
712 svg_height = vals.height;
713
714 table = gtk_table_new (7, 3, FALSE);
715 gtk_table_set_row_spacings (GTK_TABLE (table), 6);
716 gtk_table_set_col_spacings (GTK_TABLE (table), 6);
717 gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
718 gtk_table_set_row_spacing (GTK_TABLE (table), 2, 2);
719 gtk_box_pack_start (GTK_BOX (hbox), table, TRUE, TRUE, 0);
720 gtk_widget_show (table);
721
722 /* Width and Height */
723 label = gtk_label_new (_("Width:"));
724 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
725 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
726 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
727 gtk_widget_show (label);
728
729 label = gtk_label_new (_("Height:"));
730 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
731 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2,
732 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
733 gtk_widget_show (label);
734
735 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
736 gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 0, 1,
737 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
738 gtk_widget_show (hbox);
739
740 adj = (GtkAdjustment *) gtk_adjustment_new (1, 1, 1, 1, 10, 0);
741 spinbutton = gimp_spin_button_new (adj, 1.0, 2);
742 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
743 gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
744 gtk_box_pack_start (GTK_BOX (hbox), spinbutton, FALSE, FALSE, 0);
745 gtk_widget_show (spinbutton);
746
747 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
748 gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 1, 2,
749 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
750 gtk_widget_show (hbox);
751
752 size = GIMP_SIZE_ENTRY (gimp_size_entry_new (1, GIMP_UNIT_PIXEL, "%a",
753 TRUE, FALSE, FALSE, 10,
754 GIMP_SIZE_ENTRY_UPDATE_SIZE));
755 gtk_table_set_col_spacing (GTK_TABLE (size), 1, 6);
756
757 gimp_size_entry_add_field (size, GTK_SPIN_BUTTON (spinbutton), NULL);
758
759 gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (size), FALSE, FALSE, 0);
760 gtk_widget_show (GTK_WIDGET (size));
761
762 gimp_size_entry_set_refval_boundaries (size, 0,
763 GIMP_MIN_IMAGE_SIZE,
764 GIMP_MAX_IMAGE_SIZE);
765 gimp_size_entry_set_refval_boundaries (size, 1,
766 GIMP_MIN_IMAGE_SIZE,
767 GIMP_MAX_IMAGE_SIZE);
768
769 gimp_size_entry_set_refval (size, 0, svg_width);
770 gimp_size_entry_set_refval (size, 1, svg_height);
771
772 gimp_size_entry_set_resolution (size, 0, load_vals.resolution, FALSE);
773 gimp_size_entry_set_resolution (size, 1, load_vals.resolution, FALSE);
774
775 g_signal_connect (size, "value-changed",
776 G_CALLBACK (load_dialog_size_callback),
777 NULL);
778
779 /* Scale ratio */
780 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
781 gtk_table_attach (GTK_TABLE (table), hbox, 1, 2, 2, 4,
782 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
783 gtk_widget_show (hbox);
784
785 table2 = gtk_table_new (2, 2, FALSE);
786 gtk_table_set_col_spacing (GTK_TABLE (table2), 0, 2);
787 gtk_table_set_row_spacing (GTK_TABLE (table2), 0, 4);
788 gtk_box_pack_start (GTK_BOX (hbox), table2, FALSE, FALSE, 0);
789
790 xadj = (GtkAdjustment *)
791 gtk_adjustment_new (ratio_x,
792 (gdouble) GIMP_MIN_IMAGE_SIZE / (gdouble) svg_width,
793 (gdouble) GIMP_MAX_IMAGE_SIZE / (gdouble) svg_width,
794 0.01, 0.1, 0);
795 spinbutton = gimp_spin_button_new (xadj, 0.01, 4);
796 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
797 gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
798 gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 0, 1);
799 gtk_widget_show (spinbutton);
800
801 g_signal_connect (xadj, "value-changed",
802 G_CALLBACK (load_dialog_ratio_callback),
803 NULL);
804
805 label = gtk_label_new_with_mnemonic (_("_X ratio:"));
806 gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
807 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
808 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
809 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
810 gtk_widget_show (label);
811
812 yadj = (GtkAdjustment *)
813 gtk_adjustment_new (ratio_y,
814 (gdouble) GIMP_MIN_IMAGE_SIZE / (gdouble) svg_height,
815 (gdouble) GIMP_MAX_IMAGE_SIZE / (gdouble) svg_height,
816 0.01, 0.1, 0);
817 spinbutton = gimp_spin_button_new (yadj, 0.01, 4);
818 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
819 gtk_entry_set_width_chars (GTK_ENTRY (spinbutton), 10);
820 gtk_table_attach_defaults (GTK_TABLE (table2), spinbutton, 0, 1, 1, 2);
821 gtk_widget_show (spinbutton);
822
823 g_signal_connect (yadj, "value-changed",
824 G_CALLBACK (load_dialog_ratio_callback),
825 NULL);
826
827 label = gtk_label_new_with_mnemonic (_("_Y ratio:"));
828 gtk_label_set_mnemonic_widget (GTK_LABEL (label), spinbutton);
829 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
830 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
831 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
832 gtk_widget_show (label);
833
834 /* the constrain ratio chainbutton */
835 constrain = gimp_chain_button_new (GIMP_CHAIN_RIGHT);
836 gimp_chain_button_set_active (GIMP_CHAIN_BUTTON (constrain), TRUE);
837 gtk_table_attach_defaults (GTK_TABLE (table2), constrain, 1, 2, 0, 2);
838 gtk_widget_show (constrain);
839
840 gimp_help_set_help_data (GIMP_CHAIN_BUTTON (constrain)->button,
841 _("Constrain aspect ratio"), NULL);
842
843 gtk_widget_show (table2);
844
845 /* Resolution */
846 label = gtk_label_new (_("Resolution:"));
847 gtk_label_set_xalign (GTK_LABEL (label), 0.0);
848 gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
849 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
850 gtk_widget_show (label);
851
852 res = gimp_size_entry_new (1, GIMP_UNIT_INCH, _("pixels/%a"),
853 FALSE, FALSE, FALSE, 10,
854 GIMP_SIZE_ENTRY_UPDATE_RESOLUTION);
855 gtk_table_set_col_spacing (GTK_TABLE (res), 1, 6);
856
857 gtk_table_attach (GTK_TABLE (table), res, 1, 2, 4, 5,
858 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
859 gtk_widget_show (res);
860
861 /* don't let the resolution become too small, librsvg tends to
862 crash with very small resolutions */
863 gimp_size_entry_set_refval_boundaries (GIMP_SIZE_ENTRY (res), 0,
864 5.0, GIMP_MAX_RESOLUTION);
865 gimp_size_entry_set_refval (GIMP_SIZE_ENTRY (res), 0, load_vals.resolution);
866
867 g_signal_connect (res, "value-changed",
868 G_CALLBACK (load_dialog_resolution_callback),
869 (gpointer) filename);
870
871 /* Path Import */
872 toggle = gtk_check_button_new_with_mnemonic (_("Import _paths"));
873 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), load_vals.import);
874 gtk_table_attach (GTK_TABLE (table), toggle, 0, 2, 5, 6,
875 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
876 gtk_widget_show (toggle);
877
878 gimp_help_set_help_data (toggle,
879 _("Import path elements of the SVG so they "
880 "can be used with the GIMP path tool"),
881 NULL);
882
883 g_signal_connect (toggle, "toggled",
884 G_CALLBACK (gimp_toggle_button_update),
885 &load_vals.import);
886
887 toggle2 = gtk_check_button_new_with_mnemonic (_("Merge imported paths"));
888 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle2), load_vals.merge);
889 gtk_table_attach (GTK_TABLE (table), toggle2, 0, 2, 6, 7,
890 GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
891 gtk_widget_show (toggle2);
892
893 g_signal_connect (toggle2, "toggled",
894 G_CALLBACK (gimp_toggle_button_update),
895 &load_vals.merge);
896
897 g_object_bind_property (toggle, "active",
898 toggle2, "sensitive",
899 G_BINDING_SYNC_CREATE);
900
901 gtk_widget_show (dialog);
902
903 run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
904
905 if (run)
906 {
907 load_vals.width = ROUND (gimp_size_entry_get_refval (size, 0));
908 load_vals.height = ROUND (gimp_size_entry_get_refval (size, 1));
909 }
910
911 gtk_widget_destroy (dialog);
912
913 return run ? GIMP_PDB_SUCCESS : GIMP_PDB_CANCEL;
914 }
915