Open kayahr opened 4 years ago
Alternative solution without using resvg-js.
The following code has two advantages:
It fixes rendering issues in firefox (html canvas) and also it solves the pixelated issue that occurs using librsvg (which is used in node-canvas to render svgs). Important is that the width and height are the final size of your image on the canvas.
/**
* Returns SVG data with width and height in the root element.
* Don't change anything inside this method without intense performance testing.
*/
private static addSizeToRootSvgElement(svgData: string, width: number, height: number): string {
return svgData.replace(`<svg `, `<svg width="${width}" height="${height}" `);
}
By the way librsvg has many different issues with rendering svgs like some elements not being rendered at all. A way to work around those issues it to have a an up to date librsvg (version 2.54.4 solved all the issues I had). To get this version of librsvg you can check here the version delivered by your OS https://repology.org/project/librsvg/versions, so chose the right OS, install canvas dependencies and the run npm i --build-from-source
to install canvas from source. (you might have to delete node_modules and or package-lock.json beforehand).
/** * Returns SVG data with width and height in the root element. * Don't change anything inside this method without intense performance testing. */ private static addSizeToRootSvgElement(svgData: string, width: number, height: number): string { return svgData.replace(`<svg `, `<svg width="${width}" height="${height}" `); }
From my testing, the above solution (when applied to node-canvas
) is basically the same as
const image = await loadImage(Buffer.from(logoSvg, 'utf-8'));
image.width = 100;
image.height = 100;
Same output, same rendering performance. The difference is just that the latter is a bit more straightforward.
Also I noticed that to reduce pixelation it's better to multiply the width/height values by a factor of 10 - then the output is more or less crisp. However the rendering performance degrades significantly.
Issue or Feature
node-canvas renders SVGs with small dimensions very pixelated while browsers (Tested with Chrome and Firefox) do not care about the SVG size and renders a high quality image. Maybe because node-canvas rasterizes the image on load (and when width/height properties are changed) while browsers rasterizes the image on draw when the actual output size is known?
This issue is related to https://github.com/Automattic/node-canvas/issues/957 and maybe also to https://github.com/Automattic/node-canvas/issues/1474.
Steps to Reproduce
test.svg
test.js
test.html
Open test.html in Chrome or Firefox and you get a high quality output:
Run
npm install canvas
to install node-canvas and then runnode test.js
. Result is written to test.png which looks like this:As a workaround uncomment the
image.width = image.height = 100
line in test.js. Then the output is ok. But calculating the needed image size manually is annoying, node-canvas should do this transparently like the browser canvas implementations.Your Environment