1 /* svg2png - Render an SVG image to a PNG image (using cairo)
2 *
3 * Copyright � 2002 USC/Information Sciences Institute
4 *
5 * Permission to use, copy, modify, distribute, and sell this software
6 * and its documentation for any purpose is hereby granted without
7 * fee, provided that the above copyright notice appear in all copies
8 * and that both that copyright notice and this permission notice
9 * appear in supporting documentation, and that the name of
10 * Information Sciences Institute not be used in advertising or
11 * publicity pertaining to distribution of the software without
12 * specific, written prior permission. Information Sciences Institute
13 * makes no representations about the suitability of this software for
14 * any purpose. It is provided "as is" without express or implied
15 * warranty.
16 *
17 * INFORMATION SCIENCES INSTITUTE DISCLAIMS ALL WARRANTIES WITH REGARD
18 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL INFORMATION SCIENCES
20 * INSTITUTE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
21 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
22 * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
23 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
24 * PERFORMANCE OF THIS SOFTWARE.
25 *
26 * Author: Carl Worth <cworth@isi.edu>
27 */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <png.h>
32 #include <errno.h>
33
34 #include <cairo.h>
35
36 #include <svg-cairo.h>
37
38 #include "args.h"
39
40 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
41
42 static svg_cairo_status_t
43 render_to_png (FILE *svg_file, FILE *png_file, double scale, int width, int height);
44
45 int
main(int argc,char ** argv)46 main (int argc, char **argv)
47 {
48 args_t args;
49 FILE *svg_file, *png_file;
50 svg_cairo_status_t status;
51 args_parse (&args, argc, argv);
52
53 if (strcmp (args.svg_filename, "-") == 0) {
54 svg_file = stdin;
55 } else {
56 svg_file = fopen (args.svg_filename, "r");
57 if (svg_file == NULL) {
58 fprintf (stderr, "%s: failed to open %s: %s\n",
59 argv[0], args.svg_filename, strerror(errno));
60 return 1;
61 }
62 }
63
64 if (strcmp (args.png_filename, "-") == 0) {
65 png_file = stdout;
66 } else {
67 png_file = fopen (args.png_filename, "w");
68 if (png_file == NULL) {
69 fprintf (stderr, "%s: failed to open %s: %s\n",
70 argv[0], args.png_filename, strerror (errno));
71 return 1;
72 }
73 }
74
75 status = render_to_png (svg_file, png_file, args.scale, args.width, args.height);
76 if (status) {
77 fprintf (stderr, "%s: failed to render %s\n", argv[0], args.svg_filename);
78 return 1;
79 }
80
81 if (svg_file != stdin)
82 fclose (svg_file);
83 if (png_file != stdout)
84 fclose (png_file);
85
86 return 0;
87 }
88
89 static cairo_status_t
write_callback(void * closure,const unsigned char * data,unsigned int length)90 write_callback (void *closure, const unsigned char *data, unsigned int length)
91 {
92 size_t written;
93 FILE *file = closure;
94
95 written = fwrite (data, 1, length, file);
96
97 if (written == length)
98 return CAIRO_STATUS_SUCCESS;
99 else
100 return CAIRO_STATUS_WRITE_ERROR;
101 }
102
103 static svg_cairo_status_t
write_surface_to_png_file(cairo_surface_t * surface,FILE * file)104 write_surface_to_png_file (cairo_surface_t *surface, FILE *file)
105 {
106 cairo_status_t status;
107
108 status = cairo_surface_write_to_png_stream (surface, write_callback, file);
109
110 if (status)
111 return SVG_CAIRO_STATUS_IO_ERROR;
112 else
113 return SVG_CAIRO_STATUS_SUCCESS;
114 }
115
116 static svg_cairo_status_t
render_to_png(FILE * svg_file,FILE * png_file,double scale,int width,int height)117 render_to_png (FILE *svg_file, FILE *png_file, double scale, int width, int height)
118 {
119 unsigned int svg_width, svg_height;
120
121 svg_cairo_status_t status;
122 cairo_t *cr;
123 svg_cairo_t *svgc;
124 cairo_surface_t *surface;
125 double dx = 0, dy = 0;
126
127 status = svg_cairo_create (&svgc);
128 if (status) {
129 fprintf (stderr, "Failed to create svg_cairo_t. Exiting.\n");
130 exit(1);
131 }
132
133 status = svg_cairo_parse_file (svgc, svg_file);
134 if (status)
135 return status;
136
137 svg_cairo_get_size (svgc, &svg_width, &svg_height);
138
139 if (width < 0 && height < 0) {
140 width = (svg_width * scale + 0.5);
141 height = (svg_height * scale + 0.5);
142 } else if (width < 0) {
143 scale = (double) height / (double) svg_height;
144 width = (svg_width * scale + 0.5);
145 } else if (height < 0) {
146 scale = (double) width / (double) svg_width;
147 height = (svg_height * scale + 0.5);
148 } else {
149 scale = MIN ((double) width / (double) svg_width, (double) height / (double) svg_height);
150 /* Center the resulting image */
151 dx = (width - (int) (svg_width * scale + 0.5)) / 2;
152 dy = (height - (int) (svg_height * scale + 0.5)) / 2;
153 }
154
155 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
156 cr = cairo_create (surface);
157
158 cairo_save (cr);
159 cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
160 cairo_paint (cr);
161 cairo_restore (cr);
162
163 cairo_translate (cr, dx, dy);
164 cairo_scale (cr, scale, scale);
165
166 /* XXX: This probably doesn't need to be here (eventually) */
167 cairo_set_source_rgb (cr, 1, 1, 1);
168
169 status = svg_cairo_render (svgc, cr);
170
171 status = write_surface_to_png_file (surface, png_file);
172 cairo_surface_destroy (surface);
173 cairo_destroy (cr);
174
175 if (status)
176 return status;
177
178 svg_cairo_destroy (svgc);
179
180 return status;
181 }
182