How to Convert an SVG to an Image in the Browser?

在使用 selenium 取得網頁內容裡的圖片時,遇到圖片不是 bitmap, 而是 svg 時會出錯。

javascript error: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)

服用下面的 sample, 在執行 svgToPng() 之後, 即可在 body append png image:

const svg = `
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" width="300" height="200">
   <rect width="100%" height="100%" fill="red" />
   <circle cx="150" cy="100" r="80" fill="green" />
   <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>
`;

svgToPng(svg, (imgData) => {
  const pngImage = document.createElement('img');
  document.body.appendChild(pngImage);
  pngImage.src = imgData;
});

function svgToPng(svgData, callback) {
  const svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
  const objectUrl = URL.createObjectURL(svgBlob);
  svgUrlToPng(objectUrl, (imgData) => {
    callback(imgData);
    URL.revokeObjectURL(objectUrl);
  });
}

function svgUrlToPng(svgUrl, callback) {
  const svgImage = document.createElement('img');
  document.body.appendChild(svgImage);
  svgImage.onload = () => {
    const canvas = document.createElement('canvas');
    canvas.width = svgImage.clientWidth;
    canvas.height = svgImage.clientHeight;
    const canvasCtx = canvas.getContext('2d');
    canvasCtx.drawImage(svgImage, 0, 0);
    const imgData = canvas.toDataURL('image/png');
    callback(imgData);
  };
  svgImage.src = svgUrl;
}

範例2, 從一個 svg 的 node(tag), 匯出 png 檔.

function data_visualization_download_png(target_div, filename)
{
	const svgNode = document.getElementById(target_div);
	svgToPng(svgNode, (canvasUrl) => {
		const downloadLink = document.createElement("a");
		downloadLink.href = canvasUrl;
		downloadLink.download = filename;
		document.body.appendChild(downloadLink);
		downloadLink.click();
		document.body.removeChild(downloadLink);
	});
}

function svgToPng(svgNode, callback) {
	const doctype = '<?xml version="1.0" standalone="no"?>'
  	+ '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">';
	// serialize our SVG XML to a string.
	const xml_source = (new XMLSerializer()).serializeToString(svgNode);
	// create a file blob of our SVG.
	const svgBlob = new Blob([ doctype + xml_source], { type: 'image/svg+xml;charset=utf-8' });
	const objectUrl = URL.createObjectURL(svgBlob);
	svgUrlToPng(objectUrl, (imgData) => {
		callback(imgData);
		URL.revokeObjectURL(objectUrl);
	});
}

function svgUrlToPng(svgUrl, callback) {
	const svgImage = document.createElement('img');
	document.body.appendChild(svgImage);
	svgImage.onload = () => {
		const canvas = document.createElement('canvas');
		canvas.width = svgImage.clientWidth;
		canvas.height = svgImage.clientHeight;
		const canvasCtx = canvas.getContext('2d');
		canvasCtx.drawImage(svgImage, 0, 0);
		const canvasUrl = canvas.toDataURL('image/png');
		callback(canvasUrl);
		document.body.removeChild(svgImage);
	};
	svgImage.src = svgUrl;
}

相關網頁

CanvasRenderingContext2D.drawImage()
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage

在前端使用 JavaScript 操作 Canvas 來合併 SVG(Scalable Vector Graphics)圖片
https://dotblogs.com.tw/supershowwei/2022/08/15/use-javascript-to-merge-svg-images-in-canvas

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *