sharp
sharp copied to clipboard
SVG conversion to PNG ignores <style> variables
Possible bug
SVG conversion to PNG ignores
This issue limits compatibility with several of the assets I am using, and with 100% that I generate.
Maybe... this could be because of libvips, which uses librsvg. Acccording to this post, they still do not support style variables: https://gitlab.gnome.org/GNOME/librsvg/-/issues/459
Even if the issue is because of a dependent package, it is important to track it until it is supported and be transparent to developers that use style variables.
Are you using the latest version of sharp?
- [x] I am using the latest version of
sharp
as reported bynpm view sharp dist-tags.latest
.
What is the output of running npx envinfo --binaries --system --npmPackages=sharp --npmGlobalPackages=sharp
?
System:
OS: macOS 11.7
CPU: (4) x64 Intel(R) Core(TM) i5-7500 CPU @ 3.40GHz
Memory: 6.26 GB / 32.00 GB
Shell: 5.8 - /bin/zsh
Binaries:
Node: 16.14.0 - /usr/local/bin/node
npm: 8.15.1 - /usr/local/bin/npm
npmPackages:
sharp: ^0.31.2 => 0.31.2
What are the steps to reproduce?
- Convert the attached sample SVG to PNG
What is the expected behaviour?
- Output should have a blue background, as defined in the --Bg variable, but the background is black.
Please provide a minimal, standalone code sample, without other dependencies, that demonstrates this problem
This is a nextjs api endpoint:
const sharp = require('sharp');
const sharpOptions = {
compressionLevel: 0,
quality: 100,
}
export default async function handler(request, response) {
const svg = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="600" height="600" viewBox="0 0 20 20"><defs><style>:root{--Bg:#0000FF;}.Bg{fill:var(--Bg);}.Rect{fill:#00ff00;}</style></defs><g><rect class="Bg" x="0" y="0" width="20" height="20"/><rect class="Rect" x="5" y="5" width="10" height="10"/></g></svg>';
const svgBuffer = Buffer.from(svg);
const png = sharp(svgBuffer).png(sharpOptions);
const pngData = await png.toBuffer();
response.statusCode = 200;
response.setHeader('Content-Type', 'image/png');
response.setHeader('Cache-Control', 'public, max-age=0, must-revalidate');
response.end(pngData);
}
Please provide sample image(s) that help explain this problem
As a fallback, I'm converting all variables to their actual value. My simple assets use color codes only, so other cases may need a more refined approach.
// match all: --varName:#ff00ff;
const regexp = /(--)[a-zA-Z]+:#[a-fA-F0-9]+;/g;
const vars = [..._svg.matchAll(regexp)];
for (const v of vars) {
const parts = v[0].split(':');
const name = parts[0]; // --varName
const value = parts[1].split(';')[0]; // #ff00ff
svg = svg.replaceAll(`var(${name})`, value);
}
Yes, please subscribe to https://gitlab.gnome.org/GNOME/librsvg/-/issues/459 for updates.