diff options
author | Kim Woelders <kim@woelders.dk> | 2022-01-06 14:56:38 +0100 |
---|---|---|
committer | Kim Woelders <kim@woelders.dk> | 2022-01-08 16:08:37 +0100 |
commit | a542fb672406be26599c089eee2c6e350bace9dd (patch) | |
tree | 3c77a4d84a6bb81ddc78aacf2c8935ac5a1c1ba1 | |
parent | 04b8c35e175c09d705725385beecbff125aeb496 (diff) | |
download | imlib2-a542fb672406be26599c089eee2c6e350bace9dd.tar.gz |
Add svg loader
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/lib/loaders.c | 6 | ||||
-rw-r--r-- | src/modules/loaders/Makefile.am | 9 | ||||
-rw-r--r-- | src/modules/loaders/loader_svg.c | 200 | ||||
-rw-r--r-- | test/images/icon-64.svg | 9 | ||||
-rw-r--r-- | test/test_load.cpp | 3 |
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", |