File APIの画像プレビューをちゃんと理解する

File APIが自分的にややこしかったので、画像プレビューに限定して整理しますね。

File APIを使わなくてもできること

以下の項目は普通に取得できます。

  • 更新日時
  • ファイル名
  • データサイズ(バイト数)
  • MIMEタイプ(ファイルの種類)
<!-- ファイル入力のためのinput -->
<input id="inputNode" type="file">

<!-- ここからデータ取得のスクリプト -->
<script src="http://code.jquery.com/jquery.min.js">// jQueryの読み込み</script>
<script>
$( '#inputNode' ).change( function () { // 入力をフックにデータ取得を実行
	// 選択されたファイルはinputノードの"files"配列に格納される
	// ↓任意の変数に選択されたファイルのオブジェクトを格納
	var selectedFile = this.files[0];

	// あとはこのオブジェクトから各データを呼び出せばOK

	// 更新日時:lastModifiedDate
	// 出力例:Fri Dec 14 2012 23:38:54 GMT+0900 (東京 (標準時))
	console.debug( selectedFile.lastModifiedDate );

	// ファイル名:name
	// 出力例:"omoide.jpg"
	console.debug( selectedFile.name );

	// データサイズ:size
	// 出力例:103437
	console.debug( selectedFile.size );

	// MIMEタイプ:type
	// 出力例:"image/jpeg"
	console.debug( selectedFile.type );
} );
</script>

File APIを使った画像プレビューのフロー

  1. FileReaderオブジェクトを生成

  2. FileReaderで画像の読み込み完了を検知

  3. FileReaderで画像データをData URIスキーム化

  4. 取得したData URIスキームをimgタグにセットしてプレビュー

FileReaderオブジェクトがFile APIの心臓。これを生成するとFile APIのいろいろな機能を使うことができます。

Data URIスキームってゆうのは画像を文字列に置き換える技術で、これをそのままimgタグのsrcに入れると画像が見られるというもの。画像はローカルで処理しているから、プレビューしただけならまだサーバーには送られていない状態です。

実際にやったのが下記の例。

<!-- ファイル入力のためのinput -->
<input id="inputNode" type="file">

<!-- プレビュー画像を出力するためのdiv -->
<div id="outputWrapper"></div>

<!-- ここからデータ取得のスクリプト -->
<script src="http://code.jquery.com/jquery.min.js">// jQueryの読み込み</script>
<script>
$( '#inputNode' ).change( function () { // 入力をフックにデータ取得を実行
	var selectedFile = this.files[0];
	// ここまではFile APIを使わない場合と同じ

	// ↓"FileReader"オブジェクトを生成し変数fileReaderに格納
	var fileReader = new FileReader();

	// ↓fileReaderにファイルが読み込まれた後( onload )の動作を定義
	fileReader.onload = function( event ) {
		// ロード時の各種情報はonloadの引数(この場合はevent)に格納される
		// ロードされた画像ファイルのData URIスキームは event.target.result に格納される
		// ↓変数loadedImageUriに格納
		var loadedImageUri = event.target.result;

		// ↓取得した画像ファイルのData URIスキームを元に画像を表示(imgのsrcに指定するだけ!)
		$( '#outputWrapper' ).html( '<img src="' + loadedImageUri + '">' );
	};

	// ↓画像読み込みを実行。"FileReader"の"readAsDataURL"関数を使う
	// 引数はユーザーが入力したファイルのオブジェクト(= selectedFile = this.files[0])
	fileReader.readAsDataURL( selectedFile );
} );
</script>


サンプルとして↓にアップしていますので実際に試してみてください。
サンプルページ

FileReaderのonload時にとれる情報

上記例のfileReader.onload = function( event ) { ~ }でeventとしている変数からとれる情報は主に下記のとおり。

とれる情報 変数 格納されるデータの例
ファイルのデータサイズ event.total 103437
ロード済みのデータサイズ
※ここではonload(ロード完了後)なのでファイルサイズと同じ
event.loaded 103437
FileReaderオブジェクト event.currentTarget
event.target
event.srcElement
※どれも同じオブジェクトが格納される
(FileReaderオブジェクト)


上記event.targetからとれる情報は主に下記のとおり。

とれる情報 変数 格納されるデータの例
エラー内容 event.target.error null
中止時のアクション event.target.onabort null
エラー時のアクション event.target.onerror null
ロード完了時のアクション event.target.onload function (event) { ~ }
ロード完了時(エラー含む)のアクション event.target.onloadend null
ロード開始時のアクション event.target.onloadstart null
ロード進行中のアクション event.target.onprogress null
ロード状況 event.target.readyState 2
※0→未だ
※1→なう
※2→完了
Data URIスキーム化された画像 event.target.result “data:image/png;base64,iVBORw0fdaft…”
※実際はすごい長い文字列