提问人:Zain 提问时间:10/20/2010 最后编辑:PhrogzZain 更新时间:10/24/2023 访问量:469931
在浏览器中将SVG转换为图像(JPEG,PNG等)
Convert SVG to image (JPEG, PNG, etc.) in the browser
答:
以下是通过 JavaScript 执行此操作的方法:
- 使用 canvg JavaScript 库使用 Canvas 渲染 SVG 图像:https://github.com/gabelerner/canvg
- 根据以下说明从 Canvas 捕获编码为 JPG(或 PNG)的数据 URI: 将 HTML Canvas 捕获为 gif/jpg/png/pdf?
评论
toImage
() 和 download()
以获取自动下载的图像。
jbeard4 解决方案运行良好。
我正在使用 Raphael SketchPad 创建 SVG。链接到步骤 1 中的文件。
对于“保存”按钮(svg 的 id 是“editor”,canvas 的 id 是“canvas”):
$("#editor_save").click(function() {
// the canvg call that takes the svg xml and converts it to a canvas
canvg('canvas', $("#editor").html());
// the canvas calls to output a png
var canvas = document.getElementById("canvas");
var img = canvas.toDataURL("image/png");
// do what you want with the base64, write to screen, post to server, etc...
});
评论
<svg>...</svg
canvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
$(selector).html()
html()
svg
$(svg_elem)[0].outerHTML
这似乎适用于大多数浏览器:
function copyStylesInline(destinationNode, sourceNode) {
var containerElements = ["svg","g"];
for (var cd = 0; cd < destinationNode.childNodes.length; cd++) {
var child = destinationNode.childNodes[cd];
if (containerElements.indexOf(child.tagName) != -1) {
copyStylesInline(child, sourceNode.childNodes[cd]);
continue;
}
var style = sourceNode.childNodes[cd].currentStyle || window.getComputedStyle(sourceNode.childNodes[cd]);
if (style == "undefined" || style == null) continue;
for (var st = 0; st < style.length; st++){
child.style.setProperty(style[st], style.getPropertyValue(style[st]));
}
}
}
function triggerDownload (imgURI, fileName) {
var evt = new MouseEvent("click", {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement("a");
a.setAttribute("download", fileName);
a.setAttribute("href", imgURI);
a.setAttribute("target", '_blank');
a.dispatchEvent(evt);
}
function downloadSvg(svg, fileName) {
var copy = svg.cloneNode(true);
copyStylesInline(copy, svg);
var canvas = document.createElement("canvas");
var bbox = svg.getBBox();
canvas.width = bbox.width;
canvas.height = bbox.height;
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, bbox.width, bbox.height);
var data = (new XMLSerializer()).serializeToString(copy);
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svgBlob);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob)
{
var blob = canvas.msToBlob();
navigator.msSaveOrOpenBlob(blob, fileName);
}
else {
var imgURI = canvas
.toDataURL("image/png")
.replace("image/png", "image/octet-stream");
triggerDownload(imgURI, fileName);
}
document.removeChild(canvas);
};
img.src = url;
}
评论
.msToBlob()
更改以匹配您的元素svg
function svg2img(){
var svg = document.querySelector('svg');
var xml = new XMLSerializer().serializeToString(svg);
var svg64 = btoa(xml); //for utf8: btoa(unescape(encodeURIComponent(xml)))
var b64start = 'data:image/svg+xml;base64,';
var image64 = b64start + svg64;
return image64;
};svg2img()
评论
Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
我最近发现了几个用于 JavaScript 的图像跟踪库,它们确实能够构建可接受的位图近似值,包括大小和质量。我正在开发这个 JavaScript 库和 CLI:
https://www.npmjs.com/package/svg-png-converter
它为所有这些提供了统一的 API,支持浏览器和节点,不依赖于 DOM,以及命令行工具。
对于转换徽标/卡通/类似图像,它做得很好。对于照片/真实感,需要进行一些调整,因为输出大小可能会增长很多。
它有一个游乐场,尽管现在我正在研究一个更好的游乐场,更易于使用,因为添加了更多功能:
https://cancerberosgx.github.io/demos/svg-png-converter/playground/#
我的用例是从网络加载 svg 数据,这个 ES6 类完成了这项工作。
class SvgToPngConverter {
constructor() {
this._init = this._init.bind(this);
this._cleanUp = this._cleanUp.bind(this);
this.convertFromInput = this.convertFromInput.bind(this);
}
_init() {
this.canvas = document.createElement("canvas");
this.imgPreview = document.createElement("img");
this.imgPreview.style = "position: absolute; top: -9999px";
document.body.appendChild(this.imgPreview);
this.canvasCtx = this.canvas.getContext("2d");
}
_cleanUp() {
document.body.removeChild(this.imgPreview);
}
convertFromInput(input, callback) {
this._init();
let _this = this;
this.imgPreview.onload = function() {
const img = new Image();
_this.canvas.width = _this.imgPreview.clientWidth;
_this.canvas.height = _this.imgPreview.clientHeight;
img.crossOrigin = "anonymous";
img.src = _this.imgPreview.src;
img.onload = function() {
_this.canvasCtx.drawImage(img, 0, 0);
let imgData = _this.canvas.toDataURL("image/png");
if(typeof callback == "function"){
callback(imgData)
}
_this._cleanUp();
};
};
this.imgPreview.src = input;
}
}
以下是您如何使用它
let input = "https://restcountries.eu/data/afg.svg"
new SvgToPngConverter().convertFromInput(input, function(imgData){
// You now have your png data in base64 (imgData).
// Do what ever you wish with it here.
});
如果你想要一个普通的 JavaScript 版本,你可以前往 Babel 网站并在那里转译代码。
将SVG转换为blob URL和将blob URL转换为png图像的解决方案
const svg=`<svg version="1.1" baseProfile="full" width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<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(svg, callback) {
const url = getSvgUrl(svg);
svgUrlToPng(url, (imgData) => {
callback(imgData);
URL.revokeObjectURL(url);
});
}
function getSvgUrl(svg) {
return URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
}
function svgUrlToPng(svgUrl, callback) {
const svgImage = document.createElement('img');
// imgPreview.style.position = 'absolute';
// imgPreview.style.top = '-9999px';
document.body.appendChild(svgImage);
svgImage.onload = function () {
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);
// document.body.removeChild(imgPreview);
};
svgImage.src = svgUrl;
}
评论
URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }))
'data:image/svg+xml;utf-8,${svg.replace(/#/g, '%23').replace(/\n/g, '%0A')}';
'data:image/svg+xml;base64,${btoa(drawing)}';
Svg
可以根据条件进行转换:png
- 如果格式为 SVG(字符串)路径:
svg
- 创建画布
- 创建并设置为参数
new Path2D()
svg
- 在画布上绘制路径
- 创建映像并用作 .
canvas.toDataURL()
src
例:
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let svgText = 'M10 10 h 80 v 80 h -80 Z';
let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.stroke(p);
let url = canvas.toDataURL();
const img = new Image();
img.src = url;
请注意,在 Edge 中不受支持,在 Edge 中部分受支持。Polyfill 解决了以下问题: https://github.com/nilzona/path2d-polyfillPath2D
ie
- 使用以下命令创建 blob 并在画布上绘制:
svg
.drawImage()
- make canvas 元素
- 从 svg xml 创建一个 svgBlob 对象
- 从 domUrl.createObjectURL(svgBlob) 创建一个 url 对象;
- 创建一个 Image 对象并将 url 分配给图像 src
- 将图像绘制到画布中
- 从 canvas 获取 png 数据字符串: canvas.toDataURL();
请注意,在 ie,您将在 canvas.toDataURL() 阶段获得异常;这是因为IE的安全限制太高,在画布上绘制图像后将画布视为只读。所有其他浏览器仅在图像是跨源时才限制。
- 使用 JavaScript 库。它是独立的库,但具有有用的功能。
canvg
喜欢:
ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();
评论
这里有一个函数,它没有库,并返回一个 Promise:
/**
* converts a base64 encoded data url SVG image to a PNG image
* @param originalBase64 data url of svg image
* @param width target width in pixel of PNG image
* @return {Promise<String>} resolves to png data url of the image
*/
function base64SvgToBase64Png (originalBase64, width) {
return new Promise(resolve => {
let img = document.createElement('img');
img.onload = function () {
document.body.appendChild(img);
let canvas = document.createElement("canvas");
let ratio = (img.clientWidth / img.clientHeight) || 1;
document.body.removeChild(img);
canvas.width = width;
canvas.height = width / ratio;
let ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
try {
let data = canvas.toDataURL('image/png');
resolve(data);
} catch (e) {
resolve(null);
}
};
img.onerror = function() {
resolve(null);
};
img.src = originalBase64;
});
}
在Firefox上,没有设置宽度/高度的SVG存在问题。
请参阅此工作示例,其中包括对Firefox问题的修复。
评论
有几种方法可以使用 Canvg 库将 SVG 转换为 PNG。
就我而言,我需要从内联 SVG 获取 PNG blob。
库文档提供了一个示例(请参阅 OffscreenCanvas 示例)。
但是这种方法目前在Firefox中不起作用。是的,您可以在设置中启用 gfx.offscreencanvas.enabled 选项。但是网站上的每个用户都会这样做吗?:)
但是,还有另一种方法也可以在Firefox中使用。
const el = document.getElementById("some-svg"); //this is our inline SVG
var canvas = document.createElement('canvas'); //create a canvas for the SVG render
canvas.width = el.clientWidth; //set canvas sizes
canvas.height = el.clientHeight;
const svg = new XMLSerializer().serializeToString(el); //convert SVG to string
//render SVG inside canvas
const ctx = canvas.getContext('2d');
const v = await Canvg.fromString(ctx, svg);
await v.render();
let canvasBlob = await new Promise(resolve => canvas.toBlob(resolve));
最后一行感谢这个答案
这是我的 2 美分。不知何故,锚标记在代码片段中未按预期工作,但是它在 中工作正常。Download
Chrome
这是工作 jsFiddle
const waitForImage = imgElem => new Promise(resolve => imgElem.complete ? resolve() : imgElem.onload = imgElem.onerror = resolve);
const svgToImgDownload = ext => {
if (!['png', 'jpg', 'webp'].includes(ext))
return;
const _svg = document.querySelector("#svg_container").querySelector('svg');
const xmlSerializer = new XMLSerializer();
let _svgStr = xmlSerializer.serializeToString(_svg);
const img = document.createElement('img');
img.src = 'data:image/svg+xml;base64,' + window.btoa(_svgStr);
waitForImage(img)
.then(_ => {
const canvas = document.createElement('canvas');
canvas.width = _svg.clientWidth;
canvas.height = _svg.clientHeight;
canvas.getContext('2d').drawImage(img, 0, 0, _svg.clientWidth, _svg.clientHeight);
return canvas.toDataURL('image/' + (ext == 'jpg' ? 'jpeg' : ext), 1.0);
})
.then(dataURL => {
console.log(dataURL);
document.querySelector("#img_download_btn").innerHTML = `<a href="${dataURL}" download="img.${ext}">Download</a>`;
})
.catch(console.error);
};
document.querySelector('#map2Png').addEventListener('click', _ => svgToImgDownload('png'));
document.querySelector('#map2Jpg').addEventListener('click', _ => svgToImgDownload('jpg'));
document.querySelector('#map2Webp').addEventListener('click', _ => svgToImgDownload('webp'));
<div id="svg_container" style="float: left; width: 50%">
<svg width="200" height="200" viewBox="-100 -100 200 200">
<circle cx="0" cy="20" r="70" fill="#D1495B" />
<circle cx="0" cy="-75" r="12" fill="none" stroke="#F79257" stroke-width="2" />
<rect x="-17.5" y="-65" width="35" height="20" fill="#F79257" />
</svg>
</div>
<div>
<button id="map2Png">PNG</button>
<button id="map2Jpg">JPG</button>
<button id="map2Webp">WEBP</button>
</div>
<div id="img_download_btn"></div>
评论
if (!['jpg'].includes(ext)) return
如果有人使用 jpeg,则永远不会到达,猜你的意思是ext == 'jpg' ? 'jpeg'
['png','jpg','jpeg','webp']
- 从 SVG 获取数据 URI:
data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElem))}
- 准备镜像
- 创建一个画布,并使用 toDataURL 导出。
例
<!-- test data-->
<svg width="400" height="400"><g transform="translate(23.915343915343925,-80.03971756398937)" class="glyph" stroke="#000000" fill="#a0a0a0"><path d="M74.97 108.70L74.97 108.70L100.08 110.77Q93.89 147.91 87.35 179.89L87.35 179.89L148.23 179.89L148.23 194.34Q143.76 277.91 113.84 339.81L113.84 339.81Q144.44 363.54 163.70 382.46L163.70 382.46L146.51 402.75Q128.62 384.18 101.80 361.83L101.80 361.83Q75.32 405.85 34.39 436.80L34.39 436.80L17.20 415.82Q57.43 386.93 82.20 345.66L82.20 345.66Q57.78 326.40 27.86 304.39L27.86 304.39Q44.37 257.96 56.75 203.97L56.75 203.97L19.26 203.97L19.26 179.89L61.90 179.89Q69.47 145.16 74.97 108.70ZM93.20 323.99L93.20 323.99Q118.65 272.06 123.12 203.97L123.12 203.97L82.20 203.97Q69.47 260.03 55.71 297.17L55.71 297.17Q76.01 311.61 93.20 323.99ZM160.26 285.13L160.26 260.37L239.71 260.37L239.71 216.01Q268.25 191.24 294.05 155.48L294.05 155.48L170.58 155.48L170.58 130.71L322.94 130.71L322.94 155.48Q297.49 191.93 265.50 223.92L265.50 223.92L265.50 260.37L337.38 260.37L337.38 285.13L265.50 285.13L265.50 397.59Q265.50 431.64 237.65 431.64L237.65 431.64L187.09 431.64L180.21 407.57Q202.22 407.91 227.67 407.91L227.67 407.91Q239.71 407.91 239.71 390.03L239.71 390.03L239.71 285.13L160.26 285.13Z"></path></g></svg>
<button title="download">svg2png</button>
<script>
const output = {"name": "result.png", "width": 64, "height": 64}
document.querySelector("button").onclick = () => {
const svgElem = document.querySelector("svg")
// const uriData = `data:image/svg+xml;base64,${btoa(svgElem.outerHTML)}` // it may fail.
const uriData = `data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElem))}`
const img = new Image()
img.src = uriData
img.onload = () => {
const canvas = document.createElement("canvas");
[canvas.width, canvas.height] = [output.width, output.height]
const ctx = canvas.getContext("2d")
ctx.drawImage(img, 0, 0, output.width, output.height)
// 👇 download
const a = document.createElement("a")
const quality = 1.0 // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
a.href = canvas.toDataURL("image/png", quality)
a.download = output.name
a.append(canvas)
a.click()
a.remove()
}
}
</script>
这是一个老问题,在 2022 年我们有 ES6,我们不需要第三方库。
这是将图像转换为其他格式的一种非常基本的方法。svg
诀窍是将元素加载为元素,然后使用 canvas 元素将图像转换为所需的格式。因此,需要四个步骤:svg
img
- 提取为数据字符串。
svg
xml
- 将数据字符串加载到元素中
xml
img
- 使用元素将元素转换为
img
dataURL
canvas
- 将转换后的元素加载到新元素中
dataURL
img
第 1 步
提取一个作为数据字符串很简单,我们不需要将其转换为 base64 字符串。我们只是将其序列化为 XML,然后将字符串编码为 URI:svg
xml
// Data header for a svg image:
const dataHeader = 'data:image/svg+xml;charset=utf-8'
// Serialize it as xml string:
const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e)
// Encode URI data as UTF8 data:
const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}`
// Select the element:
const $svg = document.getElementById('svg-container').querySelector('svg')
// Encode it as a data string:
const svgData = encodeAsUTF8(serializeAsXML($svg))
注意:
如果需要 base64 数据,可以使用此选项:
...
// Encode URI data as base64 data:
const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}`
...
// Encode it as a data string:
const svgData = encodeAsB64(serializeAsXML($svg))
步骤 2
将数据字符串加载到元素中:xml
img
// This function returns a Promise whenever the $img is loaded
const loadImage = async url => {
const $img = document.createElement('img')
$img.src = url
return new Promise((resolve, reject) => {
$img.onload = () => resolve($img)
$img.onerror = reject
$img.src = url
})
}
步骤 3
使用元素将元素转换为:img
dataURL
canvas
const $canvas = document.createElement('canvas')
$canvas.width = $svg.clientWidth
$canvas.height = $svg.clientHeight
$canvas.getContext('2d').drawImage(img, 0, 0, $svg.clientWidth, $svg.clientHeight)
return $canvas.toDataURL(`image/${format}`, 1.0)
步骤 4
将转换后的元素加载到新元素中:dataURL
img
const $img = document.createElement('img')
$img.src = dataURL
$holder.appendChild($img)
这里有一个工作片段:
const dataHeader = 'data:image/svg+xml;charset=utf-8'
const $svg = document.getElementById('svg-container').querySelector('svg')
const $holder = document.getElementById('img-container')
const $label = document.getElementById('img-format')
const destroyChildren = $element => {
while ($element.firstChild) {
const $lastChild = $element.lastChild ?? false
if ($lastChild) $element.removeChild($lastChild)
}
}
const loadImage = async url => {
const $img = document.createElement('img')
$img.src = url
return new Promise((resolve, reject) => {
$img.onload = () => resolve($img)
$img.onerror = reject
})
}
const serializeAsXML = $e => (new XMLSerializer()).serializeToString($e)
const encodeAsUTF8 = s => `${dataHeader},${encodeURIComponent(s)}`
const encodeAsB64 = s => `${dataHeader};base64,${btoa(s)}`
const convertSVGtoImg = async e => {
const $btn = e.target
const format = $btn.dataset.format ?? 'png'
$label.textContent = format
destroyChildren($holder)
const svgData = encodeAsUTF8(serializeAsXML($svg))
const img = await loadImage(svgData)
const $canvas = document.createElement('canvas')
$canvas.width = $svg.clientWidth
$canvas.height = $svg.clientHeight
$canvas.getContext('2d').drawImage(img, 0, 0, $svg.clientWidth, $svg.clientHeight)
const dataURL = await $canvas.toDataURL(`image/${format}`, 1.0)
console.log(dataURL)
const $img = document.createElement('img')
$img.src = dataURL
$holder.appendChild($img)
}
const buttons = [...document.querySelectorAll('[data-format]')]
for (const $btn of buttons) {
$btn.onclick = convertSVGtoImg
}
.wrapper {
display: flex;
flex-flow: row nowrap;
width: 100vw;
}
.images {
display: flex;
flex-flow: row nowrap;
width: 70%;
}
.image {
width: 50%;
display: flex;
flex-flow: row wrap;
justify-content: center;
}
.label {
width: 100%;
text-align: center;
}
<div class="wrapper">
<div class="item images">
<div class="image left">
<div class="label">svg</div>
<div id="svg-container">
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="200" height="200" viewBox="0 0 248 204">
<path fill="#1d9bf0" d="M221.95 51.29c.15 2.17.15 4.34.15 6.53 0 66.73-50.8 143.69-143.69 143.69v-.04c-27.44.04-54.31-7.82-77.41-22.64 3.99.48 8 .72 12.02.73 22.74.02 44.83-7.61 62.72-21.66-21.61-.41-40.56-14.5-47.18-35.07 7.57 1.46 15.37 1.16 22.8-.87-23.56-4.76-40.51-25.46-40.51-49.5v-.64c7.02 3.91 14.88 6.08 22.92 6.32C11.58 63.31 4.74 33.79 18.14 10.71c25.64 31.55 63.47 50.73 104.08 52.76-4.07-17.54 1.49-35.92 14.61-48.25 20.34-19.12 52.33-18.14 71.45 2.19 11.31-2.23 22.15-6.38 32.07-12.26-3.77 11.69-11.66 21.62-22.2 27.93 10.01-1.18 19.79-3.86 29-7.95-6.78 10.16-15.32 19.01-25.2 26.16z"/>
</svg>
</div>
</div>
<div class="image right">
<div id="img-format" class="label"></div>
<div id="img-container"></div>
</div>
</div>
<div class="item buttons">
<button id="btn-png" data-format="png">PNG</button>
<button id="btn-jpg" data-format="jpeg">JPG</button>
<button id="btn-webp" data-format="webp">WEBP</button>
</div>
</div>
评论
img.src
step 2
data:image/svg+xml
format
step 2
如果目标是通过浏览器将 SVG 文件转换为 PNG 图像文件,也许以下网站可以为那些需要它的人提供帮助:
https://mybyways.com/blog/convert-svg-to-png-using-your-browser
在此部分中输入 SVG 代码,然后单击“加载 SVG”按钮
将出现 SVG 图像的预览,可以通过按将 SVG 另存为 PNG 按钮下载或保存为 PNG 图像文件。
评论