Add svg loader

This commit is contained in:
Kim Woelders 2022-01-06 14:56:38 +01:00
parent 04b8c35e17
commit a542fb6724
6 changed files with 229 additions and 0 deletions

View File

@ -196,6 +196,7 @@ loader_check_gif() {
EC_LOADER_CHECK(GIF, auto, , loader_check_gif)
EC_LOADER_CHECK(JPEG, auto, libjpeg)
EC_LOADER_CHECK(PNG, auto, libpng)
EC_LOADER_CHECK(SVG, auto, librsvg-2.0)
EC_LOADER_CHECK(TIFF, auto, libtiff-4)
EC_LOADER_CHECK(WEBP, auto, libwebpdemux)
@ -274,6 +275,7 @@ echo " Regular image loaders"
echo " GIF.....................: $gif_ok"
echo " JPEG....................: $jpeg_ok"
echo " PNG.....................: $png_ok"
echo " SVG.....................: $svg_ok"
echo " TIFF....................: $tiff_ok"
echo " WEBP....................: $webp_ok"
echo " Decompressors"

View File

@ -35,6 +35,9 @@ static const char *const ext_lbm[] = { "iff", "ilbm", "lbm", NULL };
#ifdef BUILD_PNG_LOADER
static const char *const ext_png[] = { "png", NULL };
#endif
#ifdef BUILD_SVG_LOADER
static const char *const ext_svg[] = { "svg", NULL };
#endif
static const char *const ext_pnm[] =
{ "pnm", "ppm", "pgm", "pbm", "pam", NULL };
static const char *const ext_tga[] = { "tga", NULL };
@ -77,6 +80,9 @@ static const KnownLoader loaders_known[] = {
{"png", ext_png},
#endif
{"pnm", ext_pnm},
#ifdef BUILD_SVG_LOADER
{"svg", ext_svg},
#endif
{"tga", ext_tga},
#ifdef BUILD_TIFF_LOADER
{"tiff", ext_tiff},

View File

@ -23,6 +23,9 @@ endif
if BUILD_PNG_LOADER
pkg_LTLIBRARIES += png.la
endif
if BUILD_SVG_LOADER
pkg_LTLIBRARIES += svg.la
endif
if BUILD_TIFF_LOADER
pkg_LTLIBRARIES += tiff.la
endif
@ -93,6 +96,12 @@ pnm_la_LDFLAGS = -module -avoid-version
pnm_la_LIBADD = $(top_builddir)/src/lib/libImlib2.la
pnm_la_LIBTOOLFLAGS = --tag=disable-static
svg_la_SOURCES = loader_svg.c
svg_la_CPPFLAGS = $(SVG_CFLAGS) $(AM_CPPFLAGS)
svg_la_LDFLAGS = -module -avoid-version
svg_la_LIBADD = $(SVG_LIBS) $(top_builddir)/src/lib/libImlib2.la
svg_la_LIBTOOLFLAGS = --tag=disable-static
tga_la_SOURCES = loader_tga.c
tga_la_LDFLAGS = -module -avoid-version
tga_la_LIBADD = $(top_builddir)/src/lib/libImlib2.la

View File

@ -0,0 +1,200 @@
#include "loader_common.h"
#include <math.h>
#include <sys/mman.h>
#include <librsvg/rsvg.h>
#define DBG_PFX "LDR-svg"
#define DPI 96
static double
u2pix(double x, int unit)
{
switch (unit)
{
default:
case RSVG_UNIT_PERCENT: /* 0 percentage values where 1.0 means 100% */
case RSVG_UNIT_PX: /* 1 pixels */
case RSVG_UNIT_EM: /* 2 em, or the current font size */
case RSVG_UNIT_EX: /* 3 x-height of the current font */
return x;
case RSVG_UNIT_IN: /* 4 inches */
return x * DPI;
case RSVG_UNIT_CM: /* 5 centimeters */
return x * DPI / 2.54;
case RSVG_UNIT_MM: /* 6 millimeters */
return x * DPI / 25.4;
case RSVG_UNIT_PT: /* 7 points, or 1/72 inch */
return x * DPI / 72;
case RSVG_UNIT_PC: /* 8 picas, or 1/6 inch (12 points) */
return x * DPI / 6;
}
}
int
load2(ImlibImage * im, int load_data)
{
int rc;
void *fdata;
RsvgHandle *rsvg;
GError *error;
gboolean ok;
cairo_surface_t *surface;
cairo_t *cr;
RsvgRectangle cvb;
rc = LOAD_FAIL;
fdata = mmap(NULL, im->fsize, PROT_READ, MAP_SHARED, fileno(im->fp), 0);
if (fdata == MAP_FAILED)
return LOAD_BADFILE;
surface = NULL;
cr = NULL;
error = NULL;
rsvg = rsvg_handle_new_from_data(fdata, im->fsize, &error);
if (!rsvg)
goto quit;
rc = LOAD_BADIMAGE; /* Format accepted */
{
gboolean out_has_width, out_has_height, out_has_viewbox;
RsvgLength out_width = { }, out_height = { };
RsvgRectangle out_viewbox = { };
rsvg_handle_get_intrinsic_dimensions(rsvg,
&out_has_width,
&out_width,
&out_has_height,
&out_height,
&out_has_viewbox, &out_viewbox);
D("WH:%d%d %.1fx%.1f (%d/%d: %.1fx%.1f) VB:%d %.1f,%.1f %.1fx%.1f\n",
out_has_width, out_has_height,
out_width.length, out_height.length, out_width.unit, out_height.unit,
u2pix(out_width.length, out_width.unit),
u2pix(out_height.length, out_height.unit),
out_has_viewbox,
out_viewbox.x, out_viewbox.y, out_viewbox.width, out_viewbox.height);
if (out_has_width && out_has_height)
{
im->w = lrint(u2pix(out_width.length, out_width.unit));
im->h = lrint(u2pix(out_height.length, out_height.unit));
D("Choose rsvg_handle_get_intrinsic_dimensions width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
if (out_has_viewbox && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(out_viewbox.width);
im->h = ceil(out_viewbox.height);
D("Choose rsvg_handle_get_intrinsic_dimensions viewbox\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#if 0
#if LIBRSVG_CHECK_VERSION(2, 52, 0)
{
gdouble dw = 0, dh = 0;
ok = rsvg_handle_get_intrinsic_size_in_pixels(rsvg, &dw, &dh);
D("ok=%d WxH=%.1fx%.1f\n", ok, dw, dh);
if (ok && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(dw);
im->h = ceil(dh);
D("Choose rsvg_handle_get_intrinsic_size_in_pixels width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#endif
#endif
{
RsvgRectangle out_ink_rect = { }, out_logical_rect = { };
ok = rsvg_handle_get_geometry_for_element(rsvg, NULL,
&out_ink_rect,
&out_logical_rect, &error);
D("ok=%d Ink: %.1f,%.1f %.1fx%.1f Log: %.1f,%.1f %.1fx%.1f\n", ok,
out_ink_rect.x, out_ink_rect.y, out_ink_rect.width, out_ink_rect.height,
out_logical_rect.x, out_logical_rect.y, out_logical_rect.width,
out_logical_rect.height);
if (ok && (im->w <= 0 || im->w <= 0))
{
im->w = ceil(out_ink_rect.width);
im->h = ceil(out_ink_rect.height);
D("Choose rsvg_handle_get_geometry_for_element ink rect width/height\n");
#if !IMLIB2_DEBUG
goto got_size;
#endif
}
}
#if !IMLIB2_DEBUG
got_size:
#endif
if (!IMAGE_DIMENSIONS_OK(im->w, im->h))
goto quit;
UPDATE_FLAG(im->flags, F_HAS_ALPHA, 1);
if (!load_data)
QUIT_WITH_RC(LOAD_SUCCESS);
/* Load data */
if (!__imlib_AllocateData(im))
QUIT_WITH_RC(LOAD_OOM);
memset(im->data, 0, im->w * im->h * sizeof(DATA32));
surface =
cairo_image_surface_create_for_data((void *)im->data, CAIRO_FORMAT_ARGB32,
im->w, im->h,
im->w * sizeof(DATA32));;
if (!surface)
QUIT_WITH_RC(LOAD_OOM);
cr = cairo_create(surface);
if (!cr)
QUIT_WITH_RC(LOAD_OOM);
cvb.x = cvb.y = 0;
cvb.width = im->w;
cvb.height = im->h;
rsvg_handle_render_document(rsvg, cr, &cvb, &error);
if (im->lc)
__imlib_LoadProgress(im, im->frame_x, im->frame_y, im->w, im->h);
rc = LOAD_SUCCESS;
quit:
if (surface)
cairo_surface_destroy(surface);
if (cr)
cairo_destroy(cr);
if (rc <= 0)
__imlib_FreeData(im);
if (rsvg)
g_object_unref(rsvg);
munmap(fdata, im->fsize);
return rc;
}
void
formats(ImlibLoader * l)
{
static const char *const list_formats[] = { "svg" };
__imlib_LoaderSetFormats(l, list_formats, ARRAY_SIZE(list_formats));
}

9
test/images/icon-64.svg Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64px" height="64px" viewBox="0 0 64 64" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 64 0 L 50.910156 0 L 0 64 L 13.089844 64 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 5.816406 64 L 32 32 L 39.273438 32 L 13.089844 64 Z M 58.183594 0 L 32 32 L 24.726562 32 L 50.910156 0 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 0 0 L 16 0 L 64 64 L 48 64 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(100%,100%,100%);fill-opacity:1;" d="M 58.183594 0 L 56.726562 0 L 5.816406 64 L 7.273438 64 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 807 B

View File

@ -30,6 +30,9 @@ static const char *const pfxs[] = {
"pbm", // pnm
"ppm", // pnm
"tga",
#ifdef BUILD_SVG_LOADER
"svg",
#endif
"tiff",
"webp",
"xbm",