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:
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.
Something which is useful for complex drawings is to be able to determine the dimensions of text boxes. Resvg can be used to query the dimensions of SVG elements (in particular text elements). Maybe might be interesting to expose the query functionality? I won’t be usint that for my own projects as ExTypst fits my bill better, but it’s something to think about.
Cool library and great to see some bindings for the current go-to SVG renderer.
I’m curious about what issues you had with libvips (I maintain image which is ultimately built on libvips). I’ve not had any special issues with SVG rendering (although it currently binds with libsvg with plans to move to resvg).
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:
Windows Support: One of my primary requirements was compatibility with Windows. Unfortunately, as of the time of development, vix did not support it.
Font Loading with librsvg: I was unable to successfully get libvips to load my specific font.
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:
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, Thanks very much for the thoughtful response, really appreciate it. I agree with all three of your challenges with libsvg (under libvips) although I would like to try and debug a little further the font loading issues you had. Are you able to share your .ttf file for the font that wouldn’t load?
On the image loading part, typically Image would encourage composing images to achieve the result, but given your templating approach I can see why you want everything to be in an <svg> tag.
Also great to see more bindings for some good Rust libs too.
Amazing thank you @MRdotB!
The Livebook example needed {:resvg, "~> 0.3"}, to succeed and it got the NIF like charm! Congrats, I’m imagining Windows is not a top priority for the majority of image processors, but you managed to figure it out! Thank you!