]> gitweb.michael.orlitzky.com - libsvgtiny-pixbuf.git/blob - example.c
3dab2bace2093f70bc9d1a0625418ae45c810a8d
[libsvgtiny-pixbuf.git] / example.c
1 #include <fcntl.h> /* open */
2 #include <stdio.h> /* printf, fprintf */
3 #include <stdlib.h> /* malloc */
4 #include <sys/stat.h> /* fstat */
5 #include <unistd.h> /* read */
6
7 #include <cairo.h>
8 #include <gdk/gdk.h>
9 #include <gdk-pixbuf/gdk-pixbuf.h>
10 #include <svgtiny.h>
11
12 /* Convenient typedefs for libsvgtiny */
13 typedef struct svgtiny_diagram diagram_t;
14
15
16 /**
17 * Render an svgtiny path using cairo.
18 */
19 void render_path(cairo_t *cr, struct svgtiny_shape *path) {
20 unsigned int j;
21
22 cairo_new_path(cr);
23 for (j = 0; j != path->path_length; ) {
24 switch ((int) path->path[j]) {
25 case svgtiny_PATH_MOVE:
26 cairo_move_to(cr,
27 path->path[j + 1],
28 path->path[j + 2]);
29 j += 3;
30 break;
31 case svgtiny_PATH_CLOSE:
32 cairo_close_path(cr);
33 j += 1;
34 break;
35 case svgtiny_PATH_LINE:
36 cairo_line_to(cr,
37 path->path[j + 1],
38 path->path[j + 2]);
39 j += 3;
40 break;
41 case svgtiny_PATH_BEZIER:
42 cairo_curve_to(cr,
43 path->path[j + 1],
44 path->path[j + 2],
45 path->path[j + 3],
46 path->path[j + 4],
47 path->path[j + 5],
48 path->path[j + 6]);
49 j += 7;
50 break;
51 default:
52 printf("error ");
53 j += 1;
54 }
55 }
56 if (path->fill != svgtiny_TRANSPARENT) {
57 cairo_set_source_rgb(cr,
58 svgtiny_RED(path->fill) / 255.0,
59 svgtiny_GREEN(path->fill) / 255.0,
60 svgtiny_BLUE(path->fill) / 255.0);
61 cairo_fill_preserve(cr);
62 }
63 if (path->stroke != svgtiny_TRANSPARENT) {
64 cairo_set_source_rgb(cr,
65 svgtiny_RED(path->stroke) / 255.0,
66 svgtiny_GREEN(path->stroke) / 255.0,
67 svgtiny_BLUE(path->stroke) / 255.0);
68 cairo_set_line_width(cr, path->stroke_width);
69 cairo_stroke_preserve(cr);
70 }
71 }
72
73 /*
74 * @brief Parse an SVG file into a diagram_t structure.
75 *
76 * @param path
77 * The path to the SVG file.
78 *
79 * @return If successful, a pointer to a @c diagram_t structure is
80 * returned; if not, @c NULL is returned. You are expected to @c
81 * svgtiny_free the result if it is valid.
82 */
83 diagram_t* svgtiny_diagram_from_path(char* path, int width, int height) {
84 diagram_t *diagram;
85
86 int fd;
87 size_t bytecount;
88 char *buffer;
89 size_t bytesread;
90 struct stat sb;
91 svgtiny_code code;
92
93 /* load file into memory buffer */
94 fd = open(path, O_RDONLY);
95 if (fd == -1) {
96 perror(path);
97 return NULL;
98 }
99
100 if (fstat(fd, &sb)) {
101 perror(path);
102 return NULL;
103 }
104 bytecount = sb.st_size;
105
106 buffer = malloc(bytecount);
107 if (!buffer) {
108 fprintf(stderr, "Unable to allocate %zd bytes\n", bytecount);
109 return NULL;
110 }
111
112 bytesread = read(fd, buffer, bytecount);
113 if (bytesread != bytecount) {
114 perror(path);
115 return NULL;
116 }
117 close(fd);
118
119
120 /* create svgtiny object */
121 diagram = svgtiny_create();
122 if (!diagram) {
123 fprintf(stderr, "svgtiny_create() failed\n");
124 return NULL;
125 }
126
127 code = svgtiny_parse(diagram, buffer, bytecount, path, width, height);
128 free(buffer);
129
130 if (code != svgtiny_OK) {
131 fprintf(stderr, "svgtiny_parse failed: ");
132 switch (code) {
133 case svgtiny_OUT_OF_MEMORY:
134 fprintf(stderr, "svgtiny_OUT_OF_MEMORY");
135 break;
136 case svgtiny_LIBDOM_ERROR:
137 fprintf(stderr, "svgtiny_LIBDOM_ERROR");
138 break;
139 case svgtiny_NOT_SVG:
140 fprintf(stderr, "svgtiny_NOT_SVG");
141 break;
142 case svgtiny_SVG_ERROR:
143 fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s",
144 diagram->error_line,
145 diagram->error_message);
146 break;
147 default:
148 fprintf(stderr, "unknown svgtiny_code %i", code);
149 break;
150 }
151 fprintf(stderr, "\n");
152 return NULL;
153 }
154
155 return diagram;
156 }
157
158 /*
159 * @brief Create a cairo context from a libsvgtiny diagram.
160 *
161 * @param diagram
162 * A pointer to a valid libsvgtiny diagram.
163 *
164 * @return If successful, a pointer to a @c cairo_t context structure
165 * is returned; if not, @c NULL is returned. You are expected to @c
166 * cairo_destroy the result if it is valid.
167 */
168 cairo_t* cairo_context_from_diagram(diagram_t* diagram) {
169 cairo_t* cr;
170 cairo_surface_t* surface;
171 cairo_status_t crs;
172 unsigned int i;
173
174 surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
175 diagram->width,
176 diagram->height);
177
178 crs = cairo_surface_status(surface);
179 if (crs != CAIRO_STATUS_SUCCESS) {
180 fprintf(stderr,
181 "cairo_image_surface_create failed: %s\n",
182 cairo_status_to_string(crs));
183 cairo_surface_destroy(surface);
184 return NULL;
185 }
186
187 cr = cairo_create(surface);
188 crs = cairo_status(cr);
189
190 /* Immediately destroy the surface which is now accessible as
191 cr->target */
192 cairo_surface_destroy(surface);
193
194 if (crs != CAIRO_STATUS_SUCCESS) {
195 fprintf(stderr,
196 "cairo_create failed: %s\n",
197 cairo_status_to_string(crs));
198 cairo_destroy(cr);
199 return NULL;
200 }
201
202 cairo_set_source_rgb(cr, 1, 1, 1);
203 cairo_paint(cr);
204
205 /* Loop through the shapes in the diagram... */
206 for (i = 0; i != diagram->shape_count; i++) {
207
208 /* If this shape is a path, just render it. */
209 if (diagram->shape[i].path) {
210 render_path(cr, &diagram->shape[i]);
211 }
212
213 /* If this shape is text... */
214 if (diagram->shape[i].text) {
215 /* Figure out what color to use from the R/G/B components of the
216 shape's stroke. */
217 cairo_set_source_rgb(cr,
218 svgtiny_RED(diagram->shape[i].stroke) / 255.0,
219 svgtiny_GREEN(diagram->shape[i].stroke) / 255.0,
220 svgtiny_BLUE(diagram->shape[i].stroke) / 255.0);
221 /* Then move to the actual position of the text within the
222 shape... */
223 cairo_move_to(cr,
224 diagram->shape[i].text_x,
225 diagram->shape[i].text_y);
226
227 /* and draw it. */
228 cairo_show_text(cr, diagram->shape[i].text);
229 }
230 }
231
232
233 /* Check the status again just for good measure? */
234 crs = cairo_status(cr);
235 if (crs != CAIRO_STATUS_SUCCESS) {
236 fprintf(stderr,
237 "cairo error: %s\n",
238 cairo_status_to_string(crs));
239 cairo_destroy(cr);
240 return NULL;
241 }
242
243 return cr;
244 }
245
246 int main(int argc, char** argv) {
247 char* svgpath;
248 char* pngpath;
249 int pngwidth = 1024, pngheight = 1024;
250
251 diagram_t* diagram;
252 cairo_t *cr = 0;
253
254 GdkPixbuf* pb;
255
256 /* Parse arguments, and maybe print usage */
257 if (argc < 3) {
258 printf("Usage: %s INPUT OUTPUT\n", argv[0]);
259 printf("Convert an SVG file (INPUT) to a PNG file (OUTPUT)\n");
260 return 2;
261 }
262
263 svgpath = argv[1];
264 pngpath = argv[2];
265
266 diagram = svgtiny_diagram_from_path(svgpath, pngwidth, pngheight);
267 if (!diagram) {
268 return 1;
269 }
270
271 cr = cairo_context_from_diagram(diagram);
272 if (!cr) {
273 svgtiny_free(diagram);
274 return 1;
275 }
276
277 pb = gdk_pixbuf_get_from_surface(cairo_get_target(cr),
278 0,
279 0,
280 pngwidth,
281 pngheight);
282
283
284 if (pb) {
285 gdk_pixbuf_save(pb, pngpath, "png", NULL, NULL);
286 g_object_unref(pb);
287 }
288
289 return 0;
290 }