summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKim Woelders <kim@woelders.dk>2022-01-06 14:56:38 +0100
committerKim Woelders <kim@woelders.dk>2022-01-08 16:08:37 +0100
commita542fb672406be26599c089eee2c6e350bace9dd (patch)
tree3c77a4d84a6bb81ddc78aacf2c8935ac5a1c1ba1
parent04b8c35e175c09d705725385beecbff125aeb496 (diff)
downloadimlib2-a542fb672406be26599c089eee2c6e350bace9dd.tar.gz
Add svg loader
-rw-r--r--configure.ac2
-rw-r--r--src/lib/loaders.c6
-rw-r--r--src/modules/loaders/Makefile.am9
-rw-r--r--src/modules/loaders/loader_svg.c200
-rw-r--r--test/images/icon-64.svg9
-rw-r--r--test/test_load.cpp3
6 files changed, 229 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac
index 90d0cfa..90273ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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"
diff --git a/src/lib/loaders.c b/src/lib/loaders.c
index 1849677..757894b 100644
--- a/src/lib/loaders.c
+++ b/src/lib/loaders.c
@@ -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},
diff --git a/src/modules/loaders/Makefile.am b/src/modules/loaders/Makefile.am
index 29866fb..d7fea3a 100644
--- a/src/modules/loaders/Makefile.am
+++ b/src/modules/loaders/Makefile.am
@@ -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
diff --git a/src/modules/loaders/loader_svg.c b/src/modules/loaders/loader_svg.c
new file mode 100644
index 0000000..78ddd73
--- /dev/null
+++ b/src/modules/loaders/loader_svg.c
@@ -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));
+}
diff --git a/test/images/icon-64.svg b/test/images/icon-64.svg
new file mode 100644
index 0000000..72558ce
--- /dev/null
+++ b/test/images/icon-64.svg
@@ -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>
diff --git a/test/test_load.cpp b/test/test_load.cpp
index b15fe9a..1728263 100644
--- a/test/test_load.cpp
+++ b/test/test_load.cpp
@@ -30,6 +30,9 @@ static const char *const pfxs[] = {
"pbm", // pnm
"ppm", // pnm
"tga",
+#ifdef BUILD_SVG_LOADER
+ "svg",
+#endif
"tiff",
"webp",
"xbm",