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