rsvg/0000755000176200001440000000000014200153071011224 5ustar liggesusersrsvg/NAMESPACE0000644000176200001440000000040314177744770012471 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(librsvg_version) export(rsvg) export(rsvg_eps) export(rsvg_pdf) export(rsvg_png) export(rsvg_ps) export(rsvg_raw) export(rsvg_svg) export(rsvg_webp) useDynLib(rsvg,R_librsvg_version) useDynLib(rsvg,R_rsvg) rsvg/LICENSE0000644000176200001440000000005113656262217012246 0ustar liggesusersYEAR: 2016 COPYRIGHT HOLDER: Jeroen Ooms rsvg/tools/0000755000176200001440000000000013656262217012405 5ustar liggesusersrsvg/tools/winlibs.R0000644000176200001440000000066313656262217014204 0ustar liggesusers# Build against static libraries from rwinlib VERSION <- commandArgs(TRUE) if(!file.exists(sprintf("../windows/rsvg-%s/include/librsvg-2.0/librsvg/rsvg.h", VERSION))){ if(getRversion() < "3.3.0") setInternet2() download.file(sprintf("https://github.com/rwinlib/rsvg/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "../windows") unlink("lib.zip") } rsvg/man/0000755000176200001440000000000014177747567012037 5ustar liggesusersrsvg/man/librsvg_version.Rd0000644000176200001440000000036414043614232015514 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/version.R \name{librsvg_version} \alias{librsvg_version} \title{librsvg version} \usage{ librsvg_version() } \description{ Print the version of the librsvg library } rsvg/man/rsvg.Rd0000644000176200001440000000432514177747567013313 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/rsvg.R \name{rsvg} \alias{rsvg} \alias{rsvg_raw} \alias{rsvg_webp} \alias{rsvg_png} \alias{rsvg_pdf} \alias{rsvg_svg} \alias{rsvg_ps} \alias{rsvg_eps} \title{Render SVG into Bitmap} \usage{ rsvg(svg, width = NULL, height = NULL, css = NULL) rsvg_raw(svg, width = NULL, height = NULL, css = NULL) rsvg_webp(svg, file = NULL, width = NULL, height = NULL, css = NULL) rsvg_png(svg, file = NULL, width = NULL, height = NULL, css = NULL) rsvg_pdf(svg, file = NULL, width = NULL, height = NULL, css = NULL) rsvg_svg(svg, file = NULL, width = NULL, height = NULL, css = NULL) rsvg_ps(svg, file = NULL, width = NULL, height = NULL, css = NULL) rsvg_eps(svg, file = NULL, width = NULL, height = NULL, css = NULL) } \arguments{ \item{svg}{path/url to svg file or raw vector with svg data. Use \link{charToRaw} to convert an SVG string into raw data.} \item{width}{output width in pixels or \code{NULL} for default.} \item{height}{output height in pixels or \code{NULL} for default} \item{css}{path/url to external css file or raw vector with css data. This requires your system has a recent version of librsvg.} \item{file}{path to output file or \code{NULL} to return content as raw vector} } \description{ Render svg image into a high quality bitmap. When both \code{width} and \code{height} are \code{NULL}, the output resolution matches that of the input. When either \code{width} or \code{height} is specified, the image is scaled proportionally. When both \code{width} and \code{height} are specified, the image is stretched into the requested size. } \examples{ # create some svg options(example.ask=FALSE) tmp <- tempfile() svglite::svglite(tmp, width = 10, height = 7) ggplot2::qplot(mpg, wt, data = mtcars, colour = factor(cyl)) dev.off() # convert directly into a vector or bitmap graphics format rsvg_pdf(tmp, "out.pdf") rsvg_png(tmp, "out.png") rsvg_svg(tmp, "out.svg") rsvg_ps(tmp, "out.ps") rsvg_eps(tmp, "out.eps") # render into raw bitmap array bitmap <- rsvg(tmp, height = 1440) dim(bitmap) # h*w*c # read in your package of choice magick::image_read(bitmap) webp::write_webp(bitmap, "bitmap.webp", quality = 100) # cleanup unlink(c("out.*", "bitmap.webp")) } rsvg/DESCRIPTION0000644000176200001440000000241714200153071012736 0ustar liggesusersType: Package Package: rsvg Title: Render SVG Images into PDF, PNG, (Encapsulated) PostScript, or Bitmap Arrays Version: 2.2.0 Authors@R: c( person("Jeroen", "Ooms", , "jeroen@berkeley.edu", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-4035-0289")), person("Salim", "Brüggemann", , "salim-b@pm.me", role = c("ctb"), comment = c(ORCID = "0000-0002-5329-5987"))) Description: Renders vector-based svg images into high-quality custom-size bitmap arrays using 'librsvg2'. The resulting bitmap can be written to e.g. png, jpeg or webp format. In addition, the package can convert images directly to various formats such as pdf or postscript. License: MIT + file LICENSE URL: https://github.com/jeroen/rsvg BugReports: https://github.com/jeroen/rsvg/issues Suggests: ggplot2, knitr, magick, rmarkdown, spelling, svglite, webp VignetteBuilder: knitr Encoding: UTF-8 Language: en-US RoxygenNote: 7.1.2 SystemRequirements: librsvg2 NeedsCompilation: yes Packaged: 2022-02-06 14:03:55 UTC; jeroen Author: Jeroen Ooms [aut, cre] (), Salim Brüggemann [ctb] () Maintainer: Jeroen Ooms Repository: CRAN Date/Publication: 2022-02-07 08:20:09 UTC rsvg/build/0000755000176200001440000000000014177752513012346 5ustar liggesusersrsvg/build/vignette.rds0000644000176200001440000000033414177752513014705 0ustar liggesusersb```b`adb`b2 1# '..KM.. MAJKI-KWsW(,PpVSBS3%$7Mn5`  `aBRȚZ% ?iN,/AQU▙ 7$apq2݀a>9`~}MI,F(WJbI^ZP?}oorsvg/tests/0000755000176200001440000000000014043614477012407 5ustar liggesusersrsvg/tests/spelling.R0000644000176200001440000000007413656262217014350 0ustar liggesusersspelling::spell_check_test(vignettes = TRUE, error = FALSE) rsvg/tests/engine.R0000644000176200001440000000001614043614525013766 0ustar liggesuserslibrary(rsvg) rsvg/tests/engine.Rout.save0000644000176200001440000000121214043614512015446 0ustar liggesusers R version 3.5.3 (2019-03-11) -- "Great Truth" Copyright (C) 2019 The R Foundation for Statistical Computing Platform: x86_64-apple-darwin15.6.0 (64-bit) R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > library(rsvg) > rsvg/src/0000755000176200001440000000000014177752513012036 5ustar liggesusersrsvg/src/rsvg.c0000644000176200001440000001547614177747567013215 0ustar liggesusers#define R_NO_REMAP #define STRICT_R_HEADERS #include #include #include #include #include #include #include #include #include typedef struct { unsigned char *buf; size_t size; } memory; #if LIBRSVG_CHECK_VERSION(2,52,0) static int unit_to_px(RsvgLength x){ double l = x.length; switch(x.unit){ case RSVG_UNIT_PX: case RSVG_UNIT_PT: return l; case RSVG_UNIT_IN: return 300*l; case RSVG_UNIT_CM: return 100*l; default: return 800; } } #endif static void setup_render_handle(RsvgHandle *svg, cairo_t *cr){ #if LIBRSVG_CHECK_VERSION(2,52,0) GError *err = NULL; RsvgRectangle viewport = {0.0}; //viewport.width = width; //viewport.height = height; rsvg_handle_render_document(svg, cr, &viewport, &err); if(err != NULL) Rf_error("Failure in rsvg_handle_render_document: %s", err->message); #else if(!rsvg_handle_render_cairo(svg, cr)) Rf_error("Cairo failed to render svg"); #endif } static SEXP write_bitmap(RsvgHandle *svg, int width, int height, double sx, double sy){ cairo_surface_t *canvas = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(canvas); cairo_scale(cr, sx, sy); setup_render_handle(svg, cr); int stride = cairo_image_surface_get_stride(canvas); //should be equal to width * channels int size = stride * height; cairo_surface_flush(canvas); SEXP image = PROTECT(Rf_allocVector(RAWSXP, size)); SEXP dim = Rf_allocVector(INTSXP, 3); INTEGER(dim)[0] = 4; INTEGER(dim)[1] = width; INTEGER(dim)[2] = height; Rf_setAttrib(image, R_DimSymbol, dim); memcpy(RAW(image), cairo_image_surface_get_data(canvas), size); UNPROTECT(1); g_object_unref(svg); cairo_surface_destroy(canvas); cairo_destroy(cr); return image; } static cairo_status_t write_func(void *ctx, const unsigned char *data, unsigned int length) { memory *mem = (memory*) ctx; #ifdef _WIN32 mem->buf = realloc(mem->buf, exp2(ceil(log2(mem->size + length)))); #else mem->buf = realloc(mem->buf, mem->size + length); #endif if (!mem->buf) return CAIRO_STATUS_WRITE_ERROR; memcpy(&(mem->buf[mem->size]), data, length); mem->size += length; return CAIRO_STATUS_SUCCESS; } static SEXP write_png(RsvgHandle *svg, int width, int height, double sx, double sy){ cairo_surface_t *canvas = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); cairo_t *cr = cairo_create(canvas); cairo_scale(cr, sx, sy); setup_render_handle(svg, cr); memory mem = {NULL, 0}; cairo_surface_write_to_png_stream(canvas, write_func, &mem); cairo_surface_flush(canvas); cairo_surface_destroy(canvas); cairo_destroy(cr); g_object_unref(svg); SEXP res = Rf_allocVector(RAWSXP, mem.size); memcpy(RAW(res), mem.buf, mem.size); free(mem.buf); return res; } static SEXP write_stream(RsvgHandle *svg, int width, int height, double sx, double sy, cairo_surface_t* (*fun) (cairo_write_func_t, void *, double, double), cairo_bool_t is_eps) { memory buf = {NULL, 0}; cairo_surface_t *canvas = fun(write_func, &buf, width, height); if(is_eps) cairo_ps_surface_set_eps(canvas, TRUE); cairo_t *cr = cairo_create(canvas); cairo_scale(cr, sx, sy); setup_render_handle(svg, cr); cairo_surface_show_page(canvas); cairo_surface_flush(canvas); cairo_surface_destroy(canvas); cairo_destroy(cr); g_object_unref(svg); SEXP res = Rf_allocVector(RAWSXP, buf.size); memcpy(RAW(res), buf.buf, buf.size); free(buf.buf); return res; } SEXP R_rsvg(SEXP data, SEXP rwidth, SEXP rheight, SEXP format, SEXP css){ GError *err = NULL; RsvgHandle *svg = rsvg_handle_new_from_data (RAW(data), LENGTH(data), &err); if(err != NULL) Rf_error("Failed to parse svg: %s", err->message); if(Rf_length(css)){ #if LIBRSVG_CHECK_VERSION(2,48,0) if(!rsvg_handle_set_stylesheet(svg, (const unsigned char *) RAW(css), Rf_length(css), &err) || err){ //Note: this doesn't seem to work? //Looks like rsvg_handle_set_stylesheet never fails. g_object_unref(svg); Rf_error("Failed to load css stylesheet: %s", err ? err->message : ""); } #else Rf_warning("An external CSS file was specified but this requires at least librsvg 2.48 (you have %s)", LIBRSVG_VERSION); #endif } #if LIBRSVG_CHECK_VERSION(2,52,0) gboolean has_width; RsvgLength in_width; gboolean has_height; RsvgLength in_height; gboolean has_viewbox; RsvgRectangle viewbox; rsvg_handle_get_intrinsic_dimensions (svg, &has_width, &in_width, &has_height, &in_height, &has_viewbox, &viewbox); double input_width = has_viewbox ? viewbox.width : (has_width ? unit_to_px(in_width) : 800); double input_height = has_viewbox ? viewbox.height : (has_height ? unit_to_px(in_height) : 800); //REprintf("Size: %fx%f\n", input_width, input_height); #else RsvgDimensionData dimensions; rsvg_handle_get_dimensions(svg, &dimensions); int input_width = dimensions.width; int input_height = dimensions.height; //REprintf("Size: %fx%f\n", (double)input_width, (double)input_height); #endif //scale into the requested resolution double width; double height; double sx; double sy; if(rwidth == R_NilValue && rheight == R_NilValue){ width = input_width; height = input_height; sx = sy = 1; } else if(rwidth != R_NilValue && rheight != R_NilValue){ width = Rf_asInteger(rwidth); height = Rf_asInteger(rheight); sx = width / input_width; sy = height / input_height; } else if(rwidth != R_NilValue){ width = Rf_asInteger(rwidth); sx = sy = width / input_width; height = round(input_height * sy); } else { height = Rf_asInteger(rheight); sx = sy = height / input_height; width = round(input_width * sx); } switch(Rf_asInteger(format)){ case 0: return write_bitmap(svg, width, height, sx, sy); case 1: return write_png(svg, width, height, sx, sy); case 2: return write_stream(svg, width, height, sx, sy, cairo_pdf_surface_create_for_stream, FALSE); case 3: return write_stream(svg, width, height, sx, sy, cairo_svg_surface_create_for_stream, FALSE); case 4: return write_stream(svg, width, height, sx, sy, cairo_ps_surface_create_for_stream, FALSE); case 5: return write_stream(svg, width, height, sx, sy, cairo_ps_surface_create_for_stream, TRUE); } return R_NilValue; } SEXP R_librsvg_version(){ return Rf_mkString(LIBRSVG_VERSION); } void R_init_rsvg(DllInfo *dll) { #if !defined(LIBRSVG_MAJOR_VERSION) || LIBRSVG_MAJOR_VERSION == 2 #if !defined(LIBRSVG_MINOR_VERSION) || LIBRSVG_MINOR_VERSION < 36 g_type_init(); #endif #endif static const R_CallMethodDef CallEntries[] = { {"R_rsvg", (DL_FUNC) &R_rsvg, 5}, {"R_librsvg_version", (DL_FUNC) &R_librsvg_version, 0}, {NULL, NULL, 0} }; R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } rsvg/src/Makevars.win0000644000176200001440000000151514043623670014321 0ustar liggesusersVERSION = 2.48.8 RWINLIB = ../windows/rsvg-$(VERSION) all: clean winlibs winlibs: clean "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" $(VERSION) clean: rm -f $(SHLIB) $(OBJECTS) PKG_CPPFLAGS = \ -I$(RWINLIB)/include/librsvg-2.0 \ -I$(RWINLIB)/include/glib-2.0 \ -I$(RWINLIB)/lib${R_ARCH}/glib-2.0/include \ -I$(RWINLIB)/include/gdk-pixbuf-2.0 \ -I$(RWINLIB)/include/cairo LIBBUILD = ${subst gcc ,-,${R_COMPILED_BY}}${R_ARCH} PKG_LIBS = \ -L$(RWINLIB)/lib${LIBBUILD} \ -L$(RWINLIB)/lib${R_ARCH}${CRT} \ -lrsvg-2 -lxml2 \ -lpangocairo-1.0 -lpango-1.0 -lpangowin32-1.0 \ -lcairo -lfreetype -lpixman-1 -lgdk_pixbuf-2.0 \ -lcairo-gobject -lgio-2.0 -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 \ -lffi -lpcre -lpng16 -lintl -lz -liconv -lfribidi \ -lusp10 -liphlpapi -lgdiplus -lgdi32 -lole32 -ldnsapi -lws2_32 -luserenv rsvg/src/Makevars.ucrt0000644000176200001440000000003714043620320014464 0ustar liggesusersCRT=-ucrt include Makevars.win rsvg/src/Makevars.in0000644000176200001440000000004614037640500014122 0ustar liggesusersPKG_CPPFLAGS=@cflags@ PKG_LIBS=@libs@ rsvg/vignettes/0000755000176200001440000000000014177752513013257 5ustar liggesusersrsvg/vignettes/svg-css.Rmd0000644000176200001440000000552114177752217015314 0ustar liggesusers--- title: "Rendering SVG with CSS in R" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rendering SVG with CSS in R} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) library(rsvg) ``` The `rsvg` R package provides bindings to [librsvg-2](https://wiki.gnome.org/Projects/LibRsvg) to render SVG files into bitmaps directly from R. On Linux systems, you need to install librsvg from `apt` or `yum` before installing the R package from CRAN. On Windows and MacOS this is not needed. ## SVG with embedded CSS This [Mozilla example](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/style) shows that the SVG specification allows for a `style` element, which is also supported in all browsers. Embedded CSS is supported in all versions of librsvg, but the quality of css rendering has improved a lot in recent versions of librsvg. ```{r} str <- charToRaw(' ') rsvg_png(str, file = 'ex1.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG with embedded CSS"} knitr::include_graphics("ex1.png") ``` ## SVG with external CSS Recent versions of librsvg can also apply an external CSS file to the SVG. This has the same effect as an external CSS file that is embedded in header of an HTML file. By using an external CSS, we can split the drawing structure from the styling. The new "css" parameter requires a somewhat recent version of librsvg so it may not work on older Linux systems. It is available on any MacOS or Windows, and the latest versions of Ubuntu, Debian, Fedora, etc. ```{r} svg <- charToRaw(' ') # Render without style: rsvg_png(svg, file = 'ex2.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG without CSS"} knitr::include_graphics("ex2.png") ``` ```{r} css <- charToRaw('circle { fill: navy; stroke: hotpink; stroke-width: 10px; }') # Render without style: rsvg_png(svg, css = css, file = 'ex3.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG with external CSS"} knitr::include_graphics("ex3.png") ``` ## Bitmap rendering and magick The examples above write the rendered SVG file directly to a PNG file on disk. But you can also render the SVG to an in-memory bitmap buffer. ```{r} bitmap <- rsvg_raw('https://jeroen.github.io/images/tiger.svg', width = 600) str(bitmap) ``` The `bitmap` object is an array in R that contain the pixels of the image. You can read it for example using the `magick` package for subsequent image editing, or to save it to a standard format. ```{r} magick::image_read(bitmap) ``` rsvg/NEWS0000644000176200001440000000250014177747567011760 0ustar liggesusers2.2.0 - Add `rsvg_eps()` which converts to Encapsulated PostScript (EPS) format (@salim-b) - Fix some deprecation warnings 2.1.2 - Windows: update to librsvg v2.48.8 - Add ucrt64 support 2.1.1 - CRAN stuff 2.1 - Expose 'css' parameter - Add vignette 'Rendering SVG with CSS in R' 2.0 - Windows, Mac: upgrade to librsvg 2.48.4. This is a major upgrade, librsvg has been rewritten completely in rust based on Mozilla Servo. 1.3 - Upgraded autobrew to 2.42.2 with custom bottle 1.2 - MacOS: use librsvg 2.40.19 because 2.42 has static linking bug 1.1 - Fix the configure script to use legacybrew on OSX 10.9 for CRAN 1.0 - Upgrade to fully static librsvg 2.40.16 build on Windows - Fixed a bug that could cause a freeze or segfault with old versions of librsvg 0.6 - Update Homebrew URL in configure script - Change autobrew to --force-bottle dependencies and use current glib2 - Add '-framework AppKit' to PKG_LIBS for OSX static binary (needed by CMD check) 0.5 - Fix for Warning on OSX CRAN builder. - Minor tweaks to configure script 0.4 - Fix autobrew script for Snow Leopard 0.3 - Add output formats rsvg_png() rsvg_pdf() rsvg_ps() rsvg_svg() - Fix for rounding issue in proportional image scaling - Add support for url in rsvg() 0.2 - Initial CRAN release with Windows support rsvg/configure.win0000644000176200001440000000000013656262217013733 0ustar liggesusersrsvg/R/0000755000176200001440000000000014177747567011465 5ustar liggesusersrsvg/R/rsvg.R0000644000176200001440000001027614177747567012577 0ustar liggesusers#' Render SVG into Bitmap #' #' Render svg image into a high quality bitmap. When both \code{width} and \code{height} #' are \code{NULL}, the output resolution matches that of the input. When either \code{width} #' or \code{height} is specified, the image is scaled proportionally. When both \code{width} #' and \code{height} are specified, the image is stretched into the requested size. #' #' @export #' @useDynLib rsvg R_rsvg #' @param svg path/url to svg file or raw vector with svg data. Use \link{charToRaw} to convert #' an SVG string into raw data. #' @param width output width in pixels or \code{NULL} for default. #' @param height output height in pixels or \code{NULL} for default #' @param css path/url to external css file or raw vector with css data. This #' requires your system has a recent version of librsvg. #' @rdname rsvg #' @examples # create some svg #' options(example.ask=FALSE) #' tmp <- tempfile() #' svglite::svglite(tmp, width = 10, height = 7) #' ggplot2::qplot(mpg, wt, data = mtcars, colour = factor(cyl)) #' dev.off() #' #' # convert directly into a vector or bitmap graphics format #' rsvg_pdf(tmp, "out.pdf") #' rsvg_png(tmp, "out.png") #' rsvg_svg(tmp, "out.svg") #' rsvg_ps(tmp, "out.ps") #' rsvg_eps(tmp, "out.eps") #' #' # render into raw bitmap array #' bitmap <- rsvg(tmp, height = 1440) #' dim(bitmap) # h*w*c #' #' # read in your package of choice #' magick::image_read(bitmap) #' webp::write_webp(bitmap, "bitmap.webp", quality = 100) #' #' # cleanup #' unlink(c("out.*", "bitmap.webp")) rsvg <- function(svg, width = NULL, height = NULL, css = NULL) { out <- rsvg_raw(svg, width = width, height = height, css = css) out <- structure(as.numeric(out)/255, dim = dim(out)) aperm(out) # Convert to standard with*height*rgba } #' @rdname rsvg #' @export rsvg_raw <- function(svg, width = NULL, height = NULL, css = NULL) { svg <- read_data(svg) if(length(css)){ css <- read_data(css) } stopifnot(is.null(width) || is.numeric(width)) stopifnot(is.null(height) || is.numeric(height)) out <- .Call(R_rsvg, svg, width, height, 0L, css) out[c(3,2,1,4),,, drop = FALSE] } #' @rdname rsvg #' @export rsvg_webp <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { out <- rsvg_raw(svg, width = width, height = height, css = css) webp::write_webp(out, file, 100) } #' @rdname rsvg #' @export #' @param file path to output file or \code{NULL} to return content as raw vector rsvg_png <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { rsvg_format(svg, file, width = width, height = height, css = css, format = 1L) } #' @rdname rsvg #' @export rsvg_pdf <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { rsvg_format(svg, file, width = width, height = height, css = css, format = 2L) } #' @rdname rsvg #' @export rsvg_svg <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { rsvg_format(svg, file, width = width, height = height, css = css, format = 3L) } #' @rdname rsvg #' @export rsvg_ps <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { rsvg_format(svg, file, width = width, height = height, css = css, format = 4L) } #' @rdname rsvg #' @export rsvg_eps <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL) { rsvg_format(svg, file, width = width, height = height, css = css, format = 5L) } rsvg_format <- function(svg, file = NULL, width = NULL, height = NULL, css = NULL, format = 0L) { svg <- read_data(svg) if(length(css)){ css <- read_data(css) } stopifnot(is.null(width) || is.numeric(width)) stopifnot(is.null(height) || is.numeric(height)) out <- .Call(R_rsvg, svg, width, height, format, css) if(is.character(file)){ writeBin(out, file[1]) } else { return(out) } } read_data <- function(svg){ if(is.character(svg)){ if(grepl("^https?://", svg)){ con <- url(svg, "rb") on.exit(close(con)) svg <- raw(); while(length(buf <- readBin(con, raw(), 1e6))){ svg <- c(svg, buf) } } else if(file.exists(svg)){ svg <- readBin(svg, raw(), file.info(svg)$size) } else { stop("Argument 'svg' or 'css' must be a file path, url, or raw vector.") } } stopifnot(is.raw(svg)) return(svg) } rsvg/R/version.R0000644000176200001440000000044114043614423013244 0ustar liggesusers#' librsvg version #' #' Print the version of the librsvg library #' #' @export #' @useDynLib rsvg R_librsvg_version librsvg_version <- function(){ .Call(R_librsvg_version) } .onAttach <- function(libname, pkg){ packageStartupMessage(paste("Linking to librsvg", librsvg_version())) } rsvg/MD50000644000176200001440000000230714200153071011536 0ustar liggesusersc7853dcf153907852d08b111cd22c0df *DESCRIPTION 91443a13b3d89ea22bfa1222461b0111 *LICENSE 8e28502b4d9d9133a0135e30843c9ba7 *NAMESPACE 3046a8cd7368db8e1e3b7600b26eda81 *NEWS e6c9597b81158a66fffadaec902d9df7 *R/rsvg.R 177a6ad2e634248dfa712a79769774af *R/version.R 6b4b5542d421c7066886f8a2e451b649 *build/vignette.rds 4ce1fcf8d4a4b68aac58e1c00c2db6d0 *cleanup 6c4b46a003d897b3c1369eea50ef4a09 *configure d41d8cd98f00b204e9800998ecf8427e *configure.win 690cb4dddb253549c5d9e28a6b37d5a9 *inst/WORDLIST c4d24ca2b9d8f4e3478886f323cbde2b *inst/doc/svg-css.R 5d02f4fae14e589cc59f1c546851730d *inst/doc/svg-css.Rmd 27d8fbc367afd16f675b09bc73022e6b *inst/doc/svg-css.html 7bc96f2139bc0d6d2d7bd370cd80eafb *man/librsvg_version.Rd 148683c64c42fb36c63c5d9660159884 *man/rsvg.Rd 111e1efb50ff675feb507ea42a24b300 *src/Makevars.in 2cec33791efd347cbcb051402d7cf9c4 *src/Makevars.ucrt 2a4531a0b2f5c61acbe9ac508e9772b9 *src/Makevars.win 9e446c20fbd88b173f63674e0e418425 *src/rsvg.c acf961b512c3a18d79ad47b2f088e9a7 *tests/engine.R 72bc94fdb523877ecce355437756df88 *tests/engine.Rout.save bc882e5235bfdccc9e49f99290365b40 *tests/spelling.R fff247a06122a190113e672035c4be2f *tools/winlibs.R 5d02f4fae14e589cc59f1c546851730d *vignettes/svg-css.Rmd rsvg/inst/0000755000176200001440000000000014177752513012224 5ustar liggesusersrsvg/inst/doc/0000755000176200001440000000000014177752513012771 5ustar liggesusersrsvg/inst/doc/svg-css.R0000644000176200001440000000311714177752512014502 0ustar liggesusers## ----setup, include=FALSE----------------------------------------------------- knitr::opts_chunk$set(echo = TRUE) library(rsvg) ## ----------------------------------------------------------------------------- str <- charToRaw(' ') rsvg_png(str, file = 'ex1.png') ## ---- echo=FALSE, fig.cap="Rendering of SVG with embedded CSS"---------------- knitr::include_graphics("ex1.png") ## ----------------------------------------------------------------------------- svg <- charToRaw(' ') # Render without style: rsvg_png(svg, file = 'ex2.png') ## ---- echo=FALSE, fig.cap="Rendering of SVG without CSS"---------------------- knitr::include_graphics("ex2.png") ## ----------------------------------------------------------------------------- css <- charToRaw('circle { fill: navy; stroke: hotpink; stroke-width: 10px; }') # Render without style: rsvg_png(svg, css = css, file = 'ex3.png') ## ---- echo=FALSE, fig.cap="Rendering of SVG with external CSS"---------------- knitr::include_graphics("ex3.png") ## ----------------------------------------------------------------------------- bitmap <- rsvg_raw('https://jeroen.github.io/images/tiger.svg', width = 600) str(bitmap) ## ----------------------------------------------------------------------------- magick::image_read(bitmap) rsvg/inst/doc/svg-css.html0000644000176200001440000112322514177752513015252 0ustar liggesusers Rendering SVG with CSS in R

Rendering SVG with CSS in R

The rsvg R package provides bindings to librsvg-2 to render SVG files into bitmaps directly from R. On Linux systems, you need to install librsvg from apt or yum before installing the R package from CRAN. On Windows and MacOS this is not needed.

SVG with embedded CSS

This Mozilla example shows that the SVG specification allows for a style element, which is also supported in all browsers. Embedded CSS is supported in all versions of librsvg, but the quality of css rendering has improved a lot in recent versions of librsvg.

str <- charToRaw('<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
  <style>
    circle {
      fill: gold;
      stroke: maroon;
      stroke-width: 10px;
    }
  </style>

  <circle cx="150" cy="150" r="100" />
</svg>')
rsvg_png(str, file = 'ex1.png')
Rendering of SVG with embedded CSS

Rendering of SVG with embedded CSS

SVG with external CSS

Recent versions of librsvg can also apply an external CSS file to the SVG. This has the same effect as an external CSS file that is embedded in header of an HTML file.

By using an external CSS, we can split the drawing structure from the styling. The new “css” parameter requires a somewhat recent version of librsvg so it may not work on older Linux systems. It is available on any MacOS or Windows, and the latest versions of Ubuntu, Debian, Fedora, etc.

svg <- charToRaw('<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
  <circle cx="150" cy="150" r="100" />
</svg>')

# Render without style:
rsvg_png(svg, file = 'ex2.png')
Rendering of SVG without CSS

Rendering of SVG without CSS

css <- charToRaw('circle {
  fill: navy;
  stroke: hotpink;
  stroke-width: 10px;
}')
# Render without style:
rsvg_png(svg, css = css, file = 'ex3.png')
Rendering of SVG with external CSS

Rendering of SVG with external CSS

Bitmap rendering and magick

The examples above write the rendered SVG file directly to a PNG file on disk. But you can also render the SVG to an in-memory bitmap buffer.

bitmap <- rsvg_raw('https://jeroen.github.io/images/tiger.svg', width = 600)
str(bitmap)
##  raw [1:4, 1:600, 1:600] 00 00 00 00 ...

The bitmap object is an array in R that contain the pixels of the image. You can read it for example using the magick package for subsequent image editing, or to save it to a standard format.

magick::image_read(bitmap)

rsvg/inst/doc/svg-css.Rmd0000644000176200001440000000552114177752217015026 0ustar liggesusers--- title: "Rendering SVG with CSS in R" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Rendering SVG with CSS in R} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE) library(rsvg) ``` The `rsvg` R package provides bindings to [librsvg-2](https://wiki.gnome.org/Projects/LibRsvg) to render SVG files into bitmaps directly from R. On Linux systems, you need to install librsvg from `apt` or `yum` before installing the R package from CRAN. On Windows and MacOS this is not needed. ## SVG with embedded CSS This [Mozilla example](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/style) shows that the SVG specification allows for a `style` element, which is also supported in all browsers. Embedded CSS is supported in all versions of librsvg, but the quality of css rendering has improved a lot in recent versions of librsvg. ```{r} str <- charToRaw(' ') rsvg_png(str, file = 'ex1.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG with embedded CSS"} knitr::include_graphics("ex1.png") ``` ## SVG with external CSS Recent versions of librsvg can also apply an external CSS file to the SVG. This has the same effect as an external CSS file that is embedded in header of an HTML file. By using an external CSS, we can split the drawing structure from the styling. The new "css" parameter requires a somewhat recent version of librsvg so it may not work on older Linux systems. It is available on any MacOS or Windows, and the latest versions of Ubuntu, Debian, Fedora, etc. ```{r} svg <- charToRaw(' ') # Render without style: rsvg_png(svg, file = 'ex2.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG without CSS"} knitr::include_graphics("ex2.png") ``` ```{r} css <- charToRaw('circle { fill: navy; stroke: hotpink; stroke-width: 10px; }') # Render without style: rsvg_png(svg, css = css, file = 'ex3.png') ``` ```{r, echo=FALSE, fig.cap="Rendering of SVG with external CSS"} knitr::include_graphics("ex3.png") ``` ## Bitmap rendering and magick The examples above write the rendered SVG file directly to a PNG file on disk. But you can also render the SVG to an in-memory bitmap buffer. ```{r} bitmap <- rsvg_raw('https://jeroen.github.io/images/tiger.svg', width = 600) str(bitmap) ``` The `bitmap` object is an array in R that contain the pixels of the image. You can read it for example using the `magick` package for subsequent image editing, or to save it to a standard format. ```{r} magick::image_read(bitmap) ``` rsvg/inst/WORDLIST0000644000176200001440000000014014043614625013402 0ustar liggesusersAppVeyor CentOS Github Homebrew MacOS OSX RHEL RStudio css dev jpeg librsvg magick png svg webp rsvg/cleanup0000755000176200001440000000006414177752513012624 0ustar liggesusers#!/bin/sh rm -f src/Makevars configure.log autobrew rsvg/configure0000755000176200001440000000544314177752513013164 0ustar liggesusers# Anticonf (tm) script by Jeroen Ooms (2020) # This script will query 'pkg-config' for the required cflags and ldflags. # If pkg-config is unavailable or does not find the library, try setting # INCLUDE_DIR and LIB_DIR manually via e.g: # R CMD INSTALL --configure-vars='INCLUDE_DIR=/.../include LIB_DIR=/.../lib' # Library settings PKG_CONFIG_NAME="librsvg-2.0" PKG_DEB_NAME="librsvg2-dev" PKG_RPM_NAME="librsvg2-devel" PKG_CSW_NAME="librsvg_dev, sunx11_devel" PKG_BREW_NAME="librsvg" PKG_TEST_HEADER="" PKG_LIBS="-lrsvg" PKG_CFLAGS="" # Use pkg-config if available pkg-config --version >/dev/null if [ $? -eq 0 ]; then PKGCONFIG_CFLAGS=`pkg-config --cflags ${PKG_CONFIG_NAME}` PKGCONFIG_LIBS=`pkg-config --libs --silence-errors ${PKG_CONFIG_NAME}` fi # Note that cflags may be empty in case of success if [ "$INCLUDE_DIR" ] || [ "$LIB_DIR" ]; then echo "Found INCLUDE_DIR and/or LIB_DIR!" PKG_CFLAGS="-I$INCLUDE_DIR $PKG_CFLAGS" PKG_LIBS="-L$LIB_DIR $PKG_LIBS" elif [ "$PKGCONFIG_CFLAGS" ] || [ "$PKGCONFIG_LIBS" ]; then echo "Found pkg-config cflags and libs!" PKG_CFLAGS=${PKGCONFIG_CFLAGS} PKG_LIBS=${PKGCONFIG_LIBS} elif [ `uname` = "Darwin" ]; then test ! "$CI" && brew --version 2>/dev/null if [ $? -eq 0 ]; then BREWDIR=`brew --prefix` PKG_CFLAGS="-I$BREWDIR/include" PKG_LIBS="-L$BREWDIR/lib $PKG_LIBS" else curl -sfL "https://autobrew.github.io/scripts/librsvg" > autobrew . ./autobrew fi fi # For debugging echo "Using PKG_CFLAGS=$PKG_CFLAGS" echo "Using PKG_LIBS=$PKG_LIBS" # Find compiler CC=`${R_HOME}/bin/R CMD config CC` CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` CPPFLAGS=`${R_HOME}/bin/R CMD config CPPFLAGS` # Test configuration echo "#include $PKG_TEST_HEADER" | ${CC} ${CPPFLAGS} ${PKG_CFLAGS} ${CFLAGS} -E -xc - >/dev/null 2>configure.log # Customize the error if [ $? -ne 0 ]; then echo "--------------------------- [ANTICONF] --------------------------------" echo "Configuration failed to find the $PKG_CONFIG_NAME library. Try installing:" echo " * deb: $PKG_DEB_NAME (Debian, Ubuntu, etc)" echo " * rpm: $PKG_RPM_NAME (Fedora, EPEL)" echo " * csw: $PKG_CSW_NAME (Solaris)" echo " * brew: $PKG_BREW_NAME (OSX)" echo "If $PKG_CONFIG_NAME is already installed, check that 'pkg-config' is in your" echo "PATH and PKG_CONFIG_PATH contains a $PKG_CONFIG_NAME.pc file. If pkg-config" echo "is unavailable you can set INCLUDE_DIR and LIB_DIR manually via:" echo "R CMD INSTALL --configure-vars='INCLUDE_DIR=... LIB_DIR=...'" echo "-------------------------- [ERROR MESSAGE] ---------------------------" cat configure.log echo "--------------------------------------------------------------------" exit 1 fi # Write to Makevars sed -e "s|@cflags@|$PKG_CFLAGS|" -e "s|@libs@|$PKG_LIBS|" src/Makevars.in > src/Makevars # Success exit 0