MRdotB

MRdotB

Resvg - SVG Rendering in Elixir with Rust

Greetings Elixir community!

Today, I’m thrilled to present you with resvg_nif, an open-source project that provides Elixir bindings for the Rust-based SVG rendering library resvg. After initially exploring resvg via a port, I decided to take a plunge into creating native bindings for it.

SVG to PNG conversion:

:ok = Resvg.svg_to_png("input.svg", "output.png")

Resvg also allows direct handling of SVG content as strings:

svg_string = """
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
  <path stroke-linecap="round" stroke-linejoin="round" d="M2.25 15a4.5 4.5 0 004.5 4.5H18a3.75 3.75 0 001.332-7.257 3 3 0 00-3.758-3.848 5.25 5.25 0 00-10.233 2.33A4.502 4.502 0 002.25 15z" />
</svg>
"""
:ok = Resvg.svg_string_to_png(svg_string, "output.png", resources_dir: "/tmp")

To see Resvg in action, you can try the Livebook !

This NIF originated from my endeavor to create a system for generating YouTube thumbnails. After experimenting with various approaches using ImageMagick and libvips, I discovered that utilizing SVGs for conversion yielded the best results, simplifying testing in the process. The impressive support for fonts and SVG images offered by Resvg is strikingly similar to the rendering you get in a browser, making adjustments and testing much easier.

One thumbnail generated from my svg template.

Most Liked

MRdotB

MRdotB

I have published resvg version 0.3.0

I added a query_all function which return the pos and size of nodes with id.

Resvg.query_all("rustacean.svg")
[
  %Resvg.Native.Node{
    id: "Layer-1",
    x: -63.99300003051758,
    y: 90.14399719238281,
    width: 1304.344970703125,
    height: 613.6170043945312
  }
]

The precompiled nif is now working on windows system.

MRdotB

MRdotB

Hello Kip,

Your work with image, and specifically the use of Operation.svgload_buffer(svg), was a significant source of inspiration while I was developing this library.

I encountered several issues with libvips / vix that led me to try alternative:

  1. Windows Support: One of my primary requirements was compatibility with Windows. Unfortunately, as of the time of development, vix did not support it.

  2. Font Loading with librsvg: I was unable to successfully get libvips to load my specific font.

  3. SVG local file resolution: Another challenge I faced pertained to the svg element <image> in librsvg when resolving local files.

I found resvg to be more compatible with my requirements. Resvg allowed you to specify the :resources_dir, facilitating the resolution of images from this path:

path = "/project/assets/"
svg_string = """
  <svg xmlns="http://www.w3.org/2000/svg" width="400" height="200"
    xmlns:xlink="http://www.w3.org/1999/xlink"
  >
    <image xlink:href="mdn-logo.png" width="200" height="200" />
    <image xlink:href="mdn-logo.png" x="200" width="200" height="200" />
  </svg>
"""
Resvg.svg_string_to_png_buffer(svg_string, resources_dir: path)

Moreover, I found that resvg provided results that closely matched those from the browser. This aspect was particularly important to me as I heavily rely on the browser to create the svg templates and making adjustments.

MRdotB

MRdotB

The :rustler_precompiled nif does not work on windows but the self compiled work. I’m new to rustler and friends. I will try to fix it asap.

Last Post!

lud

lud

Hey, sorry I forgot to update my comment, I indeed added an emoji font and it is automatically picked up!

Thank you :slight_smile:

Where Next?

Popular in Announcing Top

Crowdhailer
Experimenting with this code. OK.try do user &lt;- fetch_user(1) cart &lt;- fetch_cart(1) order = checkout(cart, user) save_orde...
New
versilov
Could not wait for the missing Elixir ML libraries to appear, so, I wrote one myself, taking https://github.com/sdwolfz/exlearn as a foun...
New
mspanc
I am pleased to announce an initial release of the Membrane Framework - an Elixir-based framework with special focus on processing multim...
New
mbuhot
Leverage Open Api 3.0 (Swagger) to document, test, validate and explore your Plug and Phoenix APIs. Generate and serve a JSON Open API ...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
dominicletz
Hi, I thought I had posted my library before but seems I hadn’t. The project is still in early stages but it’s growing and so I think it...
New
zachdaniel
Ash Framework What is Ash? Ash Framework is a declarative, resource-oriented application development framework for Elixir. A resource can...
New

Other popular topics Top

nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54921 245
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

We're in Beta

About us Mission Statement