Convert SVG to image (JPEG, PNG, etc.) in the browser
Here is how you can do it through JavaScript:
- Use the canvg JavaScript library to render the SVG image using Canvas: https://github.com/gabelerner/canvg
- Capture a data URI encoded as a JPG (or PNG) from the Canvas, according to these instructions: Capture HTML Canvas as gif/jpg/png/pdf?
When converting an svg to png in the browser using canvas api, embedded image in svg is randomly blank in Safari
This is a known and old bug.
For a workaround, it seems that a simple setTimeout(draw, 100)
is enough, though that seems quite fragile to be honest (for instance 0
was working with my image but not with the font example in the bug report).
const ctx = document.querySelector("canvas").getContext("2d");
(async () => {
const png_blob = await fetch("https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png").then(r=>r.ok&&r.blob());
const png_dataURL = await readAsDataURL(png_blob);
const anti_cache = "#" + Math.random();
const svg_markup = `<svg xmlns="http://www.w3.org/2000/svg" width="300" height="150" viewBox="0 0 100 100">
<rect width="10" height="10" fill="purple"/>
<image href="${ png_dataURL + anti_cache }" width="100" height="100"/>
</svg>`;
const svg_blob = new Blob([svg_markup], { type: "image/svg+xml" });
const img = new Image();
img.src = URL.createObjectURL(svg_blob);
img.onload = (evt) => {
setTimeout(
() => ctx.drawImage(img, 0, 0),
100
);
};
})().catch(console.error);
function readAsDataURL(blob) {
const reader = new FileReader();
return new Promise((res, rej) => {
reader.onload = () => res(reader.result);
reader.onerror = rej;
try {
reader.readAsDataURL(blob);
}
catch(err) {
rej(err);
}
});
}
<canvas></canvas>
Convert a SVG to a PNG/JPEG without using canvas in a serverless function
The best way to deal with this that I have found so far is by using a headless chrome and getting a screenshot. As an example by using puppeteer
I could get a screenshot of the viewport like follows,
const browser = await puppeteer.launch();
const page = await browser.newPage();
let yourName = 'world'
const svg = `
<svg fill="none" viewBox="0 0 600 400" width="600" height="400" xmlns="http://www.w3.org/2000/svg">
<foreignObject width="100%" height="100%">
<div xmlns="http://www.w3.org/1999/xhtml">
<style>
.title {
font-size: 10vh;
font-weight: regular;
background-color: #ffddff;
}
</style>
<p class="title">Hello ${yourName}</p>
</div>
</foreignObject>
</svg>
`;
await page.setViewport({ width: 2048, height: 1170 });
await page.setContent(svg);
console.log(await page.content());
await page.screenshot({path: 'screenshot.png'});
await browser.close();
Then it will be easy to send the png
as the response.
In browser conversion of svg to png image (cross browser including IE)
IE9 seem to indeed support the canvas element as per https://msdn.microsoft.com/fr-fr/library/ff975241(v=vs.85).aspx
The following sample/test code for toDataURL works for me in IE11 : http://samples.msdn.microsoft.com/Workshop/samples/canvas/todataurl.html
The fiddle you gave does not work in IE11 ; looking at the console errors, it leads to the fact that you cannot call drawImage before the image has finished its rendering. IE Throws a
call to unsupported method or attributes of a method
Adding a setTimeout allow IE to render the dynamic image and bypass this error.
But it then leads to a
Security Error
because it seems that IE has tainted the canvas because of some "cross origin" issue
SecurityError
The img or video element is not of the same origin or domain
as the document that owns the canvas element. Versions earlier
than Internet Explorer 10 use SECURITY_ERR.
IE seems to be tainting all images filled with SVG for security reasons - SVG tained canvas IE security error toDataURL
I managed to have a working version using canvg
, which transforms an SVG file into canvas instructions - https://github.com/gabelerner/canvg
the solution boils down to
var svg = Highcharts.getSVG(charts);
var mycanvas = document.createElement('canvas');
canvg(mycanvas, svg)
console.log(mycanvas.toDataURL("image/png"))
check this fiddle http://jsfiddle.net/6bxqbaeb/1/ which works in IE11
Related Topics
How to Test For an Empty JavaScript Object
How to Insert an Item into an Array At a Specific Index (JavaScript)
Pass Correct "This" Context to Settimeout Callback
Remove Accents/Diacritics in a String in JavaScript
How to "Properly" Create a Custom Object in JavaScript
Passing Data to a Bootstrap Modal
How to Create an Array Containing 1...N
Convert String to Title Case With JavaScript
Difference Between Call and Apply
How to Get the Caret Column (Not Pixels) Position in a Textarea, in Characters, from the Start
How to Get the Current Date in JavaScript
Combination of Async Function + Await + Settimeout
Jquery .Live() VS .On() Method For Adding a Click Event After Loading Dynamic Html
Difference Between == and === in JavaScript
How to Completely Uninstall Node.Js, and Reinstall from Beginning (Mac Os X)