• FileReader.readAsDataURL()で選択した画像を送信前にプレビューする

FileReader.readAsDataURL()で選択した画像を送信前にプレビューする

公開日: 執筆:佐藤

input type="file"で選択した画像は、FileReader.readAsDataURL()で読み、送信前にimg要素へ表示できます。選択したFileを読み終えたら、loadイベントでresultを受け取り、img要素のsrcへ設定します。

この処理はブラウザー内のプレビューです。画像をサーバーへアップロードしたことにはなりません。ファイル形式とサイズの最終判定も、送信を受けるサーバー側で別に行います。

input type=fileから最初のFileを取り出す

input type="file"のfilesは、選択されたFileを持つFileListです。単一ファイルの入力欄なら、files[0]から選択した画像を取得します。

次は説明用の仮例です。JPEG、PNG、GIFのいずれかを一枚選び、直下のimg要素へ表示します。

<label for="preview-file">画像を選択</label>
<input
	type="file"
	id="preview-file"
	accept="image/jpeg,image/png,image/gif"
>
<p id="preview-message"></p>
<img id="preview-image" alt="">

accept属性は、選択画面で受け付ける種類を示すために使います。ただし、これだけでファイルの内容を保証できるとは考えません。

readAsDataURL()のloadでresultをimgへ渡す

JavaScriptでは、ファイルの選択が変わるたびに、FileListの有無、ファイルの種類、読込み結果を順に確認します。

(function () {
	var input = document.getElementById('preview-file');
	var preview = document.getElementById('preview-image');
	var message = document.getElementById('preview-message');
	var allowedTypes = {
		'image/jpeg': true,
		'image/png': true,
		'image/gif': true
	};

	input.addEventListener('change', function () {
		var file;
		var reader;

		preview.removeAttribute('src');
		preview.alt = '';
		message.textContent = '';

		if (!input.files || input.files.length === 0) {
			return;
		}

		file = input.files[0];

		if (!allowedTypes[file.type]) {
			message.textContent = 'JPEG、PNG、GIFの画像を選択してください。';
			return;
		}

		reader = new FileReader();

		reader.onload = function () {
			preview.src = reader.result;
			preview.alt = '選択した画像のプレビュー';
		};

		reader.onerror = function () {
			message.textContent = '画像を読み込めませんでした。';
		};

		reader.readAsDataURL(file);
	}, false);
}());

readAsDataURL()でFileまたはBlobを非同期で読むと、完了後のresultにファイル全体を表すData URLが入ります。コードは、その文字列をimg.srcへ渡します。

読込みに失敗した場合はerrorイベントが発生し、resultはnullになります。成功時のloadと失敗時のerrorを分ければ、空のプレビューと読込み失敗を同じ状態にしません。

プレビューとアップロードは別の処理にする

このコードには、フォーム送信もXMLHttpRequestもありません。readAsDataURL()が終わっても、画像データはブラウザーで読み込まれただけです。

アップロードを加える場合は、送信処理を別に設計します。プレビューが表示できたことを、サーバーが保存を受け付けたことや、公開に使える画像だという承認に置き換えません。

役割を分けると、確認箇所も明確になります。

処理 実行する場所 判断できること
ファイル選択 ブラウザー 利用者が選んだFileがあるか
プレビュー ブラウザーのFileReader ファイルをData URLとして読めたか
アップロード ブラウザーとサーバーの通信 サーバーへデータが届いたか
形式とサイズの受入れ サーバー 保存を許可する内容か

typeとsizeは画面案内に使いサーバーでも確かめる

Fileにはtypeとsizeがあります。ブラウザー側では、種類が選択条件と合わない場合や、大きすぎる画像を選んだ場合に、送信前の案内を出せます。

ただし、ブラウザーから送られるtype、ファイル名、サイズだけを信頼して保存可否を決めません。サーバー側で受信サイズを制限し、実際の内容から画像形式を確かめ、保存場所と公開可否を判断します。

大きな画像は、readAsDataURL()によって全体がメモリーへ読み込まれます。必要以上に大きなファイルをプレビュー対象にしないよう、入力画面の案内とブラウザー側の上限を用意します。ただし、ブラウザー側の上限は利用者への早い案内であり、サーバー側の制限の代わりにはなりません。

最初の一手は、アップロード処理を加えることではありません。小さなJPEGを一枚選び、loadでプレビューが出ること、画像以外を選ぶと案内が出ること、読込み失敗時に以前の画像が残らないことを確認します。その後で、送信とサーバー側の検査を別に追加します。

戻る