SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

最新ブラウザ「Internet Explorer10」と「HTML5」のAPI紹介(AD)

IE10で動くHTML5アプリ実装例
「File APIを利用したアプリ」

最新ブラウザ「Internet Explorer10」と「HTML5」のAPI紹介(1)

  • このエントリーをはてなブックマークに追加

 本連載は、「Developers Summit 2012」(デブサミ2012)において、2月16日に行われた日本マイクロソフト株式会社 春日井 良隆氏によるセッション「次期Internet Explorer、IE10とHTML5 API」(セッション資料はこちら)をもとに、Internet Explorer 10の新機能やHTML5 APIとの関連について、3回に分けて特集します。第1回目の今回は、File APIを利用したアプリ作成の方法について解説していきます。

  • このエントリーをはてなブックマークに追加

はじめに

 HTML5とそれに関連するAPIの普及により、「Webのアプリケーションプラットフォーム化」への流れが大きく進んでいます。

 Internet Explorer 10(以下、IE10)では、そうしたHTML5と関連APIの数多くがサポートされています。今回の記事では、IE10が新たにサポートするFile APIを中心に解説していきます。

 File APIとは、今までJavaScriptが直接扱うことが出来なかったローカルファイルに対して、読み取り操作を実現可能にするものです。また、今後の展開としてローカルファイルの書き込みや保存、さらにはWebアプリに専用のファイルシステムをサポートするAPIも、W3Cで標準化作業が進行中です。

※注意

 書き込みについてはFile API: Writerで、ファイルシステムについてはFile API: Directories and Systemという仕様が対応しています。

 余談ですが、IE10ではFile APIだけではなく「BlobBuilder」という、File API: Writerに関する一部の機能もサポートされています。こちらのトピックについては、「BlobBuilder を使ってファイルを作成する」という記事に詳しく解説があります。

 今回は、File APIを解説するための題材として、「MOGUTARO eats files!」というデモンストレーションを取り上げます。このデモはIE Test Drive向けに我々が開発したもので、2012年2月16日に開催されたDevelopers Summit 2012においても、「次期Internet Explorer、IE10とHTML5 API」というセッションで紹介されました。

デモの説明

 このデモンストレーションは、ファイルを任意の要素(くじらの口)にドラッグ&ドロップすることでファイルを読み込むことができ、そのファイル形式によって異なる様々な動作をします。

 対象となるファイル形式と動作は以下の4つです。

  • テキストファイル:1行ごとにテキストファイルを読み上げる
  • 画像ファイル:画像の色を解析をして虹を表示後、canvas上に表示する
  • 動画ファイル:動画再生する
  • 音楽ファイル:音楽再生する

 このデモンストレーションのソースコードは、こちらからダウンロードすることができます。

※注意

 以下、掲載するコードはjQueryを利用しています。アニメーションについてはTween.jsをというJavaScriptライブラリを利用していますが本記事ではこちらについての説明は割愛します。

ドラッグ&ドロップ

 File APIを使って任意のローカルファイルを読むためには、ユーザが明示的にWebアプリケーションに対してファイルを「読み込ませる」というアクションが必要になります。

 現在それらのアクションは、ファイル選択フォーム(<input type="file">)を用いるか、ドラッグ&ドロップを受け付けるか、の2つに限られています。このデモンストレーションでは、くじら(MOGUTARO)の大きく開いた口に対して、ファイルをドラッグ&ドロップすることができます。

 以下に示すのは、ファイルをドラッグ&ドロップによって受け取るためのコードを簡略化したものです。

 dragenter・dragover・dropのイベントを制御することで実現しています。dragenter、dragoverでは、デフォルトのイベント処理をキャンセルしています。これは、デフォルトではブラウザはドラッグ&ドロップを受け付け「ない」ため、そのデフォルト操作をキャンセルする必要があるためです。ondropイベントの処理において、ファイルの読み込みとそれに続く処理を実現しています。

$("#mouthOfWhale")
    .on("dragenter", function(e) {  // dragenter時 の ネイティブイベント無効化
        e.preventDefault();
    })
    .on("dragover", function(e) {   // dragover時 の ネイティブイベント無効化
        e.preventDefault();
    })
    .on("drop", function(e) {   // drop時 の イベントのバブリング無効化
        e.stopPropagation();
        
        /*
            ondropイベントのコールバック
            ファイル形式の振り分け
        */
        
    });

ファイル形式の振り分け

 ドラッグ&ドロップされたファイルはondropイベントから取得できます。さらに取得したファイルからファイルタイプを取得します。ファイル形式の振り分けには、このファイルタイプから判定、処理分岐させています。

 なお、jQueryを使用しているため、e.originalEvent.dataTransfer.filesから取得しています(jQueryは、独自のイベントオブジェクトでオリジナルのイベントをラップするためです)が、ネイティブのコードの場合は、e.dataTransfer.filesからの取得となるのでご注意ください。

    // e.originalEvent.dataTransfer.files に対象のファイル(FileList)がセットされる
    var files = e.originalEvent.dataTransfer.files;
    // FileListからFileを取得する
    var file = files[0] || null;
    // ファイルタイプを取得する
    var fileType = (file && file.type)? file.type: '';

    // テキストファイル判定
    if (fileType.indexOf('text/') === 0) {
        processTextFile(file);
    }
    // 画像ファイル判定
    else if (fileType.indexOf('image/') === 0) {
        processImageFile(file);
    }
    // 動画ファイル判定
    else if (fileType.indexOf('video/') === 0 &&
        /probably|maybe/.test($('#tv')[0].canPlayType(fileType))) {
            processVideoFile(file);
    }
    // 音楽ファイル判定
    else if (fileType.indexOf('audio/') === 0 &&
        /probably|maybe/.test($('#audioPlayer')[0].canPlayType(fileType))) {
            processAudioFile(file);
    }
    // etc file
    else {
        processOtherFile(file);
    }

canPlayType(type)による判定

 上のコードで使用しているcanPlayType(type)は、各ブラウザがそのメディアファイルを再生することができるかどうかを判定します。再生可能な場合は「probably」、再生できると確証を得られない場合は、「maybe」、再生不可の場合は「''」がリターンされます。

 メディア要素を扱う際には、ブラウザがどのフォーマットのファイルをを再生できるかというのも注意が必要です。IE10の場合、音楽ファイルであれば MP3 や AAC、動画ファイルであれば H.264形式でエンコードされたMPEGファイルが再生可能です。

FileReaderの機能

 FileReaderとは、名前の通りファイルを読み込むためのAPIで、以下のメソッドを利用できます。

  • readAsArrayBuffer(file)・・・ファイルを読み取った結果をArrayBuffer(型付き配列)の形式で保持します。
  • readAsBinaryString(file)・・・ファイルを読み取った結果をString型で保持します。ファイルから読み取った内容(バイト配列)を、Stringのインターフェースを通じてアクセス可能にしているだけなので、結果をテキストとして扱うことはできません。
  • readAsText(file, encode)・・・テキストファイルを読み取った結果をString型で保持します。ファイルの文字コードを指定することができます。
  • readAsDataURL(file)・・・ファイルを読み取った結果をData URL形式の文字列で保持します。
  • abort()・・・ファイルの読み込み処理を中断します。

 このサンプルでは、テキストファイルを読み込む際に readAsText(file, encode)、画像ファイルを読み込む際にはreadAsDataURL(file) を利用しています。

 FileReaderのreadAs...()メソッドは非同期で実行されます。実行結果はFileReader.resultというプロパティに各メソッドの形式でセットされます。

 以下、テキストファイルを読み込む際のコードです。reader.result にはテキストファイル形式でデータがセットされます。

var reader = new FileReader();
reader.onload = function() {
    // reader.result にテキスト形式でデータでセットされている
    var result = reader.result;
    
    // 1行ずつ読み上げる
}
reader.readAsText(file, 'UTF-8');

 次は、画像ファイルの読み込みです。

var reader = new FileReader();
reader.onload = function() {
    var result = reader.result;
    
    // 画像の色を解析をして虹を表示後、canvas上に表示する
}
reader.readAsText(file, encode);

 記述の仕方自体は同じですが、reader.resultにセットされるファイル形式が[Data URL]になります。そのため、 tmpImg.src = reader.result のように受け渡すことができるようになり、画像の加工やcanvasへの反映を実現可能にしています。

var reader = new FileReader();
reader.onload = function() {
    var result = reader.result;
    
    // 画像の色を解析をして虹を表示後、canvas上に表示する
    var tmpImg = document.createElement('img');
    tmpImg.src = reader.result;
    tmpImg.onload = function() {
        
        // 読み込んだ画像を加工して、canvas上に表示する
        var drawCanvas = $('#pict');
        var canvasWidth = drawCanvas.attr('width'), canvasHeight = drawCanvas.attr('height');
        var canvasProp = calcCanvasPosition(tmpImg.naturalWidth, tmpImg.naturalHeight, canvasWidth, canvasHeight);
        var pictCtx = drawCanvas[0].getContext('2d');
        pictCtx.clearRect(0, 0, canvasWidth, canvasHeight);
        ・・・
    }
}

reader.readAsDataURL(file);

window.URL.createObjectURL(file)

 FileReader.readAsDataURL()は対象データを全てメモリ上に保持するため、メディアファイルのようにファイルサイズが大きいものには向いていません。ファイルの内容を全てメモリに読み込むことなく、ローカルのメディアデータをvideo要素やaudio要素、img要素を使用して処理するには、URL.createObjectURL()というメソッドが役に立ちます。

 URL.createObjectURL()は、引数として渡されたファイルに対する参照を表すURL文字列を生成するメソッドです(実際はファイルに限らず、Blobと呼ばれるオブジェクトの全てに対してこのメソッドを呼び出すことができます)。

 生成されるURLは、Blob URIという形式に則り、「blob:」で始まる短い文字列となります。

 下記のコードは音楽ファイルの再生箇所の抜粋です。

function processAudioFile(file) {
    var audio = $('#audioPlayer')[0];
    var audioData = URL.createObjectURL(file);
    // 音楽ファイルURLのセット
    audio.src = audioData;
    // 音楽再生
    audio.play();
}

 動画ファイルも同様に扱えます。こちらは再生ボタン・停止ボタンのイベントを登録しています。

function processVideoFile(file) {
    var tv = $('#tv');
    var videoData = URL.createObjectURL(file);
    // 動画ファイルURLのセット
    tv.attr('src', videoData).show();
    
    pauseFunc = function() {
        tv[0].pause();
    };
    
    // リモコンの再生ボタンで動画再生
    $('#moviePlay').on('click', function(){
        tv[0].play();
    });
    // リモコンの停止ボタンで動画停止
    $('#movieStop').on('click', function(){
        pauseFunc();
    });
    // 動画終了時
    tv.on('ended', function(){
        pauseFunc();
    });
}

まとめ

 File APIにより、「JavaScriptでファイルの内容を読み取る」というこれまで不可能とされてきた事柄を容易に実現できるようになりました。この一点だけでも、Webアプリケーションでの大きなイノベーションの予感を感じさせるAPIだといっても過言ではないでしょう。

 また、冒頭でもお伝えしましたが、今後はローカルファイルへの書き出しやファイルシステムの取り扱いも視野に入れて仕様が検討されています。これらのAPIが実装された暁には、デスクトップアプリケーションと比べても機能的に全く劣ることがないような、さらに高度なWebアプリケーションの実現が期待できると言って良いでしょう。

この記事は参考になりましたか?

  • このエントリーをはてなブックマークに追加

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/6500 2012/04/18 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング