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 */
10 /* Convenient typedefs for libsvgtiny */
11 typedef struct svgtiny_diagram diagram_t
;
15 * Render an svgtiny path using cairo.
17 void render_path(cairo_t
*cr
, struct svgtiny_shape
*path
) {
21 for (j
= 0; j
!= path
->path_length
; ) {
22 switch ((int) path
->path
[j
]) {
23 case svgtiny_PATH_MOVE
:
29 case svgtiny_PATH_CLOSE
:
33 case svgtiny_PATH_LINE
:
39 case svgtiny_PATH_BEZIER
:
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
);
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
);
72 * @brief Parse an SVG file into a diagram_t structure.
75 * The path to the SVG file.
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.
81 diagram_t
* svgtiny_diagram_from_path(char* path
, int width
, int height
) {
91 /* load file into memory buffer */
92 fd
= open(path
, O_RDONLY
);
102 bytecount
= sb
.st_size
;
104 buffer
= malloc(bytecount
);
106 fprintf(stderr
, "Unable to allocate %zd bytes\n", bytecount
);
110 bytesread
= read(fd
, buffer
, bytecount
);
111 if (bytesread
!= bytecount
) {
118 /* create svgtiny object */
119 diagram
= svgtiny_create();
121 fprintf(stderr
, "svgtiny_create() failed\n");
125 code
= svgtiny_parse(diagram
, buffer
, bytecount
, path
, width
, height
);
128 if (code
!= svgtiny_OK
) {
129 fprintf(stderr
, "svgtiny_parse failed: ");
131 case svgtiny_OUT_OF_MEMORY
:
132 fprintf(stderr
, "svgtiny_OUT_OF_MEMORY");
134 case svgtiny_LIBDOM_ERROR
:
135 fprintf(stderr
, "svgtiny_LIBDOM_ERROR");
137 case svgtiny_NOT_SVG
:
138 fprintf(stderr
, "svgtiny_NOT_SVG");
140 case svgtiny_SVG_ERROR
:
141 fprintf(stderr
, "svgtiny_SVG_ERROR: line %i: %s",
143 diagram
->error_message
);
146 fprintf(stderr
, "unknown svgtiny_code %i", code
);
149 fprintf(stderr
, "\n");
158 * @brief Create a cairo context from a libsvgtiny diagram.
161 * A pointer to a valid libsvgtiny diagram.
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.
167 cairo_t
* cairo_context_from_diagram(diagram_t
* diagram
) {
169 cairo_surface_t
* surface
;
173 surface
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
,
177 crs
= cairo_surface_status(surface
);
178 if (crs
!= CAIRO_STATUS_SUCCESS
) {
180 "cairo_image_surface_create failed: %s\n",
181 cairo_status_to_string(crs
));
182 cairo_surface_destroy(surface
);
186 cr
= cairo_create(surface
);
187 crs
= cairo_status(cr
);
189 /* Immediately destroy the surface which is now accessible as
191 cairo_surface_destroy(surface
);
193 if (crs
!= CAIRO_STATUS_SUCCESS
) {
195 "cairo_create failed: %s\n",
196 cairo_status_to_string(crs
));
201 cairo_set_source_rgb(cr
, 1, 1, 1);
204 /* Loop through the shapes in the diagram... */
205 for (i
= 0; i
!= diagram
->shape_count
; i
++) {
207 /* If this shape is a path, just render it. */
208 if (diagram
->shape
[i
].path
) {
209 render_path(cr
, &diagram
->shape
[i
]);
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
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
223 diagram
->shape
[i
].text_x
,
224 diagram
->shape
[i
].text_y
);
227 cairo_show_text(cr
, diagram
->shape
[i
].text
);
232 /* Check the status again just for good measure? */
233 crs
= cairo_status(cr
);
234 if (crs
!= CAIRO_STATUS_SUCCESS
) {
237 cairo_status_to_string(crs
));
246 int main(int argc
, char** argv
) {
251 int pngwidth
= 1024, pngheight
= 1024;
254 cairo_surface_t
*surface
;
258 /* Parse arguments, and maybe print usage */
260 printf("Usage: %s INPUT OUTPUT\n", argv
[0]);
261 printf("Convert an SVG file (INPUT) to a PNG file (OUTPUT)\n");
268 diagram
= svgtiny_diagram_from_path(svgpath
, pngwidth
, pngheight
);
273 cr
= cairo_context_from_diagram(diagram
);
275 svgtiny_free(diagram
);
279 crs
= cairo_surface_write_to_png(cairo_get_target(cr
), pngpath
);
280 if (crs
!= CAIRO_STATUS_SUCCESS
) {
282 "cairo_surface_write_to_png failed: %s\n",
283 cairo_status_to_string(crs
));
284 svgtiny_free(diagram
);