如何将多个SVG转换为一个PNG图像?

问题描述

我需要将2个独立的SVG转换为1个PNG图像。我目前有将1 SVG转换为PNG的代码。该代码如下所示,我将SVG转换为canvas到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,$(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,$(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,255);stroke-width:3;stroke:rgb(0,0)" />
  Sorry,your browser does not support inline SVG.  
</svg>
 
</body>
</html>

解决方法

我已经使用了您的技术,并完成了两个单独的功能。第一个功能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,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,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,255);stroke-width:3;stroke:rgb(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>