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 */
9 #include <gdk-pixbuf/gdk-pixbuf.h>
12 /* Convenient typedefs for libsvgtiny */
13 typedef struct svgtiny_diagram diagram_t
;
17 * Render an svgtiny path using cairo.
19 void render_path(cairo_t
*cr
, struct svgtiny_shape
*path
) {
23 for (j
= 0; j
!= path
->path_length
; ) {
24 switch ((int) path
->path
[j
]) {
25 case svgtiny_PATH_MOVE
:
31 case svgtiny_PATH_CLOSE
:
35 case svgtiny_PATH_LINE
:
41 case svgtiny_PATH_BEZIER
:
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
);
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
);
74 * @brief Parse an SVG file into a diagram_t structure.
77 * The path to the SVG file.
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.
83 diagram_t
* svgtiny_diagram_from_path(char* path
, int width
, int height
) {
93 /* load file into memory buffer */
94 fd
= open(path
, O_RDONLY
);
100 if (fstat(fd
, &sb
)) {
104 bytecount
= sb
.st_size
;
106 buffer
= malloc(bytecount
);
108 fprintf(stderr
, "Unable to allocate %zd bytes\n", bytecount
);
112 bytesread
= read(fd
, buffer
, bytecount
);
113 if (bytesread
!= bytecount
) {
120 /* create svgtiny object */
121 diagram
= svgtiny_create();
123 fprintf(stderr
, "svgtiny_create() failed\n");
127 code
= svgtiny_parse(diagram
, buffer
, bytecount
, path
, width
, height
);
130 if (code
!= svgtiny_OK
) {
131 fprintf(stderr
, "svgtiny_parse failed: ");
133 case svgtiny_OUT_OF_MEMORY
:
134 fprintf(stderr
, "svgtiny_OUT_OF_MEMORY");
136 case svgtiny_LIBDOM_ERROR
:
137 fprintf(stderr
, "svgtiny_LIBDOM_ERROR");
139 case svgtiny_NOT_SVG
:
140 fprintf(stderr
, "svgtiny_NOT_SVG");
142 case svgtiny_SVG_ERROR
:
143 fprintf(stderr
, "svgtiny_SVG_ERROR: line %i: %s",
145 diagram
->error_message
);
148 fprintf(stderr
, "unknown svgtiny_code %i", code
);
151 fprintf(stderr
, "\n");
159 * @brief Create a cairo context from a libsvgtiny diagram.
162 * A pointer to a valid libsvgtiny diagram.
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.
168 cairo_t
* cairo_context_from_diagram(diagram_t
* diagram
) {
170 cairo_surface_t
* surface
;
174 surface
= cairo_image_surface_create(CAIRO_FORMAT_RGB24
,
178 crs
= cairo_surface_status(surface
);
179 if (crs
!= CAIRO_STATUS_SUCCESS
) {
181 "cairo_image_surface_create failed: %s\n",
182 cairo_status_to_string(crs
));
183 cairo_surface_destroy(surface
);
187 cr
= cairo_create(surface
);
188 crs
= cairo_status(cr
);
190 /* Immediately destroy the surface which is now accessible as
192 cairo_surface_destroy(surface
);
194 if (crs
!= CAIRO_STATUS_SUCCESS
) {
196 "cairo_create failed: %s\n",
197 cairo_status_to_string(crs
));
202 cairo_set_source_rgb(cr
, 1, 1, 1);
205 /* Loop through the shapes in the diagram... */
206 for (i
= 0; i
!= diagram
->shape_count
; i
++) {
208 /* If this shape is a path, just render it. */
209 if (diagram
->shape
[i
].path
) {
210 render_path(cr
, &diagram
->shape
[i
]);
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
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
224 diagram
->shape
[i
].text_x
,
225 diagram
->shape
[i
].text_y
);
228 cairo_show_text(cr
, diagram
->shape
[i
].text
);
233 /* Check the status again just for good measure? */
234 crs
= cairo_status(cr
);
235 if (crs
!= CAIRO_STATUS_SUCCESS
) {
238 cairo_status_to_string(crs
));
246 int main(int argc
, char** argv
) {
249 int pngwidth
= 1024, pngheight
= 1024;
256 /* Parse arguments, and maybe print usage */
258 printf("Usage: %s INPUT OUTPUT\n", argv
[0]);
259 printf("Convert an SVG file (INPUT) to a PNG file (OUTPUT)\n");
266 diagram
= svgtiny_diagram_from_path(svgpath
, pngwidth
, pngheight
);
271 cr
= cairo_context_from_diagram(diagram
);
273 svgtiny_free(diagram
);
277 pb
= gdk_pixbuf_get_from_surface(cairo_get_target(cr
),
285 gdk_pixbuf_save(pb
, pngpath
, "png", NULL
, NULL
);