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でプレビューが出ること、画像以外を選ぶと案内が出ること、読込み失敗時に以前の画像が残らないことを確認します。その後で、送信とサーバー側の検査を別に追加します。
関連記事

