HTML5
Cordova
monaca
MonacaDay 8

Monaca(Cordova)のCameraプラグインで取得した写真をBlob形式に変換する方法

写真を外部ストレージにアップロードする場合などに、Blob形式の写真データが必要になることがあるかと思います。しかしCameraプラグインの写真の取得形式はURIまたはbase64になるため、そのままではBlobデータとして扱えません。
JavaScriptでBlobデータを作るにはnew Blob()を使いますが、このコンストラクタ引数にはArrayBuffer(など)の形式のデータを指定しなければなりません。そのため、写真のURIから最終的にBlobへ変換するには、少々面倒ですが以下の手順を経由する必要があります。

  1. Cameraプラグインで写真のURIを取得
  2. URIからFileEntryに変換
  3. FileEntryからFileオブジェクトを取得し、ArrayBufferに変換
  4. ArrayBufferからBlobに変換

変換処理には、HTML5のFile APIを利用します。
それでは各手順を詳しく解説していきます。

1. Cameraプラグインで写真のURIを取得

まずは写真をURI形式で取得します。

// 写真を読み込み
navigator.camera.getPicture(onSuccess, onError, { 
  sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
  destinationType: Camera.DestinationType.FILE_URI
});

// 写真のURIが取得される
function onSuccess(imageURI) {
  // URIからFileEntryに変換
  URItoFileEntry(imageURI);
}

// エラー時の処理
function onError(error) {
  console.log(error);
}

2. URIからFileEntryに変換

FileEntryは、ローカルのファイルシステム内のファイルを表すインターフェースです。
window.resolveLocalFileSystemURL() によって、FileEntryを取得することができます。
この処理は非同期的に実行され、処理が完了すると第二引数に指定したコールバック関数にFileEntryが渡されます。

// URIからFileEntryに変換する
function URItoFileEntry(imageURI) {
  window.resolveLocalFileSystemURL(imageURI, fileEntryToArrayBuffer, onError);
}

3. FileEntryからFileオブジェクトを取得し、ArrayBufferに変換

FileEntry.file()によって、読み込み可能なファイルを表すFileオブジェクトを取得します。
そしてファイルの読み込み機能を提供するFileReaderオブジェクトを生成し、FileReader.readAsArrayBuffer()によって、FileオブジェクトをArrayBuffer形式に変換します。このメソッドは非同期で実行され、読み込みが完了するとFileReader.onloadendイベントが発火します。

// FileEntryからFileオブジェクトを取得し、さらにArrayBufferに変換する
function fileEntryToArrayBuffer(fileEntry) {
  // Fileオブジェクトを取得
  fileEntry.file((file) => { 
    // FileReaderを生成
    let reader = new FileReader();
    // ArrayBuffer形式への変換完了時の処理
    reader.onloadend = ArrayBufferToBlob;
    // ArrayBuffer形式に変換
    reader.readAsArrayBuffer(file);
  }, onError);
}

// エラー時の処理
function onError(error) {
  console.log(error);
}

4. ArrayBufferからBlobに変換

FileReader.onloadendイベントのイベント引数に、ArrayBufferオブジェクトが格納されています。あとはこのArrayBufferオブジェクトを配列形式にしてnew Blob()のコンストラクタに指定するだけです。

// ArrayBufferからBlobに変換する
function ArrayBufferToBlob(event) {
  let blob = new Blob([event.target.result])
}

ソースコード全文

// 写真を読み込み
navigator.camera.getPicture(onSuccess, onError, { 
  sourceType : Camera.PictureSourceType.PHOTOLIBRARY,
  destinationType: Camera.DestinationType.FILE_URI
});

// 写真のURIが取得される
function onSuccess(imageURI) {
  // URIからFileEntryに変換
  URItoFileEntry(imageURI)
}

// URIからFileEntryに変換する
function URItoFileEntry(imageURI) {
  window.resolveLocalFileSystemURL(imageURI, fileEntryToArrayBuffer, onError);
}

// FileEntryからFileオブジェクトを取得し、さらにArrayBufferに変換する
function fileEntryToArrayBuffer(fileEntry) {
  // Fileオブジェクトを取得
  fileEntry.file((file) => { 
    // FileReaderを生成
    let reader = new FileReader();
    // ArrayBuffer形式への変換完了時の処理
    reader.onloadend = ArrayBufferToBlob;
    // ArrayBuffer形式に変換
    reader.readAsArrayBuffer(file);
  }, onError);
}

// ArrayBufferからBlobに変換する
function ArrayBufferToBlob(event) {
  let blob = new Blob([event.target.result])
}

// エラー時の処理
function onError(error) {
  console.log(error);
}

このようにFile APIを使うと、バイナリデータを様々な形式に変換することができます。
CameraプラグインはFile APIとの併用によって、できることが増えると覚えておくと良いでしょう。