みかづきブログ その3

3ヶ月つづけてみました。

File API で取得した画像ファイルのバイナリデータを出力する

見た目上なにも起こっていませんが、画像ファイルを選択するとconsoleにバイナリデータをしれっと表示するデモです。


DEMO


JavaScript

// forked from kimmy's "File API test" http://jsdo.it/kimmy/ak8Z
(function(win, doc) {
    
    "use strict";
    
    var app = {};
    
    win.app = app;
    
})(this, document);


(function(win, doc, ns) {

    "use strict";

    // inport
    var debug = ns.debug;

    var instance = null;

    function UtilityFunctions() {
        var hasIndexOf    = !![].indexOf,
            hasObjectKeys = !!Object.keys;

        /**
         * 配列のコピー制作を試みます
         * @param  {array} // オリジナル
         * @return {array} // コピー
         */
        function copyArray(array) {
            var newArray = [],
                i = 0;

            try {
                newArray = array.concat([]);
            } catch(e) {
                for (; i < array.length; i++) {
                    newArray.push(array[i]);
                }
            }

            return newArray;
        }

        /**
         * 配列の要素のindexをモダンな感じで返します
         * @param  {array}  // 調査する配列
         * @param           // 調査する要素
         * @return {number} // インデックス
         */
        function indexOf(array, arrayElement) {
            return array.indexOf(arrayElement);
        }

        /**
         * 配列の要素のindexを返します
         * @param  {array}  // 調査する配列
         * @param           // 調査する要素
         * @return {number} // インデックス
         */
        function loopIndexOf(array, arrayElement) {
            var lenght = array.length,
                i      = 0;

             for (; i < lenght; i++) {
                if (array[i] === arrayElement) {
                    return i;
                }
            }

            return -1;
        }

        /**
         *  配列の要素を第1引数に指定して関数をどんどん実行します
         *  @param  {array}    array    // 対象配列
         *  @param  {function} callback // 実行関数
         *  @param  {object}   opt_this // thisに指定する値
         *  @param  {array}    opt_arg  // 第2引数以降を要素に持った配列
         */
        function foreach(array, callback, opt_this, opt_arg) {
            var that     = opt_this || this,
                newArray = copyArray(array),
                length   = newArray.length,
                i        = 0;

            if (!opt_arg) {
                for (; i < length; i++) {
                    callback.call(that, newArray[i], i, newArray);
                }
            } else {
                for (; i < length; i++) {
                    callback.apply(opt_this || newArray[i], [newArray[i]].concat(opt_arg));
                }
            }

            that     = null;
            newArray = null;
        }

        /**
         *  オブジェクトのキーをモダンな感じで配列にして返します。
         *  @param  {object} object // 対象オブジェクト
         *  @return {array}         // キーリスト
         */
        function getObjectKeys(object) {
            return Object.keys(object);
        }

        /**
         *  オブジェクトのキーを配列にして返します。
         *  @param  {object} object // 対象オブジェクト
         *  @return {array}         // キーリスト
         */
        function getKeyList(object) {
            var keyList = [],
                key;

            for (key in object) {
                if (object.hasOwnProperty(key)) {
                    keyList.push(key);
                }
            }

            return keyList;
        }

        return {
            copyArray  : copyArray,
            indexOf    : (hasIndexOf) ? indexOf : loopIndexOf,
            foreach    : foreach,
            getKeyList : (hasObjectKeys) ? getObjectKeys : getKeyList
        };
    }

    // singleton
    UtilityFunctions.getInstance = function() {
        if (!instance) {
            instance = new UtilityFunctions;
        }
        return instance;
    };

    // export
    ns.UtilityFunctions = UtilityFunctions;

})(this, document, app);

(function(win, doc, ns) {

    // inport
    var UtilityFunctions = ns.UtilityFunctions;

    var utilityFunctions = UtilityFunctions.getInstance();

    /**
     *  イベントをもっているか調べます
     *  @param  {string} eventType // イベント名
     */
    function hasEventListener(eventType) {
        return !!this._queue && !!this._queue[eventType];
    }

    /**
     * イベントを追加します
     * @param  {string}   eventType // イベント名
     * @param  {function} callback  // 実行関数
     * @return {object} // メソッドチェーン用オブジェクト
     */
    function addEventListener(eventType, callback) {
        var queue = this._queue || (this._queue = {}),
            length;

        if (hasEventListener.call(this, eventType)) {
            length = (utilityFunctions.copyArray(queue[eventType])).length;

            for (var i = 0; i < length; i++) {
                if (queue[eventType][i] === callback) {
                    return;
                }
            }
            queue[eventType].push(callback);
        } else {
            queue[eventType] = [callback];
        }

        length = null;

        return this;
    }

    /**
     * イベントを削除します
     * @param  {string}   eventType // イベント名
     * @param  {function} callback  // 削除すべき関数
     * @return {object} // メソッドチェーン用オブジェクト
     */
    function removeEventListener(eventType, callback) {
        var queue = this._queue || (this._queue = {}),
            i;

        if (!!hasEventListener.call(this, eventType)) {
            i = (utilityFunctions.copyArray(queue[eventType])).length;

            while (i--) {
                if (queue[eventType][i] === callback) {
                    (function(index) {
                        queue[eventType].splice(index, 1);
                    })(i);
                }
            }
        }

        i = null;

        return this;
    }

    /**
     * イベントを発火します
     * @param  {string} eventType // イベント名
     * @param           opt_arg   // コールバック関数に渡す引数
     */
    function fireEvent(eventType, opt_arg) {
        var queue = this._queue || (this._queue = {}),
            arg   = arguments.length > 1 ? utilityFunctions.copyArray(arguments).splice(1, arguments.length - 1)
                                       : [],
            length;

        if (hasEventListener.call(this, eventType)) {
            length = (utilityFunctions.copyArray(queue[eventType])).length;

            for (var i = 0; i < length; i++) {
                queue[eventType][i].apply(this, arg);
            }
        }

        length = null;
    }

    function EventDispatcher() {}

    EventDispatcher.prototype.hasEventListener    = hasEventListener;
    EventDispatcher.prototype.addEventListener    = addEventListener;
    EventDispatcher.prototype.removeEventListener = removeEventListener;
    EventDispatcher.prototype.fireEvent           = fireEvent;

    // export
    ns.EventDispatcher = EventDispatcher;

})(this, document, app);

(function(win, doc, ns) {

    "use strict";

    // import
    var EventDispatcher = ns.EventDispatcher;
    
    function CameraManager($uploader) {
        var that = this;
        
        EventDispatcher.call(this);
        
        if (!win.File){
            return;
        }

        $uploader.addEventListener("change", handleFileChange, false);

        function handleFileChange() {
            var reader = new FileReader(),
                file   = $uploader.files[0];

            reader.onload = handleReaderLoad;
            reader.readAsArrayBuffer(file);
        }            
        
        function handleReaderLoad(evt) {
            // バイナリデータの表示
            console.log(new Uint8Array(evt.target.result));
        }
    }
    
    CameraManager.prototype = new EventDispatcher();
    
    // Export
    ns.CameraManager = CameraManager;
        
})(this, document, app);


(function(win, doc, ns) {

    "use strict";
 
    // import
    var CameraManager = ns.CameraManager;
      
    var $title        = doc.querySelector("title"),
        $uploader     = doc.getElementById("fileSelecter"),
        $content      = doc.getElementById("content"),
        ctx           = $content.getContext("2d"),
        cameraManager = new CameraManager($uploader);
    
    $title.innerText = "Preview";
    
    cameraManager.addEventListener("LOAD_END", function(_, img) {
        var width  = img.width,
            height = img.height;

        $content.width  = width;
        $content.height = height;
        $content.style.width  = width  / 2 + "px";
        $content.style.height = height / 2 + "px";
        $content.style["margin-left"] = - width / 4 + "px";

        ctx.drawImage(img, 0, 0, width, height);
    });


})(this, document, app);

すごく長いですけど、重要なところを抜粋すると、

$uploader.addEventListener("change", handleFileChange, false);

function handleFileChange() {
    var reader = new FileReader(),
        file   = $uploader.files[0];

    reader.onload = handleReaderLoad;
    reader.readAsArrayBuffer(file);
}            
        
function handleReaderLoad(evt) {
    // バイナリデータの表示
    console.log(new Uint8Array(evt.target.result));
}

こちらの部分です。

readAsArrayBufferにファイルを渡し、そのonloadイベントでUint8Arrayをつくってます。
わかるようなわからないような説明になってしまってますが、挙動を見ながらだと比較的理解しやすい気がします。

今回は以上です。