canvasで描いた絵をバイナリ形式でサーバーにPOST送信する方法

最近、自宅で時間ができるとHTML5 テクニックバイブルという本を読んでいるのですが、初めて知ったことがいろいろ書いてあって驚愕する日々を送っています。

今回は上記書籍を読んで知ったCanvasで描いた絵を、Base64のData URI形式ではなく、バイナリ形式にしてPOST送信する方法のメモ。ただし、IE9では使えないよう。

まずは、受け取り側のPHPを記述。普通にフォームの画像ファイルを受け取ってサーバーにファイルを保存するような記述を書いておきます。ファイルのアップロード | PHP Laboを参考にしました。

<?php
if (is_uploaded_file($_FILES["acceptImage"]["tmp_name"])) {
  if (move_uploaded_file($_FILES["acceptImage"]["tmp_name"], 'test.png')) {
    echo "アップロードしました。<br>";
	echo $_FILES["acceptImage"]["tmp_name"];
  } else {
    echo "ファイルをアップロードできません。";
  }
} else {
  echo "ファイルが選択されていません。";
}
?>

上記のPHPでは、acceptImageというプロパティに対応するファイルをtest.pngという名前で保存するようにしたPHPです。試しに、下記のようなHTMLを書いて普通にファイル選択してPOSTするとうまく動きました。

<form action="image-accept2.php" method="post" enctype="multipart/form-data">
  ファイル:<br />
  <input type="file" name="acceptImage" size="30" /><br />
  <br />
  <input type="submit" value="アップロード" />
</form>

というわけでつづいて、前に作ったCanvasお絵描きツールの投稿先を、上記PHPに変更し、JavaScriptでCanvasのデータをPOST渡しできるよう記述するように投稿ボタンを押した時の処理を下記のようにしてみました。

$('#posting').click(function(){
	
	// バイナリ化した画像をPOSTで送る関数
	var sendImageBinary = function(blob) {
		var formData = new FormData();
		formData.append('acceptImage', blob);
		
		$.ajax({
			type: 'POST',
			url: 'image-accept2.php',
			data: formData,
			contentType: false,
			processData: false,
			success:function(date, dataType){
				//console.log("succcess");
				//console.log(data);
				var $img = $('img');
				var imgSrc = $img.attr('src');
				$img.attr('src', "");
				$img.attr('src', imgSrc);
			},
			error: function(XMLHttpRequest, textStatus, errorThrown){
				//console.log("error");
			}
		});
	};
	
	
	canvas = $('#mycanvas')[0].toDataURL();
	var base64Data = canvas.split(',')[1], // Data URLからBase64のデータ部分のみを取得
		data = window.atob(base64Data), // base64形式の文字列をデコード
		buff = new ArrayBuffer(data.length),
		arr = new Uint8Array(buff),
		blob, i, dataLen;
	
	// blobの生成
	for( i = 0, dataLen = data.length; i < dataLen; i++){
		arr[i] = data.charCodeAt(i);
	}
	blob = new Blob([arr], {type: 'image/png'});
	sendImageBinary(blob);
});

実行サンプル:canvasを使ったお絵描き投稿システム

HTML5 テクニックバイブルのほうでは、jQueryを使わずに純粋にXMLHttpRequestオブジェクトを使ってAjax送信しているコードが載っていたのですが、自分は最近Ajaxを使う時はjQueryを使うことにしてるので、jQueryを使って書いてみました。実はjQueryを使ったAajxでは最初うまく動かなかったのですが、調べてみるとjQueryでFormDataオブジェクトをAjaxで送信する場合には、contentTypeとprocessDataをfalseにしなければいけないと分かり、そのオプションを変更することによってうまく動きました(参考:jQuery: FormData オブジェクトで送信する - Sarabande.jp)。
HTML5テクニックバイブルに載っているコードでは、そんな記述が必要ない分、もう少しシンプルな記述となっています。

それにしても、上記コードは自分が初めて知ることがたくさんあります。FormDataオブジェクトぐらいなら聞いたことはあったのですが、BlobオブジェクトとかArrayBufferオブジェクトとかUint8Arrayオブジェクトとか、何だそれ!? という思いです。簡単に説明すると、BlobオブジェクトはMIMEタイプを含んだバイナリデータを表し、ArrayBufferオブジェクトは固定長のバイナリデータを表し、Uint8Arrayは8ビットの符号なし整数を表すようです。なお、Uint8Arrayの説明には、C言語での同等タイプに『uint8_t』という記述が。そんなデータ型がC言語にあったか? と思って調べてみると、どうやら『unsinged char』と同じらしいです(参考:整数型 - Wikipedia)。

HTML5はある程度知っているつもりでいましたが、まだまだ知らないことが多くありそうです。

ところで、Blobオブジェクトの取得については、canvasオブジェクトにtoBlobメソッドが実装されていれば、そのメソッドを使うことにより、簡単に取得できるようです。ただ、このメソッドは残念ながら、Firefoxでしか実装されていないよう。html5.jpによると、2011年4月5日の草案にはすでに提案されていたようなんですが・・・(参考:W3C - 『HTML 5 differences from HTML 4』日本語訳 - HTML5.JP)。Chromeですら実装してないとなると、さすがに使うのに躊躇します。

コメント

タイトルとURLをコピーしました