ブラウザでSVGを画像(JPEG、PNGなど)に変換します


300

JavaScriptを使用してSVGをビットマップ画像(JPEG、PNGなど)に変換したい。


実際にやりたいことは何ですか。echo-flowsの回答は、(一部のブラウザーでは)ほとんどすべての実際的なケースでより優れた簡単な変換方法が存在する可能性があることを示しています。
aaaaaaaaaaaa 2010

2
d3を使用した例を次に示します。stackoverflow.com/ a
ace

svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back-完全に動作します![リンクページでは、sourceSVG = $( "#your_svg_elem_name")。get(0)]
Vijay Singh

回答:


244

JavaScriptを使用してこれを行う方法を次に示します。

  1. Canvg JavaScriptライブラリを使用して、Canvasを使用してSVG画像をレンダリングします:https : //github.com/gabelerner/canvg
  2. 次の指示に従って、キャンバスからJPG(またはPNG)としてエンコードされたデータURIをキャプチャします。HTMLキャンバスをgif / jpg / png / pdfとしてキャプチャしますか?

28
これは厳密にはJavascriptではなく、HTML5でもあります。これは、IE8、またはHTML5 Canvasをサポートしないその他のブラウザーでは機能しません。
ジェームズ

16
ブラウザがSVGとキャンバスをサポートしている場合、SVGをメモリにロードし、キャンバスにペイントする方法はもっと簡単です。Canvgは必要ありません。これは、すべてのSVG解析を処理するため、かなり大きなライブラリです。 SVGをサポートするブラウザはすでに無料で提供されています。これが元のユースケースを満たしているかどうかはわかりませんが、満たしている場合は、このリソースで詳細を確認してください
Premasagar 2013年

120
IE8をサポートしないことに感謝します。次に進む時が来たことを人々は理解する必要があります。
Sanket Sahu 2014

9
これで、JavaScript SVGライブラリPabloを使用してこれを実現できます(私が作成しました)。自動ダウンロードされた画像については、toImage()およびも参照してくださいdownload()
プレマサガー2014

2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back-完全に動作します![リンクページで、sourceSVG = $( "#your_svg_elem_name")。get(0)]
Vijay Singh

44

jbeard4ソリューションは美しく機能しました。

私が使用しているラファエルスケッチブックを SVGを作成します。手順1のファイルにリンクします。

保存ボタンの場合(svgのIDは「editor」、canvasの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...
});

1
canvgには2番目のパラメーターが必要ですが<svg>...</svg、jquery html()関数はsvgタグを追加しないため、このコードは機能しますが、canvg liveを編集する必要がありましたcanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn

1
@Luckyn svg要素の$(selector).html()親を呼び出すと機能します
jonathanGB

@Luckynと@jonathanGBの場合html()、ラッパーで使用したり、親svgタグを手動で作成したりする必要はありません。このハックで除外した属性が含まれている場合もあります。使用するだけ$(svg_elem)[0].outerHTMLで、svgとその内容の完全なソースが提供されます。ただ言う...
nemesisfixx

18

これはほとんどのブラウザで動作するようです:

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

3
これは、とセキュリティ上の問題により、IE11で動作していない.msToBlob()
フロリアンLeitgeb

ありがとう!! これが「ローカル」SVG HTMLノードとリモートSVG URLの両方でどのように機能するかが気に入っています。さらに、完全な外部ライブラリを必要としません
Fabricio PH

7

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


3

私はこの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 Webサイトにアクセスして、コードをそこにトランスパイルできます。


2

これが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]"/>

ブラウザ全体で機能します。


サービスは停止しているようです。

3
私たちのホストは偽のリクエストに見舞われていました。だから私たちはそれを削除することにしました。ここで独自のサーバーを実行する必要があります。詳細については、githubリポジトリを参照してください。
Phuoc Do

1

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

1
それは私のために働いていません、私はこのエラーをUncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
受け取り

1
@XsmaelがDOMParserインターフェースを切り替えようとするdeveloper.mozilla.org/en-US/docs/Web/API/DOMParser
Mahdi Khalili

1

Svgpng条件に応じて変換することができます。

  1. svgSVG(文字列)パス形式の場合:
    • キャンバスを作成する
    • 作成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;

エッジでPath2Dはサポートされておらずie、部分的にサポートされていることに注意してください。ポリフィルはそれを解決します:https : //github.com/nilzona/path2d-polyfill

  1. svgblobを作成し、次を使用してキャンバスに描画します.drawImage()
    • キャンバス要素を作成する
    • svg xmlからsvgBlobオブジェクトを作成する
    • domUrl.createObjectURL(svgBlob);からURLオブジェクトを作成します。
    • 画像オブジェクトを作成し、画像ソースにURLを割り当てます
    • 画像をキャンバスに描画する
    • キャンバスからpngデータ文字列を取得:canvas.toDataURL();

いい説明:http : //ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

つまり、canvas.toDataURL();のステージで例外が発生することに注意してください。IEのセキュリティ制限が高すぎて、キャンバスに画像を描画した後、キャンバスを読み取り専用として扱うためです。他のすべてのブラウザは、画像がクロスオリジンの場合にのみ制限します。

  1. canvgJavaScriptライブラリを使用します。別のライブラリですが、便利な機能があります。

お気に入り:

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

3番目のリンクが壊れている
SerdarSayın

はい、確かに。今、そこにたどり着く方法がわかりません。しかし、上記の説明は、ある程度の理解には十分です。参考にした後、将来の共同コピーのための良いアイデア
Alex Vovchuk

0

私は最近、サイズと品質の両方で実際にビットマップの許容可能な近似を構築できるJavaScript用の画像トレースライブラリをいくつか発見しました。私はこのJavaScriptライブラリとCLIを開発しています:

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

DOMに依存しない、ブラウザとノードをサポートする、それらすべてに統一されたAPIとコマンドラインツールを提供します。

ロゴ/漫画/類似画像を変換するために、それは素晴らしい仕事をします。写真/リアリズムの場合、出力サイズが大きくなる可能性があるため、多少の調整が必要です。

それは遊び場を持っていますが、今はより多くの機能が追加されているので、私はより良いもの、より使いやすいものに取り組んでいます:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.