将内联SVG另存为JPEG/PNG/SVG

48

我在html中有一个内联SVG,我需要将其保存为JPEG、PNG或SVG格式。

我尝试了几种不同的方法,将SVG转换为画布,然后转换为JPEG,但是我无法使它们正常工作。

下面是我的内联SVG示例。

.font {
 color: #ffffff;
 font-family: Roboto;
 font-weight: bold;
 text-transform: uppercase;
}
.name {
 font-size: 64pt;
}
.top-bar-text {
 font-size: 32pt;
}
.font tspan {
 dominant-baseline: middle;
}
<link href='http://fonts.googleapis.com/css?family=Roboto:700' rel='stylesheet' type='text/css'>

<svg width="256" height="256" id="icon">
  <rect class="bg1" id="bg_color_1" x="0" y="0" width="256" height="256" fill="#4cbc5a" />
  <path class="bg2" id="bg_color_2" d="M 0 96 L0,256 L256,256 L256,96 s -128 96 -256 0" fill="#08a21c" />
  <text id="left_corner_text" x="24" y="36" width="48" height="64" class="top_bar lct font top-bar-text" text-anchor="middle" fill="#ffffff"><tspan>1</tspan></text>
  <text id="right_corner_text" x="232" y="36" width="48" height="64" class="top_bar rct font top-bar-text" text-anchor="middle" fill="#ffffff"><tspan>2</tspan></text>
  <text id="line_1_text" transform="scale(1,2)" x="128" y="90" width="256" height="192" class="l1t font name" text-anchor="middle" fill="#ffffff"><tspan>ABC</tspan></text>
</svg>

此外,并非所有元素都需要导出,因为用户有一些选项可以删除顶部角落的数字。

我希望转换后能够直接下载到浏览器中。

8个回答

90
现在这很简单。
基本思路是:
  1. 将SVG转换为画布
  2. 将画布转换为数据URL
  3. 从数据URL触发下载

它实际上在 Stack Overflow 代码片段之外也能正常工作。

function triggerDownload(imgURI) {
  const a = document.createElement('a');
  a.download = 'MY_COOL_IMAGE.png'; // filename
  a.target = '_blank';
  a.href = imgURI;

  // trigger download button
  // (set `bubbles` to false here.
  // or just `a.click()` if you don't care about bubbling)
  a.dispatchEvent(new MouseEvent('click', {
    view: window,
    bubbles: false,
    cancelable: true
  }));
}

const btn = document.querySelector('button');
btn.addEventListener('click', function () {
  const svgNode = document.querySelector('svg');
  const svgString = (new XMLSerializer()).serializeToString(svgNode);
  const svgBlob = new Blob([svgString], {
    type: 'image/svg+xml;charset=utf-8'
  });

  const DOMURL = window.URL || window.webkitURL || window;
  const url = DOMURL.createObjectURL(svgBlob);

  const image = new Image();
  image.width = svgNode.width.baseVal.value;
  image.height = svgNode.height.baseVal.value;
  image.src = url;
  image.onload = function () {
    const canvas = document.getElementById('canvas');
    canvas.width = image.width;
    canvas.height = image.height;

    const ctx = canvas.getContext('2d');
    ctx.drawImage(image, 0, 0);
    DOMURL.revokeObjectURL(url);

    const imgURI = canvas
      .toDataURL('image/png')
      .replace('image/png', 'image/octet-stream');
    triggerDownload(imgURI);
  };
});
<button>svg to png</button>

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">
  <rect x="10" y="10" width="50" height="50" />
  <text x="0" y="100">Look, i'm cool</text>
</svg>

<canvas id="canvas"></canvas>

关于下载部分,您可以设置文件名、图像宽度和高度等等(尽管在此示例中大多数情况下未包含)。几天前,我回答了一个关于如何从给定页面下载特定HTML部分的问题。这可能对下载部分有用:https://stackoverflow.com/a/28087280/2178180 更新 2021-11-30:现在允许您指定文件名。
更新 2023-06-29:提高代码可读性,并确保图像的宽度和高度与SVG匹配。

1
你好!在IE中支持可能会很困难,因为它不支持Blob api - 请参见caniuse blob。我认为MouseEvent接口也没有正确设置(只是猜测)。无论如何,在Firefox中应该能够正常工作。你试过哪个版本?这里有一个jsfiddle:http://jsfiddle.net/LznLjxq7/。 - Ciro Costa
1
我在SVG文件中有一个<image>标签,但只有线条/路径会被下载,你有什么线索吗? - ptkato
1
如何在转换为PNG时更改大小。需要适应我的网站的尺寸变化。请帮帮我。 - chandramouli.jamadagni
2
这是一个很好的答案,但为了使最终图像具有与SVG相同的大小,请使您的画布具有HTML(而不是CSS)属性高度和宽度。最好在onClick事件中执行此操作,并使其获取SVG的尺寸。 - user1816910
3
Safari似乎不喜欢Blob类型中的;charset=utf-8部分,这会导致img.onload未被调用的问题。对于大小调整,我会为我的canvas设置大小,并在drawImage(...)调用中提供widthheight参数。 - Matt Schuette
显示剩余13条评论

5

这里有一个解决方案,适用于IE11。

我刚刚测试了各种方法,虽然Ciro Costa的答案在Firefox和Chrome中运行良好,但它在IE11中不起作用。IE11由于渲染svg到画布需要画布实现,存在安全问题而失败,因此需要使用canvg。这里是一种使用canvg的解决方案,代码简洁,并且能够在最新版本的Chrome、Firefox、Edge和IE11中运行。

演示:https://jsfiddle.net/StefanValentin/9mudw0ts/

DOM

<svg
  id="my-svg"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  version="1.1"
  width="200"
  height="200"
>
  <rect x="10" y="10" width="50" height="50" />
  <text x="0" y="100">Look, i'm cool</text>
</svg>

JavaScript

var svg = document.querySelector('#my-svg');
var data = (new XMLSerializer()).serializeToString(svg);
// We can just create a canvas element inline so you don't even need one on the DOM. Cool!
var canvas = document.createElement('canvas');
canvg(canvas, data, {
  renderCallback: function() {
    canvas.toBlob(function(blob) {
        download('MyImageName.png', blob);
    });
  }
});

上述的 download 函数可以是任何你想要做的事情,因为有许多通过 JavaScript 触发下载的方法。这里是我们使用的一种,在我测试过的所有浏览器中都可以工作。
// Initiate download of blob
function download(
  filename, // string
  blob // Blob
) {
  if (window.navigator.msSaveOrOpenBlob) {
    window.navigator.msSaveBlob(blob, filename);
  } else {
    const elem = window.document.createElement('a');
    elem.href = window.URL.createObjectURL(blob);
    elem.download = filename;
    document.body.appendChild(elem);
    elem.click();
    document.body.removeChild(elem);
  }
}

2
canvg() 定义在哪里? - Punter Bad
1
在 JSFiddle 中,如果您检查资源,您会看到导入了 canvg.min。这将canvg公开为全局变量。但是,如果您查看文档,可以通过npm导入它并通过导入引用它:https://github.com/canvg/canvg - KhalilRavanna

3

保存内联SVG为SVG文件的解决方案

适用于现代浏览器

<svg width="100" height="100">
  <rect fill="red" x="0" y="0" width="100" height="100" />
</svg>

<button>Save to SVG</button>

let btn = document.querySelector('button')
let svg = document.querySelector('svg')

let triggerDownload = (imgURI, fileName) => {
    let a = document.createElement('a')

    a.setAttribute('download', 'image.svg')
    a.setAttribute('href', imgURI)
    a.setAttribute('target', '_blank')

    a.click()
}

let save = () => {
    let data = (new XMLSerializer()).serializeToString(svg)
    let svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'})
    let url = URL.createObjectURL(svgBlob)

    triggerDownload(url)
}

let btn = document.querySelector('button')
btn.addEventListener('click', save)

Codepen: https://codepen.io/udovichenko/pen/yLXaWLB

代码笔:https://codepen.io/udovichenko/pen/yLXaWLB


1

总体而言,这里提出的解决方案是可行的,但不要忘记明确以像素为单位设置画布大小,否则图像可能会被裁剪。

例如:

// get the size of the svg image
const { width, height } = svg.getBBox();

// create a canvas and set its size
var canvas = document.createElement(`canvas`);
canvas.setAttribute(`width`, width);
canvas.setAttribute(`height`, height);


1

@ciro costa的回答确实有帮助,但是生成的png高度不正确,除非设置画布的高度和宽度。

function downloadImg() {
  const svgElem = document.querySelector('svg')
  const serializer = new XMLSerializer();
  let svgData = serializer.serializeToString(svgElem);
  svgData = '<?xml version="1.0" standalone="no"?>\r\n' + svgData;
  const svgBlob = new Blob([svgData], {
    type: 'image/svg+xml;charset=utf-8',
  });
  let DOMURL = window.URL || window.webkitURL || window;
  const url = DOMURL.createObjectURL(svgBlob);

  const img = new Image();
  img.onload = () => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const domRect = svgElem.getBBox();
    canvas.width = domRect.width;
    canvas.height = domRect.height;
    ctx.drawImage(img, 0, 0, domRect.width, domRect.height);
    DOMURL.revokeObjectURL(url);

    const imgURI = canvas
      .toDataURL('image/png')
      .replace('image/png', 'image/octet-stream');

    download(imgURI);
  };
  img.onerror = (e) => {
    console.error('Image not loaded', e);
  };

  img.src = url;
}

function download(href) {
  let download = document.createElement('a');
  download.href = href;
  download.download = 'img.png';
  download.click();
  download.remove();
}
<svg width="256" height="256" id="icon">
      <rect class="bg1" id="bg_color_1" x="0" y="0" width="256" height="256" fill="#4cbc5a" />
    </svg>

<div>
  <button onclick="downloadImg()">Download</button>
</div>


1

如果您无法导出一个元素,可以参考@CiroCosta的方法。一种选择是在绘制SVG图像之前将图像绘制到画布上。

btn.addEventListener('click', function () {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var data = (new XMLSerializer()).serializeToString(svg);
  var DOMURL = window.URL || window.webkitURL || window;

  // get the raw image from the DOM
  var rawImage = document.getElementById('yourimageID');
  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(rawImage, 0, 0);
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);

    var imgURI = canvas
      .toDataURL('image/png')
      .replace('image/png', 'image/octet-stream');

    triggerDownload(imgURI);
  };

  img.src = url;
});

对我有用,但只适用于png和jpeg格式。SVG文件仍然只显示内联元素而不是标签。

编辑:创建这样的SVG的方法实际上是通过将图像标记转换为Base64,然后将其设置为图像属性中的xlink:href,如下所示:

<image id="crop" width="725" height="1764" xlink:href="data:image/png;base64,iVBORw0KGgo ... " />

然后触发整个SVG URL 的下载,如下所示:
btn.addEventListener('click', function () {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  var data = (new XMLSerializer()).serializeToString(svg);
  var DOMURL = window.URL || window.webkitURL || window;

  var rawImage = document.getElementById('yourimageID');
  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);

    triggerDownload(url);
    DOMURL.revokeObjectURL(url);
  }
};

你可以像这样转换png文件 这里
function getDataUri(url, callback) {
  var image = new Image();

  image.onload = function () {
    var canvas = document.createElement('canvas');
    canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
    canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size

    canvas.getContext('2d').drawImage(this, 0, 0);

    // Get raw image data
    callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, ''));

    // ... or get as Data URI
    callback(canvas.toDataURL('image/png'));
  };

  image.src = url;
}

然后设置属性

getDataUri('localImagepath', function (dataUri) {
  image.setAttribute('xlink:href', dataUri);
});

0

使用这个例子,但JavaScript部分对您来说很简单。

function SVGPNG(svg, cb) {
  let temp = document.createElement("img");
  let imageSrc = URL.createObjectURL(
    new Blob([svg], { type: "image/svg+xml" })
  );

  temp.src = imageSrc;
  temp.setAttribute("style", "position:fixed;left:-200vw;");
  document.body.appendChild(temp);
  temp.onload = function onload() {
    let canvas = document.createElement("canvas");
    canvas.width = temp.clientWidth;
    canvas.height = temp.clientHeight;
    let ctx = canvas.getContext("2d");
    ctx.drawImage(temp, 0, 0);
    let src = canvas.toDataURL("image/png");
    cb(src, canvas);
    temp.remove();
    URL.revokeObjectURL(imageSrc);
  };
}

function onPaste(e) {
  SVGPNG(e.target.value, (src) => {
    document.getElementById("output").value = src;
  });
}
body {
  font-family: system-ui;
  background: #f06d06;
  color: white;
  text-align: center;
}

textarea {
  border: solid 1px #ccc;
  border-radius: 10px;
  resize: none;
  outlined: solid 1px #999;
}
<textarea cols="60" rows="20" autofocus onchange="onPaste">Paste your SVG code here...</textarea>
<textarea cols="60" rows="20" readonly id="output">Your output here...</textarea>


-1
简单来说,将一个svg、一个canvas和一个空的img放入HTML中。将它们全部设置为相同的大小。Javascript将使用svg创建一个二进制大对象,然后在canvas中呈现为png图像。函数调用会创建canvas的克隆,并将其转换为jpeg格式。

function fjpg(){
 clone = c.cloneNode(true);
 ctx = clone.getContext('2d');
 ctx.fillStyle = "#FFF";
 ctx.fillRect(0, 0, clone.width, clone.height);
 ctx.drawImage(c, 0, 0);
 document.all.jp1.src=clone.toDataURL("image/jpeg");
 ctx = c.getContext('2d');
 svgBlob = new Blob( [dataPNG], { type: 'image/svg+xml' } );
 urlPNG = self.URL.createObjectURL( svgBlob );
 img = new Image();
 img.onload = function () {ctx.drawImage(img,0,0)}
 img.src = urlPNG;
}
c = document.all.canvas0;
ctx = c.getContext('2d');
data = (new XMLSerializer()).serializeToString(document.all.svg0);
dataJPG = data.replace('>SVG<','>JPG<');
dataPNG = data.replace('>SVG<','>PNG<');
svgBlob = new Blob( [dataJPG], { type: 'image/svg+xml' } );
urlJPG = self.URL.createObjectURL( svgBlob );
img = new Image();
img.onload = function () {
 ctx.drawImage( img, 0, 0 );
 fjpg();
}
img.src = urlJPG;
<svg id='svg0' height=180 width=180><rect width=100% height=100% fill=red /><circle cx=90 cy=90 r=80 fill=green /><text x=90 y=105 font-size=60 text-anchor=middle fill=yellow>SVG</text></svg>
<canvas id="canvas0" height=180 width=180></canvas>
<img src='' id='jp1'>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接