簡體   English   中英

在瀏覽器中將 SVG 轉換為圖像(JPEG、PNG 等)

[英]Convert SVG to image (JPEG, PNG, etc.) in the browser

我想通過 JavaScript 將 SVG 轉換為 bitmap 圖像(如 JPEG、PNG 等)。

以下是通過 JavaScript 執行此操作的方法:

  1. 使用 canvg JavaScript 庫使用 Canvas 渲染 SVG 圖像: https ://github.com/gabelerner/canvg
  2. 根據以下說明從 Canvas 捕獲編碼為 JPG(或 PNG)的數據 URI:將HTML Canvas 捕獲為 gif/jpg/png/pdf?

jbeard4 解決方案效果很好。

我正在使用Raphael SketchPad創建 SVG。 鏈接到步驟 1 中的文件。

對於保存按鈕(svg 的 id 是“editor”,畫布的 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...
});

這似乎適用於大多數瀏覽器:

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

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

我的用例是從網絡加載 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以匹配您的元素

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

這是一個無需庫即可工作並返回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 上,沒有設置 width / height 的 SVG 存在問題

請參閱此工作示例,其中包括對 Firefox 問題的修復。

這是基於PhantomJS的服務器端解決方案。 您可以使用JSONP對圖像服務進行跨域調用:

https://github.com/vidalab/banquo-server

例如:

http:// [host] /api/https%3A%2F%2Fvida.io%2Fdocuments%2FWgBMc4zDWF7YpqXGR/viewport_width=980&viewport_height=900&delay=5000&selector=%23canvas

然后可以顯示帶有img標簽的圖像:

<img src="data:image/png;base64, [base64 data]"/>

它適用於所有瀏覽器。

Svgpng可以根據條件進行轉換:

  1. 如果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;

請注意, ie不支持Path2D ,edge 部分支持。 Polyfill 解決了這個問題: https ://github.com/nilzona/path2d-polyfill

  1. 使用.drawImage()創建svg blob 並在畫布上繪制:
  • 制作畫布元素
  • 從 svg xml 創建一個 svgBlob 對象
  • 從 domUrl.createObjectURL(svgBlob) 創建一個 url 對象;
  • 創建一個 Image 對象並將 url 分配給圖像 src
  • 將圖像繪制到畫布中
  • 從畫布中獲取 png 數據字符串:canvas.toDataURL();

很好的描述: https ://web.archive.org/web/20200125162931/http://ramblings.mcpher.com:80/Home/excelquirks/gassnips/svgtopng

請注意,在 ie 中,您將在 canvas.toDataURL(); 的階段獲得異常; 這是因為 IE 的安全限制太高,在畫布后將畫布視為只讀。 所有其他瀏覽器僅在圖像是跨源時才進行限制。

  1. 使用canvg JavaScript 庫。 它是獨立的庫,但具有有用的功能。

喜歡:

ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();

我最近發現了幾個用於 JavaScript 的圖像跟蹤庫,它們確實能夠為位圖構建一個可接受的近似值,無論是大小還是質量。 我正在開發這個 JavaScript 庫和 CLI:

https://www.npmjs.com/package/svg-png-converter

它為所有這些提供了統一的 API,支持瀏覽器和節點,不依賴於 DOM,以及一個命令行工具。

對於轉換徽標/卡通/類似圖像,它做得很好。 對於照片/真實感,需要進行一些調整,因為輸出大小會增長很多。

它有一個游樂場,雖然現在我正在開發一個更好、更易於使用的游樂場,因為添加了更多功能:

https://cancerberosgx.github.io/demos/svg-png-converter/playground/#

有幾種方法可以使用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>

  1. 從 SVG 獲取數據 URI

    data:image/svg+xml;base64,${btoa(new XMLSerializer().serializeToString(svgElem))}

  2. 准備一個圖像
  3. 創建一個 canvas 並使用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>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM