ちょっと話題の記事

iPhone、Androidで使える!撮ったその場で画像編集できるHTML5アプリを作ってみよう

2012.10.21

先日、iOS6のSafariでFile API、HTML Media Captureを試してみました。
これで写真を撮ってすぐに編集できるWebアプリが作れるのではないかと思い、作ってみることにしました。

以下がサンプルのURLです。撮影して画像を表示した後に編集し保存することができます。
画像処理サンプル

OSとブラウザに関しては

  • iPhone 5(iOS6)のSafariと
  • Galaxy S3(Android 4.04)の標準ブラウザ

で動作確認しました。iOS5系、Android2系ではFile API、HTML Media Captureが使えないので動きません。
PC版Chromeでも試しましたが、ファイルを選択して画像処理できることを確認しました。
他のモバイル用OS、モバイルブラウザに関しては試せないので分かりませんが、
以下のサイトの表でFile APIとHTML Media Captureが使えれば動くかもしれません。
Mobile HTML5 - compatibility on iPhone, Android, Windows Phone, BlackBerry, Symbian and other mobile and tablet devices

それでは順を追ってサンプルの説明をしていきたいと思います。

①撮影、もしくは画像ファイルを選択して表示する

HTML5の Canvas APIFile APIHTML Media Capture を使います。

iPhoneの場合

「ファイルを選択する」ボタンで写真を撮るか、保存してある画像を選択するかを聞かれるので選択します。
撮影後もしくはファイルを選択後、画像をCanvas上に表示するのですが、これが一番大変でした。
imgタグを使って撮影した画像を表示するの問題ありませんでしたが、Canvas上に表示しようとするとサイズと向きがおかしくなります。
サイズに関しての問題を解決してくれるライブラリを以下のサイトで見つけたので使っています。
ソースコードにあるmegapix-image.jsというライブラリです。iPhone以外では普通にCanvasにdrawImageした場合と同じようです。

iOS6でメガピクセル画像をCanvasに描画するとおかしくなってしまう件と、その対処

これでサイズがおかしくなる問題は対処できたのですが、向きの問題は解決できませんでした。
横位置(ホームボタンが右側にある状態)で撮影した場合か、もしくはフォトストリームの画像を読み込めば、正常な向きで表示されます。

Androidの場合

「ファイルを選択する」ボタンを押すとiPhoneと同様に写真を撮るか、保存してある画像を選択するかを聞かれました。
Androidでもハードウェアキーを右側にして横向きで撮影した場合のみ、正常な向きで表示されます。

②画像を編集する

画像の下のボタンを押すと画像にフィルターをかけることができます。
最初はCSS Filter Effectsを使って実現しようと思ったのですが、どうしても編集後の画像を保存できませんでした。
ですのでCanvas上に画像を描画しています。画像編集自体はPIXASTICSというライブラリを使いました。

PIXASTICS
http://www.pixastic.com/

PIXASTICSはサンプルで使った処理以外にも多くの機能があります。
基本的には以下のようにCanvasのインスタンスとエフェクト名、パラメータを引数に渡すだけなので簡単でした。

Pixastic.process([Canvasのインスタンス], [エフェクト名], [パラメータ]);

変更を取り消したい場合はrevertメソッドで戻すことができます。

Pixastic.revert([Canvasのインスタンス]);

ドキュメントのページにはサンプルも付いているので使いやすかったです。
フィルターを複数かけることも可能です。


③編集した保存する。

保存に関してはブラウザの機能を利用します。出力ボタン押すと別のページに遷移するので、編集後の画像をロングタップして下さい。
下の画像のような画面になり保存することができます。

出力ボタンを押した際にiPhoneはすぐ次の画面に遷移しましたが、Androidはかなり重い処理のようで画面遷移するのにかなり時間がかかりました。
サンプルでは画像の幅を320pxで固定していますが、この値を大きくするとAndroidはブラウザがフリーズしてしまうことがありました。

編集後の画像はCanvas APIのtoDataURLメソッドで出力しています。
元画像がJPEG形式だったのでJPEGファイルで出力していますが、AndroidはPNG形式のみサポートしているためPNGファイルになります。

以下がサンプルのソースコードなります。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=2.0">
		<title>画像処理サンプル</title>
		<script src="megapix-image.js"></script>
		<script src="pixastic.custom.js"></script>
		<script>
			
			function change(selector){
				var file = selector.files[0];
				var canvas = document.getElementById("canvas");
				new MegaPixImage(file).render(canvas, { width : 320});
			}
			
			function filter(name){
				var canvas = document.getElementById("canvas");
				if(name == "noise") {
					Pixastic.process(canvas, "noise", {mono:true,amount:1 ,strength:1});
				} else {
					Pixastic.process(canvas, name);
				}
			};
			
			function output(){
				var original = document.getElementById("canvas");
				var newCanvas = document.createElement("canvas");
				
				newCanvas.width = original.width;
				newCanvas.height = original.height;
				var newContext = newCanvas.getContext("2d");
				newContext.drawImage(original, 0, 0, original.width, original.height);
				
				var img = new Image();
				img.src = newCanvas.toDataURL('image/jpeg');
				img.onload = function(){
					location.href = img.src;
				};
			}
			
			function revert() {
				var canvas = document.getElementById("canvas");
				Pixastic.revert(canvas);
			}
		</script>
	</head>    
	<body>
		<div style="background-color:#ddddff;">
			<input type="file" accept="image/*" capture="camera" id="selector" onchange="change(selector)"/>
    	</div>
		<div>
			<canvas id="canvas"/>
		</div>
		<div style="background-color:#ddffdd;">
			<input type="button" value="セピア" onclick="filter('sepia')"/>
			<input type="button" value="ノイズ" onclick="filter('noise')"/>
			<input type="button" value="反転" onclick="filter('solarize')"/>
			<input type="button" value="横反転" onclick="filter('fliph')"/>
    	</div>
		<div style="background-color:#ffdddd;">
			<input type="button" value="出力" onclick="output()"/>
			<input type="button" value="戻す" onclick="revert()"/>
    	</div>
	</body>
</html>

iPhone、Androidもかなり微妙ですが、ある程度やりたいことは実装できました。
CanvasにdrawImageした場合に向きがおかしくなる問題やtoDataURLのパフォーマンスの問題などいくつか課題が残ったので
今後も引き続きモバイルHTML5の調査をしていきたいと思います。

■関連サイト

iOS6のSafariでサポートされるHTML5の機能
HTML5で使えるスマートフォンの機能
スマートフォンサイトのパフォーマンスチューニング