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