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

IT技术 javascript svg png jpeg
2021-03-01 05:58:53

我的 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>

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

我想当它被转换为直接下载到浏览器时。

6个回答

现在这很简单。

基本思想是:

  1. SVG 到画布
  2. 画布到 dataUrl
  3. 从 dataUrl 触发下载

它实际上在 Stack Overflow 代码段之外工作

var btn = document.querySelector('button');
var svg = document.querySelector('svg');
var canvas = document.querySelector('canvas');

function triggerDownload (imgURI) {
  var evt = new MouseEvent('click', {
    view: window,
    bubbles: false,
    cancelable: true
  });

  var a = document.createElement('a');
  a.setAttribute('download', 'MY_COOL_IMAGE.png');
  a.setAttribute('href', imgURI);
  a.setAttribute('target', '_blank');

  a.dispatchEvent(evt);
}

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 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);

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

    triggerDownload(imgURI);
  };

  img.src = url;
});
<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

更新:现在让您指定文件名

这是如何运作的?我复制了确切的代码,但无法复制它。你能把它放在jsfiddle中吗?
2021-04-24 05:58:53
你好!IE 中的支持很难,因为它不支持Blob api -请参阅 caniuse blob我也认为 MouseEvent 接口没有正确设置(只是猜测)。无论如何,它应该在 Firefox 中运行良好。你在哪个版本试过?这是一个 jsfiddle:jsfiddle.net/LznLjxq7
2021-04-29 05:58:53
Safari 似乎不喜欢;charset=utf-8Blob 类型位。这会导致img.onload未调用的问题。对于大小,我大小我canvas,然后还提供widthheightPARAMS的drawImage(...)电话。
2021-04-30 05:58:53
<image>在 svg 中有一个标签,但只有行/路径被下载,你有什么线索吗?
2021-05-01 05:58:53
这是一个很好的答案,但为了使最终图像具有与 svg 相同的大小,请让您的画布具有 html(而非 css)属性高度和宽度。在onClick上执行此操作并使其获取svg的尺寸可能是个好主意。
2021-05-08 05:58:53

这是一个也适用于 IE11 的解决方案。

我只是对各种方法进行了大量测试,虽然 Ciro Costa 的上述答案非常棒,因为它适用于 Firefox 和 Chrome,但它不适用于 IE11。由于将svg 呈现到需要画布实现canvg的画布的安全问题IE11失败这是一个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);
  }
}
canvg() 在哪里定义?
2021-04-18 05:58:53
在 JSFiddle 中,如果您检查资源,您将看到导入的 canvg.min。这暴露canvg为全局。如果您查看文档虽然您可以通过 npm 导入它并通过导入来引用它:github.com/canvg/canvg
2021-05-15 05:58:53

关闭@CiroCosta。1 个选项如果您在导出元素时遇到问题,您可以在绘制 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);
});

内联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)

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

@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>