From 159e79d3a373946dbe149460714ead2e0ccdbdc8 Mon Sep 17 00:00:00 2001 From: Michael Orlitzky Date: Thu, 3 Aug 2023 16:56:06 -0400 Subject: [PATCH] example.c: get SVG -> PNG conversion via libsvgtiny/cairo working. --- example.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 211 insertions(+), 2 deletions(-) diff --git a/example.c b/example.c index d6ec4a7..1f54a00 100644 --- a/example.c +++ b/example.c @@ -1,6 +1,215 @@ +#include #include +#include +#include + +/** + * Render an svgtiny path using cairo. + */ +void render_path(cairo_t *cr, float scale, struct svgtiny_shape *path) { + unsigned int j; + + cairo_new_path(cr); + for (j = 0; j != path->path_length; ) { + switch ((int) path->path[j]) { + case svgtiny_PATH_MOVE: + cairo_move_to(cr, + scale * path->path[j + 1], + scale * path->path[j + 2]); + j += 3; + break; + case svgtiny_PATH_CLOSE: + cairo_close_path(cr); + j += 1; + break; + case svgtiny_PATH_LINE: + cairo_line_to(cr, + scale * path->path[j + 1], + scale * path->path[j + 2]); + j += 3; + break; + case svgtiny_PATH_BEZIER: + cairo_curve_to(cr, + scale * path->path[j + 1], + scale * path->path[j + 2], + scale * path->path[j + 3], + scale * path->path[j + 4], + scale * path->path[j + 5], + scale * path->path[j + 6]); + j += 7; + break; + default: + printf("error "); + j += 1; + } + } + if (path->fill != svgtiny_TRANSPARENT) { + cairo_set_source_rgb(cr, + svgtiny_RED(path->fill) / 255.0, + svgtiny_GREEN(path->fill) / 255.0, + svgtiny_BLUE(path->fill) / 255.0); + cairo_fill_preserve(cr); + } + if (path->stroke != svgtiny_TRANSPARENT) { + cairo_set_source_rgb(cr, + svgtiny_RED(path->stroke) / 255.0, + svgtiny_GREEN(path->stroke) / 255.0, + svgtiny_BLUE(path->stroke) / 255.0); + cairo_set_line_width(cr, scale * path->stroke_width); + cairo_stroke_preserve(cr); + } +} + int main(int argc, char** argv) { - printf("Hello, world!\n"); - return 0; + int exit_code = 0; + + /* Initial viewport width and height */ + int width = 1024, height = 1024; + float scale = 1.0; + char* svgpath = "Ghostscript_Tiger.svg"; + char* pngpath = "Ghostscript_Tiger.png"; + size_t svgsize = 68630; + + FILE *fd; + char *buffer; + size_t bytesread; + + svgtiny_code code; + struct svgtiny_diagram *diagram; + cairo_surface_t *surface; + cairo_t *cr = 0; + cairo_status_t cr_status; + + unsigned int i; + + /* load file into memory buffer */ + fd = fopen(svgpath, "rb"); + if (!fd) { + perror(svgpath); + return 1; + } + + buffer = malloc(svgsize); + if (!buffer) { + fprintf(stderr, "Unable to allocate %zd bytes\n", svgsize); + return 1; + } + + bytesread = fread(buffer, 1, svgsize, fd); + if (bytesread != svgsize) { + perror(svgpath); + return 1; + } + fclose(fd); + + + /* create svgtiny object */ + diagram = svgtiny_create(); + if (!diagram) { + fprintf(stderr, "svgtiny_create() failed\n"); + return 1; + } + + code = svgtiny_parse(diagram, buffer, svgsize, svgpath, width, height); + free(buffer); + + if (code != svgtiny_OK) { + fprintf(stderr, "svgtiny_parse failed: "); + switch (code) { + case svgtiny_OUT_OF_MEMORY: + fprintf(stderr, "svgtiny_OUT_OF_MEMORY"); + break; + case svgtiny_LIBDOM_ERROR: + fprintf(stderr, "svgtiny_LIBDOM_ERROR"); + break; + case svgtiny_NOT_SVG: + fprintf(stderr, "svgtiny_NOT_SVG"); + break; + case svgtiny_SVG_ERROR: + fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s", + diagram->error_line, + diagram->error_message); + break; + default: + fprintf(stderr, "unknown svgtiny_code %i", code); + break; + } + fprintf(stderr, "\n"); + return 1; + } + + + surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); + if (!surface) { + fprintf(stderr, "cairo_image_surface_create failed\n"); + exit_code = 1; + goto cleanup; + } + + cr = cairo_create(surface); + cr_status = cairo_status(cr); + if (cr_status != CAIRO_STATUS_SUCCESS) { + fprintf(stderr, + "cairo_create failed: %s\n", + cairo_status_to_string(cr_status)); + exit_code = 1; + goto cleanup; + } + + cairo_set_source_rgb(cr, 1, 1, 1); + cairo_paint(cr); + + /* Loop through the shapes in the diagram... */ + for (i = 0; i != diagram->shape_count; i++) { + + /* If this shape is a path, just render it. */ + if (diagram->shape[i].path) { + render_path(cr, scale, &diagram->shape[i]); + } + + /* If this shape is text... */ + if (diagram->shape[i].text) { + /* Figure out what color to use from the R/G/B components of the + shape's stroke. */ + cairo_set_source_rgb(cr, + svgtiny_RED(diagram->shape[i].stroke) / 255.0, + svgtiny_GREEN(diagram->shape[i].stroke) / 255.0, + svgtiny_BLUE(diagram->shape[i].stroke) / 255.0); + /* Then move to the actual position of the text within the + shape... */ + cairo_move_to(cr, + scale * diagram->shape[i].text_x, + scale * diagram->shape[i].text_y); + + /* and draw it. */ + cairo_show_text(cr, diagram->shape[i].text); + } + } + + /* Check the status again. */ + cr_status = cairo_status(cr); + if (cr_status != CAIRO_STATUS_SUCCESS) { + fprintf(stderr, "cairo error: %s\n", + cairo_status_to_string(cr_status)); + exit_code = 1; + goto cleanup; + } + + cr_status = cairo_surface_write_to_png(surface, pngpath); + if (cr_status != CAIRO_STATUS_SUCCESS) { + fprintf(stderr, "cairo error: %s\n", + cairo_status_to_string(cr_status)); + exit_code = 1; + goto cleanup; + } + +cleanup: + if (cr) { + cairo_destroy(cr); + } + cairo_surface_destroy(surface); + svgtiny_free(diagram); + + return exit_code; } -- 2.43.2