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