1 #include <stdio.h> /* fopen, fprintf, fread, printf */
2 #include <stdlib.h> /* malloc */
6 #include <gdk-pixbuf/gdk-pixbuf.h>
9 /* Convenient typedefs for libsvgtiny */
10 typedef struct svgtiny_diagram diagram_t
;
14 * Render an svgtiny path using cairo.
16 void render_path(cairo_t
*cr
, struct svgtiny_shape
*path
) {
20 for (j
= 0; j
!= path
->path_length
; ) {
21 switch ((int) path
->path
[j
]) {
22 case svgtiny_PATH_MOVE
:
28 case svgtiny_PATH_CLOSE
:
32 case svgtiny_PATH_LINE
:
38 case svgtiny_PATH_BEZIER
:
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
);
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
);
71 * @brief Parse an SVG file into a diagram_t structure.
74 * A pointer to an open file stream.
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.
80 diagram_t
* svgtiny_diagram_from_file(FILE* fp
, int width
, int height
) {
88 /* Find the size of the file stream */
89 fseek(fp
, 0L, SEEK_END
);
90 bytecount
= ftell(fp
);
93 buffer
= malloc(bytecount
);
95 fprintf(stderr
, "Unable to allocate %zd bytes\n", bytecount
);
99 bytesread
= fread(buffer
, 1, bytecount
, fp
);
100 if (bytesread
!= bytecount
) {
101 fprintf(stderr
, "Read only %zd of %zd bytes from stream\n",
107 diagram
= svgtiny_create();
109 fprintf(stderr
, "svgtiny_create() failed\n");
113 code
= svgtiny_parse(diagram
, buffer
, bytecount
, "", width
, height
);
116 if (code
!= svgtiny_OK
) {
117 fprintf(stderr
, "svgtiny_parse failed: ");
119 case svgtiny_OUT_OF_MEMORY
:
120 fprintf(stderr
, "svgtiny_OUT_OF_MEMORY");
122 case svgtiny_LIBDOM_ERROR
:
123 fprintf(stderr
, "svgtiny_LIBDOM_ERROR");
125 case svgtiny_NOT_SVG
:
126 fprintf(stderr
, "svgtiny_NOT_SVG");
128 case svgtiny_SVG_ERROR
:
129 fprintf(stderr
, "svgtiny_SVG_ERROR: line %i: %s",
131 diagram
->error_message
);
134 fprintf(stderr
, "unknown svgtiny_code %i", code
);
137 fprintf(stderr
, "\n");
145 * @brief Create a cairo context from a libsvgtiny diagram.
148 * A pointer to a valid libsvgtiny diagram.
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.
154 cairo_t
* cairo_context_from_diagram(diagram_t
* diagram
) {
156 cairo_surface_t
* surface
;
160 surface
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
,
164 crs
= cairo_surface_status(surface
);
165 if (crs
!= CAIRO_STATUS_SUCCESS
) {
167 "cairo_image_surface_create failed: %s\n",
168 cairo_status_to_string(crs
));
169 cairo_surface_destroy(surface
);
173 cr
= cairo_create(surface
);
174 crs
= cairo_status(cr
);
176 /* Immediately destroy the surface which is now accessible as
178 cairo_surface_destroy(surface
);
180 if (crs
!= CAIRO_STATUS_SUCCESS
) {
182 "cairo_create failed: %s\n",
183 cairo_status_to_string(crs
));
188 cairo_set_source_rgb(cr
, 1, 1, 1);
191 /* Loop through the shapes in the diagram... */
192 for (i
= 0; i
!= diagram
->shape_count
; i
++) {
194 /* If this shape is a path, just render it. */
195 if (diagram
->shape
[i
].path
) {
196 render_path(cr
, &diagram
->shape
[i
]);
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
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
210 diagram
->shape
[i
].text_x
,
211 diagram
->shape
[i
].text_y
);
214 cairo_show_text(cr
, diagram
->shape
[i
].text
);
219 /* Check the status again just for good measure? */
220 crs
= cairo_status(cr
);
221 if (crs
!= CAIRO_STATUS_SUCCESS
) {
224 cairo_status_to_string(crs
));
232 int main(int argc
, char** argv
) {
235 int pngwidth
= 1024, pngheight
= 1024;
243 /* Parse arguments, and maybe print usage */
245 printf("Usage: %s INPUT OUTPUT\n", argv
[0]);
246 printf("Convert an SVG file (INPUT) to a PNG file (OUTPUT)\n");
253 fp
= fopen(svgpath
, "rb");
259 diagram
= svgtiny_diagram_from_file(fp
, pngwidth
, pngheight
);
264 cr
= cairo_context_from_diagram(diagram
);
266 svgtiny_free(diagram
);
270 pb
= gdk_pixbuf_get_from_surface(cairo_get_target(cr
),
278 gdk_pixbuf_save(pb
, pngpath
, "png", NULL
, NULL
);