時折、ブラウザ上で画像生成を行っているサイトを見かけます。
このサイトでは、文字入力によってリアルタイムに画像が生成されます。入力された文字をサーバに送っている様子はありません。一体どうやって画像生成を行っているのでしょうか。
ここで使われているのが「canvas」です。今回はcanvasでの簡単な描画を行い、それをPNGとして書き出す方法を見ていきます。
canvasとはHTML要素のひとつであり、まさしく絵を描くためのキャンバスのようなものです。JavaScriptを記述することにより、canvas上で自由に描画を行うことがでます。例えばグラフ、イラストの描画、写真の編集、アニメーションなど。もちろん2Dだけではなく、3Dを扱うこともできます。WebGLも利用できるため、かなり複雑な3Dアニメーションを描画することも可能です(とても難しいけど!)
canvas要素を使うにあたり、まずHTML側でやることは、widthとheightの値を決めることです。JSからsetAttributeで指定しても大丈夫です。ただしCSSによるwidthとheightの指定は意味合いが異なり、単に(画像を拡縮するように)領域を拡大縮小するだけになります。
例を作成してみました。
ボタンを押下した際、上に表示されているのがcanvas、下に表示されているのが生成されたPNG画像です。
「画像生成」を押すたびに、つまりVueの変数の値が変わるたびに、canvasに併せて下の画像も変化するのが分かります。
コードについてはVueを使用して書いています。
<canvas id="testCvs" width="300" height="300"></canvas>
※なお、例で挙げたロゴジェネレータのHTMLソースにはcanvasが出てきません。どういうことかというと、結果の画像だけが欲しいなら、canvasは必ずしも画面に表示する必要はないのです。index.js内を「createElement」で検索すると、canvas要素を生成している行が見つかります。この見えないcanvas上で画像生成を行っているのです。
こうして確保した領域から、JSでコンテキストを取得、描画を行います。コンテキストの取得とはざっくり言えば、この領域を2Dとして扱うためのインタフェースを取得することです。
const cvs = document.getElementById('testCvs')
const context = cvs.getContext('2d')
JSでは、文字列、矩形、多角形、パスを用いた直線や曲線などを描画することができます。
今回は詳しく取り扱いませんが、mdnに詳細が載っています。これらを組み合わせて複雑な描画を行うこともできます。
基本的に、描画は「色を指定する→形と塗り方を指定する」、或いは「色を指定する→パスを指定する→塗り方を指定する」の形で行います。
今回は、背景を白で塗りつぶし、ランダムな位置に赤と青の正方形を描いてみます。
まず、背景の塗りつぶしはこのようになります。
context.fillStyle = '#fff'
context.fillRect(0, 0, 300, 300)
今回はキャンバスサイズを300x300にしたので、画面いっぱいに白い矩形を描画しました。fillRectの引数はそれぞれ(始点のX座標、始点のY座標、横幅、高さ)です。
さきほど述べたように、まず塗りつぶしの色を指定してから、四角形に塗りつぶしを行っています。
次に、ランダムな座標をふたつ決定し、それらを始点としてふたつの正方形を描いてみます。
// ランダムな位置に2つの四角形(50x50)
const point1X = Math.floor(Math.random() * (imgWidth - 50))
const point1Y = Math.floor(Math.random() * (imgHeight - 50))
const point2X = Math.floor(Math.random() * (imgWidth - 50))
const point2Y = Math.floor(Math.random() * (imgHeight - 50))
context.fillStyle = "rgb(200, 0, 0)"
context.fillRect(point1X, point1Y, 50, 50)
context.fillStyle = "rgba(0, 0, 200, 0.5)"
context.fillRect(point2X, point2Y, 50, 50)
やっていることは先ほどと一緒です。そしてこの通り、色指定には16進数だけではなく、rgbやrgbaを使用することもできます。
では最後に、canvasに描画した内容をPNG形式で書き出してみます。やり方は非常にシンプルです。
displayImg.value = cvs.toDataURL()
左辺については、Vueで書いているためこの形式になっています。
右辺の通り、「toDataURL()」を実行することで、base64形式のコードが返ってきます。特に指定しない場合は、「image/png」として出力されます。
なので、この値をimg要素のsrc属性にセットすれば、画像が表示されます。
<img :src="displayImg" alt="生成した画像">
このように、canvasに描画した内容を画像にするのは意外と簡単です。今回は矩形を用いましたが、テキストの変更をリアルタイムに検知して、画像を変化させることももちろん可能です。ぜひ手元でもやってみてくださいね!