monaca(phonegap)でcamera画像を取得して、画面遷移後、画像をサーバー(nifty mobile backend)にアップロードするまで。


やりたいこと

1.ユーザー登録画面でカメラで画像(jpeg)を取得。imgタグに画像を設定。
2.ユーザー確認画面で、imgタグで表示。表示している画像をサーバー(nifty mobile backend)に登録。

※モバイルアプリでよくやることですが、「これだ!」というサンプルがなかったので

環境

1.monaca(Phone Gap)
2.nifty mobile backend
3.HTML5 FileAPI(Phone GapのFileAPIも参考になる)

注意

1.iOSのみ稼働確認しています。
2.作ったソースをバラして、コピペしたので、一部変なとこがあるかもしれません。

#説明
1.ユーザー登録画面からカメラ起動。このとき、カメラの属性で、「destinationType:Camera.DestinationType.FILE_URI」にします。
DATA_URIでもその画面内なら問題ないのですが、BASE64のデータとなるので、画面遷移すると、非常に重たくなります。

camera.js
function setOptions(srcType) {
  var options = {
      // Some common settings are 20, 50, and 100
      quality: 50,
      destinationType: Camera.DestinationType.FILE_URI,
      // In this app, dynamically set the picture source, Camera or photo gallery
      sourceType: srcType,
      encodingType: Camera.EncodingType.JPEG,
      mediaType: Camera.MediaType.PICTURE,
      allowEdit: true,
      correctOrientation: true,  //Corrects Android orientation quirks
      targetHeight : 100,
      targetWidth   :100
  }
  return options;
}
$scope.setPicture = function openFilePicker() {
  // ギャラリーの設定
  var srcType = Camera.PictureSourceType.SAVEDPHOTOALBUM;
  var options = setOptions(srcType);
  // カメラを起動
  navigator.camera.getPicture(function cameraSuccess(imageUri) {
    console.log('albam success get image url:' + imageUri);
    // imgタグに設定する。
    var image = document.getElementById ('picture');
    image.src = imageUri;
    // Angularの場合は、一旦スコープに保存。
    $scope.picture = imageUri;
  }, function cameraError(error) {
      console.debug("Unable to obtain picture: " + error, "app");
  }, options);
}
$scope.submit = function() {
  if ($scope.userForm.$valid) {
   // Angularの場合は、locationのパラメータに設定。
    $location.search("username",$scope.username);
    $location.search("password",$scope.password);
    $location.search("password_confirm",$scope.password_confirm);
    $location.search("picture",$scope.picture);
    $scope.load("next.html");
  }
};

2.submit時に、window.resolveLocalFileSystemURL(HTML5 Web API)を使用して、ローカルファイルを取得します。nifty mobile backendに登録するには、blobにする必要があるので、FILE → FileReader.readAsArrayBufferで読み込んで、Blobを作成します。
(PhoneGapのwindow.resolveLocalFileSystemURLでも引数が異なるだけで、やることは多分一緒)

next.js
  // ローカルファイルを読み込んで、niftyにアップロードする。
  function addFile(imgUri) {
    return new Promise(function(resolve, reject) {
      window.resolveLocalFileSystemURL(imgUri, function success(fileEntry) {

        console.log("get file: " + fileEntry.fullPath);//実機でフルパス取れていない。
        var filename = fileEntry.name;

        fileEntry.file(function(file) {
          var reader = new FileReader();
          reader.onloadend = function(evt) {
            //readAsArrayBufferは非同期なので、ロード完了後のイベントで行う。
            console.log("Read complete!");

            // どうも、niftyの方で、blobにしないと、imageが読み込めないらしい。
            // fileでuploadすると、ダメ。色々試したが、Mobileで一番動きそうなのはこれ?
            var blob = new Blob([evt.target.result], {type: "application/octet-binary"});
            console.log("blob size:" + blob.size);
            ncmb.File.upload(filename, blob)
            .then(function(res){
              console.log("success upload !");
              resolve(res);
             })
            .catch(function(err){
              console.log("fail upload !");
              console.log(err);
              reject(err);
             });
          };
          reader.readAsArrayBuffer(file);
        }, function() {console.log(error);});
      }, function() {console.log(error);});
    });
  };

$scope.submit = function() {
  if ($scope.userForm.$valid) {
      // カメラからDATA_URL(base64)で取得するサンプルが沢山あるが、
      // DATA_URLだと、次画面への引き継ぎが重くなる。
      // また、niftyにあげるときに、blobにしないといけないくなるので、
      // FILE_URLで取得して、ローカルのファイルをblobにした方が無難。

      $scope.picture = imageUri;
      var addfile = addFile(imageUri);
      addfile.then(function(res){
        console.log("addFile Success");
        var response = res;
        console.log(response.fileName);
      });
      addfile.catch(function(err){
          console.log(err);
      });
  }
};

最後に。。技術要素が沢山あって、色々とハマってつかれた。。
つか、他にも参考になりそうなの沢山つくっているんだけどな。。
既に作ったソースからサンプル起こすの大変。。みんなどうしているんだろ。