「Canvasって何・・・?」状態のオンナが、Canvasを使ってsvgをpng画像に変換・ダウンロードするまで

Canvas

何度もお目にかかっていたCanvasさん。
避けに避け続けていましたが、業務で使わざるを得ない状況になったので、
お勉強と実装をしてみました。

最終的に、Vue3で、svgをpngにしたい

※svgは、インラインで直接表示させているもの。

最初、参考サイトの通りに実装しましたが、
svgの読み込みが上手く行いかなかった&エラーがあったので、
不具合・エラーを直したものを、こちらに残しておきます・・・。

Canvasとは

  • HTML5とJavaScript(以下、JS)でブラウザ上に図が描けるもの
  • <canvas>タグにJSで、図を描画していく
  • Canvasでレイアウトを決めた部分には、CSSでレイアウトを適用できない

SVGのPNG画像変換

大まかな流れとしては、CanvasとJSを使って、svgをPNG画像に変換・描画し、PNG画像のデータをダウンロード。

手順

  1. XMLSerializerを使って、SVG画像のデータを取り出す
  2. CanvasとJSを使って、PNG形式に変換
  3. CanvasのtoDataURL()で、PNG画像のURIを取得
  4. ローカルにpng画像をダウンロード

コード

// vue
<div @click="download()">
    <svg id="sample">....いろいろ描いてあります.....</svg>
</div>
const download = () => {
      // svg domを取得
      const svg = document.getElementById('sample')

      // canvasを準備
      let canvas = document.createElement('canvas')
      canvas.width = svg.width.baseVal.value
      canvas.height = svg.height.baseVal.value

      // 描画をするための、canvasの組み込みオブジェクトを準備
      const ctx = canvas.getContext('2d')
      // imgオブジェクトを準備
      let image = new Image()

      // imageの読み込みが完了したら、onloadが走る
      image.onload = () => {
        // SVGデータをPNG形式に変換する
        // canvasに描画する drawImage(image, x座標, y座標, 幅, 高さ)
        ctx.drawImage(image, 0, 0, image.width, image.height)

        // ローカルにダウンロード
        let link = document.createElement("a")
        link.href = canvas.toDataURL() // 描画した画像のURIを返す data:image/png;base64
        link.download = "canvas.png"
	link.click()
      }
      // 読み込みに失敗したらこっちが走る
      image.onerror = (error) => {
        console.log(error)
      }

      // SVGデータをXMLで取り出す
      const svgData = new XMLSerializer().serializeToString(svg)
      // この時点で、上記のonloadが走る
      image.src = 'data:image/svg+xml;charset=utf-8;base64,' + btoa(unescape(encodeURIComponent(svgData)))
}

コード解説

canvas.getContext(“2d”)

getContext(“2d”) オブジェクトは、線、ボックス、円、などを描画するメソッドを持っています。

http://memopad.bitter.jp/w3c/html5/html5_ref_canvas.html

使える描画メソッド一覧も、上記のサイトにあります。

例えば、drawImage()メソッドは、canvasに画像を描画する。

const image = new Image()
const ctx = canvas.getContext('2d')
ctx.drawImage(image, x座標, y座標, 幅, 高さ)

new Image()

The Image() constructor creates and returns a new HTMLImageElement object representing an HTML <img> element which is not attached to any DOM tree. It accepts optional width and height parameters. When called without parameters, new Image() is equivalent to calling document.createElement(“img”).

https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement

新しいHTMLImageElementインスタンス(<img>)を作成するコンストラクタ
つまり、new Image()をすることで、imgタグを作成できる

image.onload

image.srcに画像のパスを渡して、読み込み完了したタイミングで、onloadが走る

drawImage

drawImageは、<canvas>へ画像を描画する。

serializeToString

XMLSerializerのメソッドで、HTMLElementオブジェクトを、XML出力する。

new XMLSerializer().serializeToString(HTMLElementオブジェクト)
WindowOrWorkerGlobalScope.btoa() - Web API | MDN
WindowOrWorkerGlobalScope.btoa() メソッドは、 Base64 でエンコードされた ASCII 文字列をバイナリ文字列 (例えば String オブジェクトのうち、文字列中のすべての文字がバイナリデータのバイトとして扱うことができるもの) から生成します。

btoa

  • WindowOrWorkerGlobalScope.btoa()メソッドは、バイナリ文字列から、Base64でエンコードされたASCII文字列を生成する。
  • 使いどころ:画像のデータを文字列でsrcに渡したいときなど
    • btoaでデータをエンコードしている
    • atobで再度デコードできる

toDataURL

  • canvasのメソッド
  • 画像の data URI を返す。
  • typeパラメーターで、画像ファイルの形式を指定できる(デフォルトはpng)
  • 返り値の例:data:image/png;base64,iVBORw0KGgoAAAANSUhE……

用語

SVG

  • スケーラブル・ベクター・グラフィックス、Scalable Vector Graphics
  • 画像形式の1つ
  • XMLをベースにしたベクターデータで画像を描画(拡大・縮小しても画質が損なわれない)
  • イラレ以外にも、d3jsというもので作成できるらしい

XMLSerializer

XMLSerializer インターフェースは、DOM ツリーを表す XML 文字列を構築するための serializeToString() (en-US) メソッドを提供します。

https://developer.mozilla.org/ja/docs/Web/API/XMLSerializer

  • DOMから、XML文字列を生成するためのクラス
  • 最新のブラウザならだいたい対応している(チェック
  • new XMLSerializer() オブジェクトを使用する

参考サイト

お世話になりました・・・(愛)

知っておきたいHTMLのCanvasとは?何ができるのかを解説 | 侍エンジニアブログ
この記事では「 知っておきたいHTMLのCanvasとは?何ができるのかを解説 」といった内容について、誰でも理解できるように解説します。この記事を読めば、あなたの悩みが解決するだけじゃなく、新たな気付きも発見できることでしょう。お悩みの方はぜひご一読ください。
SVGを画像化する | アシアルブログ
はじめに 昨今のクライアントサイドでは、動的な画像のレンダリング、アニメーション、拡張・縮小を求められることが多々あります。そのような際にSVGは利用しやすい形式です。一方で、画像として内容を保存したくなることもあります。そのような場合に使える、SVG画像をPNG画像に変換する方法を簡単に述べます。 SVGとは SVG...
XMLSerializer - Web API | MDN
XMLSerializer インターフェースは、DOM ツリーを表す XML 文字列を構築するための serializeToString() (en-US) メソッドを提供します。
JavaScriptプログラミング講座【DOMParser について】
HTML5 canvas.getContext("2d") reference
Free HTML XHTML CSS JavaScript DHTML XML DOM XSL XSLT RSS AJAX html ADO PHP SQL tutorials, references, examples for web building.
画像を使う - Web API | MDN
これまで、図形を作成してスタイルを適用する方法を見てきました。 のより面白い機能のひとつが、画像を扱えることです。これは動的な画像合成を行う、グラフの背景として使用する、ゲームのスプライトとして使用するなどといったことが可能です。PNG、GIF、JPEG といった、ブラウザがサポートする形式の外部画像を使用できます。...
HTMLImageElement - Web APIs | MDN
The HTMLImageElement interface represents an HTML element, providing the properties and methods used to manipulate image elements.
Image() - Web APIs | MDN
The Image() constructor creates a new HTMLImageElement instance. It is functionally equivalent to document.createElement('img').
PromiseベースでImage().onloadする - Qiita
やりたいこと JavaScriptで、画像の width/height が知りたいとき、以下のようにする。 const img = new Image(); img.onload = () => { console...
HTML5 canvas drawImage Method
Free HTML XHTML CSS JavaScript DHTML XML DOM XSL XSLT RSS AJAX html ADO PHP SQL tutorials, references, examples for web building.
SVGを画像に変換してダウンロードする方法 - Qiita
D3.jsやflowchart.jsなど、SVGで出力された画像を保存したくなるときが多々あります。 そんなときに使うjavascript。Chromeのデバッガーツールのconsoleから入力するだけでOK。 出力処理 var...
WindowOrWorkerGlobalScope.btoa() - Web API | MDN
WindowOrWorkerGlobalScope.btoa() メソッドは、 Base64 でエンコードされた ASCII 文字列をバイナリ文字列 (例えば String オブジェクトのうち、文字列中のすべての文字がバイナリデータのバイトとして扱うことができるもの) から生成します。
Canvasで画像をダウンロードしたい|yusaku|note
canvasで作ったら、当然ダウンロードしたいですよね。 ブログのトップ画像に使ったり、SNSで「こんなの作りました」と言っといたほうがいい時代ですし。 canvasでダウンロードってどうするんだろう?と調べてみたのですが、すぐにわからなかったです。p5.jsのsaveCanvasのようなのはないのかな? 説明して...
HTML5でのSVGファイル操作のおさらい - Qiita
最近、HTML5でベクターグラフィックスを取り扱う時にSVG形式のファイルを利用しているWEBサイトが増えて来ている。iOS系のデバイスが超高解像度のRetinaディスプレイを採用しているので、PCサイト向けに準備した800×600や...
画像ファイルをバイナリではなくテキストで扱うbase64フォーマットって便利なのだろうか?
こんにちわ。 画像を、観ることも、描くことも、編集することも、フォーマット変換することも大好きな下駄です。 base64フォーマットって、使わなくても全く困らないんですが、使ってみると結構便利な点も多く、必要に応じて使用すると効果的なので、そのメリット・デメリットをまとめておきます。 base64の使い方 bas...

 

コメント