IndexedDB に画像とファイルを格納する
原文: Storing images and files in IndexedDB (on February 23, 2012 by Robert Nyman)
以前、私たちは localStrage に画像とファイルを保存 する方法について書きましたが、それは、今日でも利用できる実用的な方法でした。しかし、この方法には localStrage と密接に関わるパフォーマンスの問題 (このブログの後半で扱います) がいくつもあるため、IndexedDB を活用することが将来のアプローチ方法として望まれます。ここでは、IndexedDB に画像とファイルを格納し、ObjectURL を通して提供する方法をお教えします。
一般的なアプローチ
はじめに、手順について話しましょう。IndexedDB データベースを作成し、ファイルをそのデータベースに保存し、そのデータをページに読み出して提供します:
- データベースを作成するか開く
- objectStore を作成する (まだ存在しなければ)
- 画像ファイルを blob として取り込む
- データベースのトランザクションを初期化する
- その blob をデータベースに保存する
- 保存したファイルを読み出し、そのデータから ObjectURL を作成してページ内の画像要素の src にセットする
コードを書く
それでは、これらのことを行うのに必要なコードのすべての部分を分析しましょう:
データベースを作成するか開く
| // IndexedDB | |
| window.indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB, | |
| IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction, | |
| dbVersion = 1; | |
| /* | |
| Note: The recommended way to do this is assigning it to window.indexedDB, | |
| to avoid potential issues in the global scope when web browsers start | |
| removing prefixes in their implementations. | |
| You can assign it to a varible, like var indexedDB… but then you have | |
| to make sure that the code is contained within a function. | |
| */ | |
| // Create/open database | |
| var request = indexedDB.open("elephantFiles", dbVersion); | |
| request.onsuccess = function (event) { | |
| console.log("Success creating/accessing IndexedDB database"); | |
| db = request.result; | |
| db.onerror = function (event) { | |
| console.log("Error creating/accessing IndexedDB database"); | |
| }; | |
| // Interim solution for Google Chrome to create an objectStore. Will be deprecated | |
| if (db.setVersion) { | |
| if (db.version != dbVersion) { | |
| var setVersion = db.setVersion(dbVersion); | |
| setVersion.onsuccess = function () { | |
| createObjectStore(db); | |
| getImageFile(); | |
| }; | |
| } | |
| else { | |
| getImageFile(); | |
| } | |
| } | |
| else { | |
| getImageFile(); | |
| } | |
| } | |
| // For future use. Currently only in latest Firefox versions | |
| request.onupgradeneeded = function (event) { | |
| createObjectStore(event.target.result); | |
| }; |
このコードは、データベースが作成された時あるいは高いバージョン番号を取得して onupgradeneeded イベントを起こすために使うことを意図しています。これは現在、Firefox でのみサポートされていますが、他の Web ブラウザでも間もなくサポートされるでしょう。Web ブラウザがこのイベントをサポートしていなくても、非推奨の setVersion メソッドを使用してこのコードのonsuccess イベントに接続できます。
objectStore を作成する (まだ存在しなければ)
| // Create an objectStore | |
| console.log("Creating objectStore") | |
| dataBase.createObjectStore("elephants"); |
ここでは、あなたのデータ (ファイル) を格納する ObjectStore を作成します。一度作成したら再び作成する必要はありません。そのコンテンツを更新するだけです。
画像ファイルを blob として取り込む
| // Create XHR | |
| var xhr = new XMLHttpRequest(), | |
| blob; | |
| xhr.open("GET", "elephant.png", true); | |
| // Set the responseType to blob | |
| xhr.responseType = "blob"; | |
| xhr.addEventListener("load", function () { | |
| if (xhr.status === 200) { | |
| console.log("Image retrieved"); | |
| // File as response | |
| blob = xhr.response; | |
| // Put the received blob into IndexedDB | |
| putElephantInDb(blob); | |
| } | |
| }, false); | |
| // Send XHR | |
| xhr.send(); |
このコードは、ファイルのコンテンツを blob として直接取得します。現在は Firefox でのみサポートされています。
一度、ファイル全体を取り込んだら、この blob をデータベースに格納する関数に送信します。
データベースのトランザクションを初期化する
| // Open a transaction to the database | |
| var transaction = db.transaction(["elephants"], IDBTransaction.READ_WRITE); |
データベースへの書き込みを開始するには、トランザクションを objectStore の名前と行いたい操作の種類で初期化する必要があります。この場合は読み込み (read) と書き込み (write)です。
その blob をデータベースに保存する
| // Put the blob into the dabase | |
| transaction.objectStore("elephants").put(blob, "image"); |
トランザクションを準備したら、お望みの objectStore への参照を取得し、あなたの blob をその objectStore に置き、キーを与えます。
保存したファイルを読み出し、そのデータから ObjectURL を作成してページ内の画像要素の src にセットする
| // Retrieve the file that was just stored | |
| transaction.objectStore("elephants").get("image").onsuccess = function (event) { | |
| var imgFile = event.target.result; | |
| console.log("Got elephant!" + imgFile); | |
| // Get window.URL object | |
| var URL = window.URL || window.webkitURL; | |
| // Create and revoke ObjectURL | |
| var imgURL = URL.createObjectURL(imgFile); | |
| // Set img src to ObjectURL | |
| var imgElephant = document.getElementById("elephant"); | |
| imgElephant.setAttribute("src", imgURL); | |
| // Revoking ObjectURL | |
| URL.revokeObjectURL(imgURL); | |
| }; |
同じトランザクションを使用してあなたが格納した画像ファイルを取得し、objectURL を作成してそれをページ内の画像の src にセットします。
これは、例えば、script 要素に JavaScript ファイルを指定し、その JavaScript が解析されるのと全く同じことです。
完成したコード
それでは、完全に動作するコードを見てみましょう:
| (function () { | |
| // IndexedDB | |
| var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.OIndexedDB || window.msIndexedDB, | |
| IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.OIDBTransaction || window.msIDBTransaction, | |
| dbVersion = 1.0; | |
| // Create/open database | |
| var request = indexedDB.open("elephantFiles", dbVersion), | |
| db, | |
| createObjectStore = function (dataBase) { | |
| // Create an objectStore | |
| console.log("Creating objectStore") | |
| dataBase.createObjectStore("elephants"); | |
| }, | |
| getImageFile = function () { | |
| // Create XHR | |
| var xhr = new XMLHttpRequest(), | |
| blob; | |
| xhr.open("GET", "elephant.png", true); | |
| // Set the responseType to blob | |
| xhr.responseType = "blob"; | |
| xhr.addEventListener("load", function () { | |
| if (xhr.status === 200) { | |
| console.log("Image retrieved"); | |
| // Blob as response | |
| blob = xhr.response; | |
| console.log("Blob:" + blob); | |
| // Put the received blob into IndexedDB | |
| putElephantInDb(blob); | |
| } | |
| }, false); | |
| // Send XHR | |
| xhr.send(); | |
| }, | |
| putElephantInDb = function (blob) { | |
| console.log("Putting elephants in IndexedDB"); | |
| // Open a transaction to the database | |
| var transaction = db.transaction(["elephants"], IDBTransaction.READ_WRITE); | |
| // Put the blob into the dabase | |
| var put = transaction.objectStore("elephants").put(blob, "image"); | |
| // Retrieve the file that was just stored | |
| transaction.objectStore("elephants").get("image").onsuccess = function (event) { | |
| var imgFile = event.target.result; | |
| console.log("Got elephant!" + imgFile); | |
| // Get window.URL object | |
| var URL = window.URL || window.webkitURL; | |
| // Create and revoke ObjectURL | |
| var imgURL = URL.createObjectURL(imgFile); | |
| // Set img src to ObjectURL | |
| var imgElephant = document.getElementById("elephant"); | |
| imgElephant.setAttribute("src", imgURL); | |
| // Revoking ObjectURL | |
| URL.revokeObjectURL(imgURL); | |
| }; | |
| }; | |
| request.onerror = function (event) { | |
| console.log("Error creating/accessing IndexedDB database"); | |
| }; | |
| request.onsuccess = function (event) { | |
| console.log("Success creating/accessing IndexedDB database"); | |
| db = request.result; | |
| db.onerror = function (event) { | |
| console.log("Error creating/accessing IndexedDB database"); | |
| }; | |
| // Interim solution for Google Chrome to create an objectStore. Will be deprecated | |
| if (db.setVersion) { | |
| if (db.version != dbVersion) { | |
| var setVersion = db.setVersion(dbVersion); | |
| setVersion.onsuccess = function () { | |
| createObjectStore(db); | |
| getImageFile(); | |
| }; | |
| } | |
| else { | |
| getImageFile(); | |
| } | |
| } | |
| else { | |
| getImageFile(); | |
| } | |
| } | |
| // For future use. Currently only in latest Firefox versions | |
| request.onupgradeneeded = function (event) { | |
| createObjectStore(event.target.result); | |
| }; | |
| })(); |
Web ブラウザのサポート
- IndexedDB
- Firefox と Google Chrome では、古いバージョンから長い間サポートされています。IE10 と将来のバージョンの Opera でサポートが計画されています。Safari については不明です。
- onupgradeneeded
- 最新バージョンの Firefox でサポートされています。Google Chrome で間もなくサポートされ、IE10 と将来のバージョンの Opera でもサポートが計画されています。Safari については不明です。
- IndexedDB へのファイルの格納
- Firefox 11 以降でサポートされています。Google Chrome でのサポートが計画されています。IE10 でもサポートされるでしょう。Safari と Opera については不明です。
- XMLHttpRequest Level 2
- Firefox と Google Chrome では長い間サポートされており、Safari 5 以降でサポートされています。IE10 と Opera 12 でサポートが計画されています。
- responseType “blob”
- 現在は Firefox でのみサポートされています。Google Chrome で間もなくサポートされ、IE10 と Opera 12 でサポートが計画されています。Safari については不明です。
デモとコード
IndexedDB のデモと、そのデータベースに画像とファイルを保存する コードを用意しました。このデモでは、すべての動作が見られます。開発者向けツール ([Web 開発] > [調査] の機能など) を使用して、画像の要素を調査し、その src 属性の値を見てください。また、console.log メッセージを ([Web 開発] > [Web コンソール] などで) 確認し、その動作を追ってみてください。
IndexedDB にファイルを格納する コードは GitHub 上にも置いています。お試しください!