2つの画像を合成する[アルファブレンド]
誰もがコーディングできるJavascriptで画像を合成する方法をご紹介します。画像の合成はゲームや画像処理の分野で用いられ「アルファブレンド」とも呼ばれます。
このサンプルはHTML5のcanvasに対応しているブラウザが必要となります。
動作確認
IE11 / Edge / Chrome /FireFox
※IE9/IE10は未確認ですが動作するかも知れません。
画像の合成 - 単色
単色と画像の合成となります。
スライダーを0にすると原画像、128にすると半透明、255にすると赤色になります。
画像の合成 - 2つの画像
原画像1、原画像2の二つの画像を合成します。
スライダーを0にすると原画像1、128にすると半透明、255にすると原画像2になります。
原画像1 | |
原画像2 | |
合成先 |
プログラムコード - 単色
単色のアルファブレンドはHTML5の標準機能で合成しています。context.fillStyleプロパティに「rgba()」でアルファを設定してるだけです。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <input type="range" id="a_range" min="0" max="255" value="0" onmouseup="onMouseUp1();" style="padding:0;"> <span id="msg_a">0/255</span> <br> <br> <canvas id="MyCanvas"></canvas> <img id="img_src" src="test.gif" style="display:none;"> <script> // キャンバスの取得 var canvas = document.getElementById("MyCanvas"); if (canvas.getContext) { // コンテキストの取得 var ctx = canvas.getContext("2d"); // イメージの取得 var image = document.getElementById("img_src"); // イメージが読み込まれた image.addEventListener("load", function () { canvas.width = image.width; canvas.height = image.height; // キャンバスに画像を描画 ctx.drawImage(image,0,0); },false); } function onMouseUp1(){ document.getElementById('msg_a').innerHTML = a_range.value +'/255'; // キャンバスに画像を描画 ctx.drawImage(image,0,0); ctx.fillStyle = 'rgba(255,0,0,'+ a_range.value / 255 +')'; ctx.fillRect(0,0,image.width,image.height); } </script> </body> </html>
プログラムコード - 2つの画像
2つの画像のアルファブレンドはcontext.getImageData()で取得した原画像1と原画像2の画像データ(ImageData)をアルファブレンドの公式で算出して合成先へ設定します。これは画像処理で一般的に使用される手法となります。
配列の添え字の部分は画像データがRGBAの順番に格納されていますのでこのようになります。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> </head> <body> <input type="range" id="blend_range" min="0" max="255" value="0" onmouseup="onMouseUp2();" style="padding:0;"> <span id="msg_blend">0/255</span> <br> <br> <table> <tr><td>ソース1</td><td><canvas id="canvas_src1"></canvas></td></tr> <tr><td>ソース2</td><td><canvas id="canvas_src2"></canvas></td></tr> <tr><td>合成先</td><td><canvas id="canvas_dst" width="1" height="1"></canvas></td></tr> </table> <p></p> <img id="img_src1" src="test1.gif" style="display:none;"> <img id="img_src2" src="test2.png" style="display:none;"> <script> // キャンバスの取得 var src1_canvas = document.getElementById("canvas_src1"); var src2_canvas = document.getElementById("canvas_src2"); var dst_canvas = document.getElementById("canvas_dst"); var src1_ctx = src1_canvas.getContext("2d"); var src2_ctx = src2_canvas.getContext("2d"); var dst_ctx = dst_canvas.getContext("2d"); var src1_img = document.getElementById("img_src1"); var src2_img = document.getElementById("img_src2"); var src1 = null; var src2 = null; // イメージが読み込まれた src1_img.addEventListener("load", function () { src1_canvas.width = src1_img.width; src1_canvas.height = src1_img.height; // キャンバスに画像を描画 src1_ctx.drawImage(src1_img,0,0); // イメージデータの取得 src1 = src1_ctx.getImageData(0,0,src1_img.width, src1_img.height); },false); // イメージが読み込まれた src2_img.addEventListener("load", function () { src2_canvas.width = src2_img.width; src2_canvas.height = src2_img.height; // キャンバスに画像を描画 src2_ctx.drawImage(src2_img,0,0); // イメージデータの取得 src2 = src2_ctx.getImageData(0,0,src2_img.width, src2_img.height); },false); // RGBの範囲 function set255(value){ if (value > 255) return 255; if (value < 0) return 0; return value; } function onMouseUp2(){ var height = src1_img.height; var width = src1_img.width; var cnt = 0; document.getElementById('msg_blend').innerHTML = blend_range.value +'/255'; dst_canvas.width = src1_img.width; dst_canvas.height = src1_img.height; var dst = dst_ctx.createImageData(src1_img.width, src1_img.height); var amount = blend_range.value / 255; for (var y = 0; y < height; y++) { for (var x = 0;x < width; x++) { dst.data[(cnt*4)] = set255(Math.round((1 - amount) * src1.data[(cnt*4)] + (amount * src2.data[(cnt*4)]))); dst.data[(cnt*4)+1] = set255(Math.round((1 - amount) * src1.data[(cnt*4)+1] + (amount * src2.data[(cnt*4)+1]))); dst.data[(cnt*4)+2] = set255(Math.round((1 - amount) * src1.data[(cnt*4)+2] + (amount * src2.data[(cnt*4)+2]))); dst.data[(cnt*4)+3] = 255; cnt++; } } // キャンバスに画像を設定 dst_ctx.putImageData(dst,0,0); } </script> </body> </html>
注意事項
Chromeをお使いの方はローカルで実行するとセキュリティエラーが発生します。このエラーを回避するには「Uncaught SecurityErrorのエラー回避方法」をご覧ください。
既知の問題
IEとEdgeではcreateImageData()、getImageData()で取得した画像データ(ImageData)へのアクセスは非常に低速です。ChromeやFireFox並に高速であれば、Javascriptで画像処理がさくさくできるはずなんです。