Create static png from svg without Anti-aliasing, with or without canvas

1k views Asked by At

What I want

I want to take a vector SVG image and create a raster png from it without Anti-aliasing. The svg will be dynamically generated based on user input (text, bold, font-family). png is preferred, but other raster formats can be accepted.

What I am trying

var svg = '<svg><g><text>Hello World</text></g></svg>';
var img = document.createElement('img');
img.setAttribute('src','data:image/svg+xml;base64,' + btoa(svg_static_data) );
img.onload = function() {
    ctx.drawImage(img, 0, 0);
    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.msImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;
    static_image = canvas.toDataURL('image/png');
};

The svg here is very simple simply for demonstration. Here, I turn the svg into a canvas element, and turn the canvas element into an image. When that resulted in Anti-aliasing, the only configuration I found that might help was imageSmoothingEnabled, however I am still getting Anti-aliasing, likely because that configuration is for elements drawn with canvas itself. I have also tried placing that configuration above drawImage, but no luck.

What I need

A function to turn a dynamic non-animated SVG, that may contain many elements and attributes, including curved text, into a raster image that is at least mostly identical.

3

There are 3 answers

0
AudioBubble On BEST ANSWER

imageSmoothingEnabled do only apply to images, but only when the image source is drawn scaled.

However, the problem in this case is that the SVG image is anti-aliased internally when rasterized before your onload handler kicks in, so when you draw it to canvas it is already anti-aliased - there is nothing you can do to turn this off except by manually parsing and rendering the SVG (which is not a small project).

0
Rob Gibbons On

I believe this question, while slightly different, explains why you can't use the drawImage method on SVGs. Hope you find it helpful: Is there an equivalent of canvas's toDataURL method for SVG?

0
Sphinxxx On

Using a clever filter technique on the alpha channel (found here), you can "un-alias" all elements in your SVG before rendering it to the canvas. Just insert this at the top of the <svg> element:

<defs>
    <filter id="crispify">
        <feComponentTransfer>
            <feFuncA type="discrete" tableValues="0 1"/>
        </feComponentTransfer>
    </filter>
</defs>
<style>
    svg * {
        filter: url('#crispify');
    }
</style>

JSFiddle: https://jsfiddle.net/uqfgs477/1

Works in Chrome and Edge, not in Firefox.