【问题标题】:How to convert multiple SVG's to one PNG image?如何将多个 SVG 转换为一个 PNG 图像?
【发布时间】:2020-12-22 02:36:34
【问题描述】:

我需要将 2 个单独的 SVG 转换为 1 个 PNG 图像。我目前有将 1 个 SVG 转换为 PNG 的代码。这段代码如下所示,我将SVG转画布转PNG。

SVG 位于同一页面上,我尝试使用数组遍历它们并抓取两者。我目前正在处理的代码也在下面,但不起作用。关于如何将 SVG 转换为相同的 PNG 图像的任何建议?

非常感谢!

单个 SVG 转 PNG

// convert svg to png 
function svgToPng(){
    var svg = document.querySelectorAll('svg')[0];
    // clone svg nodes
    var copy = svg.cloneNode(true);
    // convert to xml format for storage/transportation
    var serializer = new XMLSerializer();
    var data = serializer.serializeToString(copy);
    // create url 
    var DOMURL = window.URL || window.webkitURL || window; 
    // create image/blob 
    var img = new Image();
    var blob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
    var url = DOMURL.createObjectURL(blob);
    // create canvas 
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    // draw image on canvas
    img.onload = function(){
        ctx.drawImage(img, 0, 0, $(svg0).width(), $(svg0).height());
        DOMURL.revokeObjectURL(url, url1);
        var imgURI = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
    }
    // send new image to window
    img.src = url;
    // return img.src;
    window.open().document.write('<img src="' + img.src + '" width="1600" height="800"/>');
};

多个 SVG 转为 PNG

// convert multipl svgs to png
function multSvgToPng(){
    var array = [];
    var totalSvg = document.querySelectorAll('svg');  // NodeList(2) [svg, svg]
    // create array 
    for(var i = 0; i < totalSvg.length; i++){
        array = document.querySelectorAll('svg')[i];
    }
    for(var j = 0; j < array.length; j++){
        var svg = array[j]; 
        var copy = svg.cloneNode(true);
        var serializer = new XMLSerializer();
        var data = serializer.serializeToString(copy);
        var DOMURL = window.URL || window.webkitURL || window;
        var img = new Image();
        var blob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
        var url = DOMURL.createObjectURL(blob);
        var svgStr = serializer.serializeToString(copy);
    }
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    img.onload = function(){
        ctx.drawImage(img, 0, 0, $(svg).width(), $(svg).height());
        DOMURL.revokeObjectURL(url);
        var imgURI = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
    }
    // send new image to window
    img.src = url;
    // return img.src;
    window.open().document.write('<img src="' + img.src + '" width="1600" height="800"/>');
}

SVG 图像示例

<!DOCTYPE html>
<html>
<body>

<svg height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  Sorry, your browser does not support inline SVG.  
</svg> 
 
</body>
</html>

<!DOCTYPE html>
<html>
<body>

<svg width="400" height="110">
  <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
  Sorry, your browser does not support inline SVG.  
</svg>
 
</body>
</html>

【问题讨论】:

  • 嗨 Nikki,欢迎来到 SO。您能否在上一个 sn-p 中包含两个 SVG 供我们试用?
  • 嗨,Emiel,谢谢你!我在上面的问题中包含了两个示例 SVG。

标签: javascript svg png


【解决方案1】:

我使用了您的技术并制作了两个单独的函数。第一个函数 drawSVGToCanvas 为单个 SVG 创建一个画布,方法是将其转换为 blob 并在图像加载后将其绘制到画布上。当 canvas 元素被填充时,它会返回一个 Promise。

convertSVGsToSingleImage 接受一个 SVG 元素列表,它将循环访问并为每个 SVG 元素调用 drawSVGToCanvas。它等到它们被渲染并继续在单个新画布上绘制返回的画布元素。这就是合并发生的地方。

const preview = document.getElementById('preview');
const svgs = document.querySelectorAll('svg');

function drawSVGToCanvas(svg) {
  const { width, height } = svg.getBoundingClientRect();
  const serializer = new XMLSerializer();
  const copy = svg.cloneNode(true);
  const data = serializer.serializeToString(copy);
  const image = new Image();
  const blob = new Blob([data], {
    type: 'image/svg+xml;charset=utf-8'
  });
  const url = URL.createObjectURL(blob);
  return new Promise(resolve => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    canvas.width = width;
    canvas.height = height;
    image.addEventListener('load', () => {
      ctx.drawImage(image, 0, 0, width, height);
      URL.revokeObjectURL(url);
      resolve(canvas);
    }, { once: true });
    image.src = url;
  })
}

async function convertSVGsToSingleImage(svgs, format = 'image/png') {
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const drawSVGs = Array.from(svgs).map(svg => drawSVGToCanvas(svg))
  const renders = await Promise.all(drawSVGs);
  canvas.width = Math.max(...renders.map(render => render.width));
  canvas.height = Math.max(...renders.map(render => render.height));
  renders.forEach(render => ctx.drawImage(render, 0, 0, render.width, render.height));
  const source = canvas.toDataURL(format).replace(format, 'image/octet-stream');
  return source;
}

convertSVGsToSingleImage(svgs).then(source => {
  const image = new Image();
  image.addEventListener('load', () => {
    preview.append(image);
  })
  image.src = source;
});
<svg width="400" height="110">
  <rect width="300" height="100" style="fill:rgb(0,0,255);stroke-width:3;stroke:rgb(0,0,0)" />
  Sorry, your browser does not support inline SVG.  
</svg>

<svg height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
  Sorry, your browser does not support inline SVG.  
</svg>

<div id="preview"></div>

【讨论】:

  • svg.getBBox() 为您提供围绕 svg 可见内容的紧密边界框。换句话说:它小于 SVG 的固有大小,并且 x 和 y 不保证为 0。您的函数没有截断部分内容,这纯属幸运。
  • 我同意。这是我的一个实验。我已将其更改为使用 getBoundingClientRect(),这提供了更预期的结果。
猜你喜欢
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
  • 2010-12-24
  • 2019-07-18
  • 1970-01-01
  • 1970-01-01
  • 2015-09-24
相关资源
最近更新 更多