アシアルブログ

アシアルの中の人が技術と想いのたけをつづるブログです

【HTML5】File APIを使って、投稿された画像を即時表示する方法【小ネタ】

こんにちは、橋本です。
今回は小ネタを1つ紹介したいと思います。 画像投稿フォームを作る際に、投稿された画像を即時表示したいなんてことありませんか? そんなときに便利なのが、HTML5で追加されたFile API

File APIを使えば、投稿された画像(正確には、選択されたローカルファイル)の情報を取得することができます。

では、画像投稿機能のサンプルを元に、File APIの使い方を見て行きましょう。
File API自体はjQueryと何の関係もありませんが、いろいろと面倒なので今回もjQueryを使っています。

サンプル


<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
        <title>サンプル</title>
    </head>
    <body>
        <input class="fileInput" type="file" /><br>
        <a href="https://www.asial.co.jp &mode=1" class="popupimg"><img src="https://www.asial.co.jp"></a>
        <script>
            $('.fileInput').change(function(){
                // 1. 選択されたファイルがない場合は何もせずにreturn
                if (!this.files.length) {
                    return;
                }

                var file = this.files[0],            // 2. files配列にファイルが入っています
                    $_img = $(this).siblings('img'), // 3. jQueryのsiblingsメソッドで兄弟のimgを取得
                    fileReader = new FileReader();   // 4. ファイルを読み込むFileReaderオブジェクト

                // 5. 読み込みが完了した際のイベントハンドラ。imgのsrcにデータをセット
                fileReader.onload = function(event) {
                    // 読み込んだデータをimgに設定
                    $_img.attr('src', event.target.result);
                };

                // 6. 画像読み込み
                fileReader.readAsDataURL(file);
            });
        </script>
    </body>
</html>


サンプルのコメントに番号をふっておいたので、番号に沿って説明していきたいと思います。

まず1ですが、ファイルの情報は、input要素のfiles配列にFileオブジェクトとして格納されています。
ですので、input要素のfiles配列のlengthでファイルの選択の有無を確認し、選択されていない場合には処理を終えるよう設定しています。


2は上記で説明したとおり、files配列にファイルが格納されていますので、そこから0番目の要素としてファイルを取得しています。


3は取得したファイルのデータを設定するimgタグを予め変数に格納しています。jQueryオブジェクトだということを明示するために、"$_"プレフィクスをつけています。


4はファイルを読み込むためのFileReaderオブジェクトをインスタンス化し、変数に入れています。これが今回のキモです。

FileReaderオブジェクトはファイルを読み込むためのオブジェクトです。
各種メソッドにFileオブジェクトを渡すことで、非同期でデータの読み込みを行います。
以下の4つのメソッドがあるのですが、よく使うのは最初の2つです。画像に関しては最初の1つでいいと思います。

readAsDataURL(file); // Data URLスキームの形式で読み出す
readAsText(file, encoding); // テキストとして読み出す。エンコーディングを指定可。
readAsBinaryString(file); // バイナリデータとして読みだす。
readAsArrayBuffer(file); // ArrayBufferを返す。詳細不明

5はFileReaderオブジェクトのonloadイベントのイベントハンドラを設定しています。
上記でちょっと触れたんですが、FileReaderオブジェクトのファイルの読み出しは非同期となりますので、イベントハンドラを設定する必要があります。

6でデータの読み込みを開始しています。今回は取得したデータをそのままimgタグのsrcにつっこむので、readAsDataURLメソッドを使用しています。


どうでしょう。非常に簡単ですね。
このサンプルをちょこっといじることで、選択されたファイルをajaxを使って即時サーバに送って保存するといったことも可能になります。



<!DOCTYPE HTML>
<html lang="ja">
    <head>
        <meta charset="UTF-8">
        <script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
        <title>サンプル</title>
    </head>
    <body>
        <input class="fileInput" type="file" /><br>
        <a href="https://www.asial.co.jp &mode=1" class="popupimg"><img src="https://www.asial.co.jp"></a>
        <script>
            $('.fileInput').change(function(){
                // 1. 選択されたファイルがない場合は何もせずにreturn
                if (!this.files.length) {
                    return;
                }

                var file = this.files[0],            // 2. files配列にファイルが入っています
                    $_img = $(this).siblings('img'), // 3. jQueryのsiblingsメソッドで兄弟のimgを取得
                    fileReader = new FileReader();   // 4. ファイルを読み込むFileReaderオブジェクト

                // 5. 読み込みが完了した際のイベントハンドラ。サーバにデータを送信
                fileReader.onload = function(event) {
                    $.ajax({
                        type: 'POST',
                        url: 'http://fairuwookurusa-ba.com',
                        data: {file: event.target.result},
                        success: function(){
                            $_img.attr('src', event.target.result);
                        },
                        error: function(a, b, c){
                            alert('ファイルのアップロードに失敗しました');
                            console.log(a, b, c);
                        }
                    });
                };

                // 6. 画像読み込み
                fileReader.readAsDataURL(file);
            });
        </script>
    </body>
</html>



またまた簡単ですね。サーバに送る際には、readAsBinaryStringメソッドを使って、バイナリとして取得してもいいかもしれませんね。

以上、簡単な小ネタの紹介でした。