diff options
Diffstat (limited to 'src/whale-svg.c')
-rw-r--r-- | src/whale-svg.c | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/src/whale-svg.c b/src/whale-svg.c new file mode 100644 index 0000000..2c4b655 --- /dev/null +++ b/src/whale-svg.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2018 Vito Caputo - <vcaputo@pengaru.com> + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 3 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> /* this is needed by cairo headers of all things */ +#include <cairo.h> +#ifdef HAVE_SVG_CAIRO +#include <svg-cairo.h> +#else +#include <librsvg/rsvg.h> +#endif + +#include "macros.h" + +typedef struct whale_svg_t { +#ifdef HAVE_SVG_CAIRO + svg_cairo_t *cairo_svg; + unsigned width, height; +#else + RsvgHandle *rsvg; + RsvgDimensionData dimensions; +#endif +} whale_svg_t; + + +whale_svg_t * whale_svg_new_file(const char *file) +{ + whale_svg_t *svg; + + svg = calloc(1, sizeof(whale_svg_t)); + fatal_if(!svg, "Unable to create svg"); + +#ifdef HAVE_SVG_CAIRO + fatal_if(svg_cairo_create(&svg->cairo_svg) != 0, + "Unable to create svg-cairo context"); + fatal_if(svg_cairo_parse(svg->cairo_svg, file) != 0, + "Unable to parse \"%s\"", file); + svg_cairo_get_size(svg->cairo_svg, &svg->width, &svg->height); +#else + //rsvg_init(); + svg->rsvg = rsvg_handle_new_from_file(file, NULL); + fatal_if(!svg->rsvg, + "Unable to create rsvg handle from file \"%s\"", file); + rsvg_handle_get_dimensions(svg->rsvg, &svg->dimensions); +#endif + + return svg; +} + + +whale_svg_t * whale_svg_new_buffer(const char *buf, size_t count) +{ + whale_svg_t *svg; + + svg = calloc(1, sizeof(whale_svg_t)); + fatal_if(!svg, "Unable to create svg"); + +#ifdef HAVE_SVG_CAIRO + fatal_if(svg_cairo_create(&svg->cairo_svg) != 0, + "Unable to create svg-cairo context"); + fatal_if(svg_cairo_parse_buffer(svg->cairo_svg, buf, count) != 0, + "Unable to parse svg buffer"); + svg_cairo_get_size(svg->cairo_svg, &svg->width, &svg->height); +#else + //rsvg_init(); + svg->rsvg = rsvg_handle_new_from_data(buf, count, NULL); + fatal_if(!svg->rsvg, + "Unable to create rsvg handle from buffer"); + rsvg_handle_get_dimensions(svg->rsvg, &svg->dimensions); +#endif + + return svg; +} + + + +SDL_Surface * whale_svg_render(whale_svg_t *svg, int width, int height) +{ + cairo_surface_t *cairo_surface; + SDL_Surface *sdl_surface; + cairo_t *cairo; + double xscale, yscale, scale, tx, ty, svg_width, svg_height; + +#ifdef HAVE_SVG_CAIRO + svg_width = svg->width; + svg_height = svg->height; +#else + svg_width = svg->dimensions.width; + svg_height = svg->dimensions.height; +#endif + + /* cached size is different so redo the costly SVG render */ + sdl_surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_ARGB8888); + fatal_if(!sdl_surface, "Unable to create sdl surface"); + + cairo_surface = cairo_image_surface_create_for_data(sdl_surface->pixels, + CAIRO_FORMAT_ARGB32, + width, + height, + sdl_surface->pitch); + fatal_if(!cairo_surface, "Unable to create cairo surface"); + +#if 0 + /* useful for debugging */ + SDL_FillRect(sdl_surface, NULL, 0xffff0000); +#endif + + cairo = cairo_create(cairo_surface); + fatal_if(!cairo, "Unable to create cairo target"); + + /* XXX: this scaling attempts to preserve the svg's aspect ratio, + * while filling the destination surface + */ + xscale = (double)width / svg_width; + yscale = (double)height / svg_height; + scale = xscale < yscale ? xscale : yscale; + + /* if we have a mismatch between the desired width/height aspect ratio, + * and the svg's aspect ratio, we need to translate to center the rendering + * in the resulting surface + */ + tx = scale * svg_width; + ty = scale * svg_height; + + if ((int)((double)tx + 0.5) < width) + tx = ((double)width - tx + 0.5) / 2.0; + else + tx = 0; + + if ((int)((double)ty + 0.5) < height) + ty = ((double)height - ty + 0.5) / 2.0; + else + ty = 0; + + cairo_translate(cairo, tx, ty); + cairo_scale(cairo, scale, scale); + +#ifdef HAVE_SVG_CAIRO + svg_cairo_render(svg->cairo_svg, cairo); +#else + rsvg_handle_render_cairo(svg->rsvg, cairo); +#endif + cairo_surface_flush(cairo_surface); + cairo_surface_destroy(cairo_surface); + cairo_destroy(cairo); + + return sdl_surface; +} + + +void whale_svg_free(whale_svg_t *svg) +{ +#ifdef HAVE_SVG_CAIRO + svg_cairo_destroy(svg->cairo_svg); +#else + rsvg_handle_free(svg->rsvg); +#endif + free(svg); +} |