スマホ用のクールなアップローダーを作る

##コンセプトは６つ
・簡単にアップロードできる
・クライアントサイドで画像のサムネイルを作る
・複数のファイルをアップロードできる
・画像をソートしてアップロードできる
・スマホの写真が時々回転してしまうので対策しよう
・そのままスマホの写真を複数アップロードできるようにすると
　ファイルサイズがえらいこと（１枚４Ｍ！）になったので
　クライアント側で画像を縮小
・もちろんAjaxでアップロードだ！

こんなアップローダーを作りたいの。でも、きっと夢ね…。

##偉大なるプログラマーに敬意を！

このアップローダーを作るにあたり以下のプログラムを使わせてもらった。

@stomita
megapix-image.js
https://github.com/stomita/ios-imagefile-megapixel

@jseidelin
exif-js
https://github.com/jseidelin/exif-js

@ibnRubaXa
Sortable.js
http://rubaxa.github.io/Sortable/

使い方については以下の解説が役立った。
@wada811
http://wada811.blogspot.com/2014/11/image-upload--preview.html

もちろんキミへの感謝も忘れないよ！
jQuery
http://jquery.com/

```js:index.js
	IMAGES = [];
	function resizeImage(file, no) {
   		var d = new $.Deferred();
	    var mpImg = new MegaPixImage(file);
		var src_keeper = document.getElementById('src_keeper');
	    EXIF.getData(file, function() {
	        var orientation = file.exifdata.Orientation;
	        var mpImg = new MegaPixImage(file);
			mpImg.render(src_keeper, { maxWidth: 1024, orientation: orientation }, function() {
				var resized_img = $(src_keeper).attr('src');
				d.resolve(resized_img, no);
			});
	    });
		return d.promise();
	}

	var sortable;
```

さて、まずはアップローダーの共通コア部分から解説しよう！

・縮小画像のデータを格納するIMAGES
・ソート機能を使うためのsortableをこっそり定義

ここで実現しているのは
・クライアント側での縮小
・EXIF情報を使って画像の回転の修正
の２つ。

画像が完全に読み込まれてから処理をする必要があり、
処理が完全に終わってから次に進むようにする。
$.Deferredの出番だ！

だいたいの部分は上記解説サイトのままだね。

iPhoneは写真の複数選択ができた。
だからHTML部分はこう書いておくよ。

```html:index.html
<input id="file" type="file" multiple accept="image/jpeg, image/gif, image/png">
```

JavaScript部分はこうだ！

```js:index.js
	$('#file').on('change', function() {
		var files_length = this.files.length; 
		for (var i=0; i<files_length; i++) {
			var file = this.files[i];
			resizeImage(file, i).then(function(resize_image, no) {
				var img = $('<img>');
				$(img).css('width', '100px');
				img.attr('id', no);
				img.attr('src', resize_image);
				var canvasData = resize_image.replace(/^data:image\/jpeg;base64,/, '');
				IMAGES.push(canvasData);
				$('#img').append(img);
				// 全ての画像を読み込んだら以下の処理を実行
				if ($('#img').find('img').size() == files_length) {
					if (files_length > 1) {
						sortable = new Sortable(document.getElementById('img'), {
							group: 'photo',
							animation: 150
						});
					}
				}
			});
		};
	});
```

縮小が終わったらIMAGESに入れておく。
全ての画像が読み込まれたらソートできるようにする。
どうしてここの処理で$.Deferredを使わないかって？
おっと、次の説明だ！

```js:index.js
	$('#upload_button').on('click', function() {
		var fd = new FormData();
		$('#img').find('img').each(function() {
			var i = parseInt($(this).attr('id'));
			fd.append('base64_encoded_data[]', IMAGES[i]);
		});
		$.ajax({
			url: '/index.php',
			type: 'POST',
			data: fd,
			processData: false,
			contentType: false,
			dataType: 'json'
		})
		.done(function(data) {
    	});
    });
```

FormDataを使ってフォームデータを動的に作成している。
サーバ側にはbase64エンコードされたデータが渡るってことさ。

##さてAndroid版だ！
なんで上でiPhoneだって前置きをしたかというと
Androidでは写真の複数選択ができなかったんだ（ouch!）
なので１枚ずつ選択していくよ。

HTML部分

```html:index.html
<input class="submit" id="android_file_select" type="button" value="画像を追加">
```

JavaScript部分

```js:index.js
    $('#android_file_select').click(function() {
		var hookInput = $('<input type="file" accept="image/jpeg, image/gif, image/png" name="files[]" style="display:none;">');
		var id = 'i' + parseInt((new Date)/1000);
		hookInput.attr('id', id);
		$('#android_file_upload').append(hookInput);
		$('#'+id).click();
		$(hookInput).on('change', function() {
			var i = IMAGES.length;
			var file = this.files[0];
			resizeImage(file, i).then(function(resize_image, no) {
				var img = $('<img>');
				$(img).css('width', '100px');
				img.attr('id', no);
				img.attr('src', resize_image);
				var canvasData = resize_image.replace(/^data:image\/jpeg;base64,/, '');
				IMAGES.push(canvasData);
				$('#android_img').append(img);
				if (sortable) {
					sortable.destroy();
				}
				sortable = new Sortable(document.getElementById('android_img'), {
					group: 'photo',
					animation: 150
				});
			});
		});
    });
```

上に書いた理由からHTMLとJavaScriptの処理自体は
HTTP_USER_AGENTでiPhoneとAndroidに分けざるを得なかった。
画像に対応するinputを動的に作成しているところ以外は
iPhone版と同じかな。

```js:index.js
    $('#android_upload_button').click(function() {
		var fd = new FormData();
		$('#android_img').find('img').each(function() {
			var i = parseInt($(this).attr('id'));
			fd.append('base64_encoded_data[]', IMAGES[i]);
		});
		$.ajax({
			url: '/index.php',
			type: 'POST',
			data: fd,
			processData: false,
			contentType: false,
			dataType: 'json'
		})
		.done(function(data) {
    	});
    });
```

さぁ、これでクールなアップローダーの完成だ！

今回のこの知識がキミの役に立つといいな。