Canvasによる画像ファイル(img要素)の読み書き

Canvas要素には、img要素との間で読み書きを行う、つまりimg要素の内容をCanvasに読み込んだり、Canvasの画像をimg要素に書き出す機能があります。Canvasからの書き出しは「pngなど画像ファイルデータ形式の文字列」を介して行うため、Canvasの内容を文字列として取得する(サーバーやWebブラウザのローカルストレージに保存する)ことも可能です。

今回は、画像ファイルをimg要素に表示し、それをCanvasに転送、Canvasで簡単な画像処理を行ってまたimg要素に書き戻すテストをしてみましょう。これにより「JavaScriptで画像処理を行いその結果を出力する」流れを確認してみることにします。

まず、img要素の内容をCanvasに転送するには、CanvasコンテキストのdrawImage()を使います。drawImage()で描画位置(や描画範囲)を指定すれば、Canvasに描画が行われます。

Canvasにimgの内容が描画されれば、後はImageDataを作成して適当に書き換えましょう。

Canvasの描画内容の出力には、toDataURL()を使います。これは名前のとおりURL形式の文字列としてCanvasの画像データ(デフォルトではpng、ブラウザによってはオプション指定でjpgなど他形式での出力も可能)を取得するものです。この文字列をimg要素のsrc属性に指定してやると、その画像をimg要素に反映することができます。

さっそく、imgとCanvasの間の画像のやり取りを試してみることにしましょう。

今回は、200*200ピクセルのimg要素とCanvas要素、それにテキスト領域を用意しました。まず、img要素に適当な画像ファイルを表示し、「転送→」ボタンで隣のCanvas要素に画像を転送します。

そして、Canvas要素に読み込んだ画像を「反転」ボタンで上下反転させられるようにしました。

画像の読み込みと反転を行ったら、「URL出力」ボタンで下のテキスト領域にtoDataURL()メソッドで出力される文字列を転送し、どんな文字列になっているのか見てみましょう。最後に、「URL設定」ボタンで文字列をimg要素のsrcに設定し、画像が切り替わることを確認します。

テスト用のHTMLとJavaScriptは、以下のとおりです。同じディレクトリにcanvas_image.jpgという画像ファイルが存在することを前提にしています。

<table>
<tr>
<td><img id="testImage" src="canvas_image.jpg" width="200" height="200"></td>
<td><canvas id="testCanvas" width="200" height="200" style="background: #000080;"></canvas></td>
</tr>
<tr>
<td style="text-align: center;"><button id="putImageToCanvas" onClick="putImageToCanvas()" disabled="disabled">転送→</button></td>
<td style="text-align: center;"><button id="canvasUpset" onClick="canvasUpset()"  disabled="disabled">反転</button> <button id="toDataURL" onClick="toDataURL()"  disabled="disabled">URL出力</button></td>
</tr>
<tr>
<td colspan="2" style="text-align: center;"><textarea id="testText" rows="6"></textarea></td>
</tr>
<tr>
<td colspan="2" style="text-align: center;"><button id="setURLtoImage" onClick="setURLtoImage()"  disabled="disabled">URL設定</button></td>
</tr>
</table>

<script type="text/javascript">

	var testImage = document.getElementById('testImage');

	var testCanvas = document.getElementById('testCanvas');
	var testContext;

	var testText = document.getElementById('testText');

	// CanvasとImageDataが利用可能ならボタン有効化
	if (testCanvas.getContext && testCanvas.getContext('2d').createImageData) {

		document.getElementById('putImageToCanvas').disabled = false;
		document.getElementById('canvasUpset').disabled = false;
		document.getElementById('toDataURL').disabled = false;
		document.getElementById('setURLtoImage').disabled = false;

		testContext = testCanvas.getContext('2d');

	}

	// img要素からCanvasに画像を転送
	function putImageToCanvas() {
		testContext.drawImage(testImage, 0, 0);
	}

	// 上下反転
	function canvasUpset() {

		var canvasImageData = testContext.getImageData(0, 0, testCanvas.width, testCanvas.height);
		var canvasRGBA = canvasImageData.data;
		var newImageData = testContext.createImageData(testCanvas.width, testCanvas.height);
		var newRGBA = newImageData.data;

		// Canvasのピクセル情報を上下反転させながらコピー
		for (i = 0;i < testCanvas.height;i++) {
			for (j = 0;j < testCanvas.width;j++) {

				newRGBA[(j * 4) + ((testCanvas.height - 1 - i) * testCanvas.width * 4)] = canvasRGBA[(j * 4) + (i * testCanvas.width * 4)];
				newRGBA[1 + (j * 4) + ((testCanvas.height - 1 - i) * testCanvas.width * 4)] = canvasRGBA[1 + (j * 4) + (i * testCanvas.width * 4)];
				newRGBA[2 + (j * 4) + ((testCanvas.height - 1 - i) * testCanvas.width * 4)] = canvasRGBA[2 + (j * 4) + (i * testCanvas.width * 4)];
				newRGBA[3 + (j * 4) + ((testCanvas.height - 1 - i) * testCanvas.width * 4)] = canvasRGBA[3 + (j * 4) + (i * testCanvas.width * 4)];

			}
		}

		// コピーしたピクセル情報をCanvasに転送
		testContext.putImageData(newImageData, 0, 0);

	}

	// Canvasの画像をURL(png文字列)化
	function toDataURL() {
		testText.value = testCanvas.toDataURL();
	}

	// URLの画像をimg要素に設定
	function setURLtoImage() {
		testImage.src = testText.value;
	}

</script>

これで、img(画像ファイル)の画像をCanvasに設定しCanvas内でJavaScriptによる画像処理を行って、その結果を「保存やimg要素への設定が可能な文字列」として取得することができるようになりました。Webベースの画像処理アプリケーション開発に活用できそうですね。

ただし、Canvasに読み込んだ画像は、セキュリティの制約で条件(ローカルでの実行や他ドメインの画像ファイルなど)によってはImageDataの作成やURL化ができないこともあります。


創作プログラミングの街