I'm trying to convert a bunch of siblings SVG images to base64 PNG strings, using just the browser and plain Javascript, but for some reason beyond my knowledge I get the base64 PNG string of only the last SVG. Here is the HTML snippet:
<html>
<head><title>Browser SVG to PNG Converter</title></head>
<body bgcolor="#DDDDEE">
<h1>Browser SVG to PNG Converter</h1>
<div id="div_svg">
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,235,235);" />
<rect x="30" y="15" width="90" height="120" style="stroke:#000000;stroke-width:1;fill:none;" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,200,35);" />
<rect x="30" y="30" width="70" height="90" style="stroke:#000000;stroke-width:2;fill:none;" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,235,235);" />
<rect x="30" y="15" width="90" height="120" style="stroke:#000000;stroke-width:3;fill:none;" /> </svg>
</div>
<br />
<button id="btn_convert">Convert SVG to PNG and display it below</button>
<br />
<br />
<canvas id="aux_canvas" style="display:none;"></canvas>
<textarea id="output_png" style="width:90vw;height:40vh;display:block;">base64 PNG source will be displayed here:</textarea>
<script>
document.getElementById('btn_convert').addEventListener('click', function() {
var svg_all = document.getElementById('div_svg').querySelectorAll('svg');
var canvas = document.getElementById('aux_canvas');
var win = window.URL || window.webkitURL || window;
var img = new Image();
img.addEventListener("load", function() {
canvas.getContext('2d').drawImage(img, 0, 0);
win.revokeObjectURL(url);
document.getElementById('output_png').value += "\n\n" + canvas.toDataURL("image/png");
});
for(let i = 0; i < svg_all.length; i++) {
let svg = svg_all[i];
canvas.width = svg.getBoundingClientRect().width;
canvas.height = svg.getBoundingClientRect().height;
var data = new XMLSerializer().serializeToString(svg);
var blob = new Blob([data], {
type: 'image/svg+xml'
});
var url = win.createObjectURL(blob);
document.getElementById('output_png').value += "\nGoing to load image..."
img.src = url;
document.getElementById('output_png').value += "\nEnded loading image..."
}
});
</script>
</body>
</html>
Input as hardcoded SVG and output to textarea
are only for testing purposes, my ultimate goal is a Javascript function getting an array of SVG sources and returning the corresponding PNG images as an array of base64 strings.
Image loading is asynchronous, you have to wait for each image to load before moving to the next, use Promise with async
and await
before each loading.
Here is a working example
const svgString = `
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,235,235);" />
<rect x="30" y="15" width="90" height="120" style="stroke:#000000;stroke-width:1;fill:none;" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="130" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,200,35);" />
<rect x="30" y="30" width="70" height="90" style="stroke:#000000;stroke-width:2;fill:none;" /> </svg>
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="150">
<rect width="100%" height="100%" style="stroke-width:0;fill:rgb(35,235,235);" />
<rect x="30" y="15" width="90" height="120" style="stroke:#000000;stroke-width:3;fill:none;" /> </svg>`;
const div = document.createElement("div");
div.innerHTML = svgString;
const svgs = div.querySelectorAll("svg");
const convertButton = document.querySelector("#btn_convert");
const output = document.querySelector("#output_png");
const img = document.createElement("img");
const canvas = document.createElement("canvas");
const ctx = canvas.getContext('2d');
const URL = window.URL || window.webkitURL || window;
convertButton.onclick = async () => {
for(let i = 0; i < svgs.length; i++) {
output.value += "\n---- Loading image... \n\n";
output.value += await svgToBase64(svgs[i]);
output.value += "\n---- Image Loaded ... \n\n";
}
};
async function svgToBase64(svg) {
const width = svg.getAttribute("width");
const height = svg.getAttribute("height");
canvas.width = width;
canvas.height = height;
const data = new XMLSerializer().serializeToString(svg);
console.log(data)
const blob = new Blob([data], {
type: 'image/svg+xml'
});
console.log(blob)
var url = URL.createObjectURL(blob);
return new Promise((resolve) => {
img.onload = () => {
ctx.drawImage(img, 0, 0);
URL.revokeObjectURL(url);
resolve(canvas.toDataURL("image/png"));
}
img.src = url;
});
}
body {
background: #DDDDEE;
}
<h1>Browser SVG to PNG Converter</h1>
<br />
<button id="btn_convert">Convert SVG to PNG and display it below</button>
<br />
<br />
<textarea id="output_png" style="width:90vw;height:40vh;display:block;">base64 PNG source will be displayed here:</textarea>