NIFCLOUD-mbaas / UserCommunity

ニフクラ mobile backend ユーザーコミュニティ
https://mbaas.nifcloud.com/
81 stars 18 forks source link

Mbaasを利用したMonacaでの画像表示について #1065

Open m40851 opened 4 years ago

m40851 commented 4 years ago

初めての投稿です。初心者なので基本的な質問であれば申し訳ありません。 2つ質問があります。

https://press.monaca.io/mbaas-devrel/3300

上記のサイトを閲覧しながらMonacaのフォトシェアアプリを用いて画像一覧の表示を試みていますが、画像をアップロードし、その画像がデータストアにあることを確認しました。 MonacaのクラウドIDE上では画像フォルダから選択すると以下のように表示されますが やったああ1

iPhoneのMonacaのアプリを用いて同じことをしても画像の表示がされません。またデータストアでの画像の保存もされていません。 image 携帯にもクラウドIDEと同じように表示させたいのですが上手にいっていません。 上記のサイトにあるソースコード通りに記述を行っていますが、プレビューに関連のあるソースコードを以下に記載します。お忙しいところではありますがご教授のほど宜しくお願い致します。

const drawImage = (img, orientation) => {
  const canvas = $("#preview")[0];
  const ctx = canvas.getContext('2d');
  const size = 320;
  const offset = {width: 0, height: 0};
  let rotate = 0;
  let width = height  = size;
  canvas.width = canvas.height = size;
  let originalWidth = img.width;
  let originalHeight = img.height;
  switch (orientation) {
    case 2:
      ctx.translate(width, 0);
      ctx.scale(-1, 1);
      break;
    case 3:
      ctx.translate(width, height);
      ctx.rotate(Math.PI);
      break;
    case 4:
      ctx.translate(0, height);
      ctx.scale(1, -1);
      break;
    case 5:
      ctx.rotate(0.5 * Math.PI);
      ctx.scale(1, -1);
      break;
    case 6:
      ctx.rotate(0.5 * Math.PI);
      ctx.translate(0, -height);
      break;
    case 7:
      ctx.rotate(0.5 * Math.PI);
      ctx.translate(width, -height);
      ctx.scale(-1, 1);
      break;
    case 8:
      ctx.rotate(-0.5 * Math.PI);
      ctx.translate(-width, 0);
      break;
    default:
      break;
  }
  if (originalWidth > originalHeight) {
    // 横長
    width =  320 * originalWidth / originalHeight;
    offset.width = -1 * (width - size) / 2;
  }
  if (originalWidth < originalHeight) {
    // 縦長
    height =  320 * originalHeight / originalWidth;
    offset.height = -1 * (height - size) / 2;
  }
  ctx.drawImage(img, offset.width, offset.height, width, height);
};

const loadExif = (img) => {
  return new Promise((res, rej) => {
    EXIF.getData(img, function() {
      const lat = EXIF.getTag(this, "GPSLatitude");
      const long = EXIF.getTag(this, "GPSLongitude");
      const orientation = EXIF.getTag(this, "Orientation");
      res({
        lat: lat,
        long: long,
        orientation: orientation
      });
    });
  })
}
goofmint commented 4 years ago

処理がどこで失敗しているのでしょうか? drawImage に処理がいっているのでしょうか?

恐らくこのコードだけ見ても分からないです。スマートフォンで画像を選択した後の処理(ブログ記事で言えば dom.on('change', '#cameraImageFile', (e) => { の処理部分)で何かしらエラーが出て drawImage が実行されていないのではないかと思うのですがいかがでしょうか?

m40851 commented 4 years ago

返信ありがとうございます。ブログ記事ではdom.onを用いた処理がされていましたが、 スマホでの動きを確認したところ以下のようなエラーが出ました。 Maximum call stack size exceeded. プレビュータブでの実行はできました。

そこでブログサイトの下のほうにあったソースコードのzipファイルに入っていたコードでの実行を試したところスマホでの動きでは画像がプレビュー表示されていませんでした。パソコンのプレビュータブでの実行ではプレビュー画面が表示されました。コンソール画面にエラーも特に出ていませんでした。 画像を選択したあとの処理は以下のようになっています。 質問の回答になっていなければ申し訳ありません。長文で失礼いたしました。ご教授のほどよろしくお願いいたします。

document.addEventListener('show', function(event) {
  var page = event.target;

  if (page.id == "search-page") {
    var channels = page.querySelector('#channels');
    generateStoryBubbles(channels);
  }
  if (page.id == "profile-page") {
    page.querySelector('#profileImageUpload').addEventListener('click', (e) => {
      if (ons.platform.isIOS()) {
        $(e.target).click();
      }
      page.querySelector('#profileImageFile').click();
    });
  }
  if (page.id == 'camera-page') {
     $('.cameraPlaceholder').show();
    $('#preview').hide();
    $('#latitude').val('');
    $('#longitude').val('');
    $('#location').val('');
    page.querySelector('.select-photo').addEventListener('click', (e) => {
      if (ons.platform.isIOS()) {
        $(e.target).click();
      }
      page.querySelector('#cameraImageFile').click();
    });
  }
  }

);

$(document).on('change', '#cameraImageFile', (e) => {
  const file = e.target.files[0];
  const fr = new FileReader();
  fr.onload = (e) => {
    const img = new Image();
    img.onload = (e) => {
      loadExif(img)
        .then((exif) => {
          drawImage(img, exif.orientation);
          waitAndUpload();
          return getAddress(exif)
        })
        .then((results) => {
          $('.cameraPlaceholder').hide();
          $('#preview').show();
          $('#latitude').val(results.latitude);
          $('#longitude').val(results.longitude);
          $('#location').val(results.address);
        }, (err) => {
          console.log(err);
        });
    };
    img.src = e.target.result;
  };
  fr.readAsDataURL(file);
});
goofmint commented 4 years ago

そうですね…知りたいのは どこで、どんなエラーになっているのか なので…。例えば怪しいと思う箇所の前でalertやconsole.logを使って出力してみるのが良いかと思います。iOSであればmacOSと繋いでSafariでデバッグできます。ChromeとAndroidの組み合わせでもデバッグ可能です。

m40851 commented 4 years ago

御解答ありがとうございます。alertやconsoleを使ったところ何もエラーが表示されなかったのでもう少し試行錯誤してみようかと思います。分かりづらい質問ですがありがとうございました。 もう一点お聞きしたいのですが、ncmbをのファイルストアを用いて画像の変更を行う機能を実装しているのですが、画像を選択しファイルストアに画像が保存されているのが確認されているのですがデバック上に画像が変更が読み込まれず、以下のような写真のアイコンの画像になっています。

コメント 2019-11-06 154109

どのようなことが起こっているのかが理解できていません。すみませんがご教授頂けると幸いです。よろしくお願いいたします。

goofmint commented 4 years ago

画像ファイルはどのように読み込んでいるのでしょうか?

m40851 commented 4 years ago

https://press.monaca.io/mbaas-devrel/1545 上記サイトを参考にし以下のようなソースコードで読み込んでいます。

$(document).on('change', '#profileImageFile', (e) => {
  const file = e.target.files[0];
  const user = ncmb.User.getCurrentUser();
  fileUpload(`${user.objectId}-${file.name}`, file)
    .then((fileUrl) => {
      $('.profileImage').attr('src', fileUrl);
      // 自分の設定を更新
      return user
        .set('profileImage', fileUrl)
        .update()
    })
    .then(() => {

    })
    .catch((err) => {
      ons.notification.alert(JSON.stringify(err));

    })
});

const fileUpload = (fileName, file) => {
  return new Promise((res, rej) => {
    const user = ncmb.User.getCurrentUser();
    // アクセス権限の設定
    const acl = new ncmb.Acl();
    acl
      .setPublicReadAccess(true)
      .setUserWriteAccess(user, true);
    ncmb.File
      .upload(fileName, file, acl)
      .then((f) => {
        res(filePath(f.fileName));
        ons.notification.alert('OK10');
      })
      .catch((err) => {
        rej(err);
        ons.notification.alert('No');
      })
  });
};

document.addEventListener('show', function(event) {
  var page = event.target;

  if (page.id == "profile-page") {
    page.querySelector('#profileImageUpload').addEventListener('click', (e) => {
      if (ons.platform.isIOS()) {
        $(e.target).click();
      }
      page.querySelector('#profileImageFile').click();
      console.log("Yes")
    });
  }
);
goofmint commented 4 years ago

確認することとして、ファイルが更新されているのであれば res(filePath(f.fileName)); まで来ているのではないかと予測されます。であれば、 filePath(f.fileName) が期待している結果を返しているのか確認するのが良いのかなと。

m40851 commented 4 years ago

御解答のほどありがとうございます。以下の記述にalertを追加して検証をしてみました。エラーが出ずアラートとして「OK1」と「OK]が出たので上手にいっているのではないかと思いますが、画像の表示が先ほどと変わっていませんでした。

ファイルストアのパーミッションを全員に対する読み込みにチェックをつけています。これも何か関係があるのでしょうか・・・。 何度も質問申し訳ございませんがよろしくお願いいたします。

const fileUpload = (fileName, file) => {
  return new Promise((res, rej) => {
    const user = ncmb.User.getCurrentUser();
    // アクセス権限の設定
    const acl = new ncmb.Acl();
    acl
      .setPublicReadAccess(true)
      .setUserWriteAccess(user, true);
    ncmb.File
      .upload(fileName, file, acl)
      .then((f) => {
        res(filePath(f.fileName));
        ons.notification.alert('OK');
        console.log(filePath(f.fileName));
      })
      .catch((err) => {
        rej(err);
        ons.notification.alert('NO');
        console.log(JSON.stringify(err));
      })
  });
};

$(document).on('change', '#profileImageFile', (e) => {
  const file = e.target.files[0];
  const user = ncmb.User.getCurrentUser();
  fileUpload(`${user.objectId}-${file.name}`, file)
    .then((fileUrl) => {
      $('.profileImage').attr('src', fileUrl);
      // 自分の設定を更新
      return user
        .set('profileImage', fileUrl)
        .update()
    })
    .then(() => {
        ons.notification.alert('OK1');
    })
    .catch((err) => {
      ons.notification.alert('NO1');
      ons.notification.alert(JSON.stringify(err));
    })
});
const filePath = (fileName) => {
  return `https://mb.api.cloud.nifty.com/2013-09-01/applications/${applicationId}/publicFiles/${fileName}`;
  ons.notification.alert('OK2');
};
goofmint commented 4 years ago

alertはコードがその部分を通っているかどうかの確認になりますので、次は期待した値(今回は画像のURL)が入っているかどうかが問題になります。

filePath(f.fileName) の値をconsole.logやalertで出すとどうでしょう?

m40851 commented 4 years ago

何度もご返信ありがとうございます。 現在、上記のfileUploadの部分でconsole.log(filePath(f.fileName));を入力すると画像のURLが確認できました。 以下のコードにconsole.log(filePath(f.fileName));と入力したところアラートで「NO1」が確認できコンソール画面では {"line":330,"column":31,"sourceURL".(スマホのファイルのパス?)}とエラーが出ていました。 初めて見るものなのですが検索してもよくわかりませんでした。 ご教授頂ければ幸いです。

$(document).on('change', '#profileImageFile', (e) => {
  const file = e.target.files[0];
  const user = ncmb.User.getCurrentUser();
  fileUpload(`${user.objectId}-${file.name}`, file)
    .then((fileUrl) => {
      $('.profileImage').attr('src', fileUrl);
      // 自分の設定を更新
      return user
        .set('authData', {})
        .set('profileImage', fileUrl)
        .update()
    })
    .then(() => {
        ons.notification.alert('OK1');
        console.log(filePath(f.fileName));
    })
    .catch((err) => {
      ons.notification.alert('NO1');
      console.log(err);
    })
});
goofmint commented 4 years ago
$('.profileImage').attr('src', fileUrl);

ここに正しいfileUrlが入っているのでしょうか?そのURLにアクセスして正しく画像が表示されるのでしょうか?

m40851 commented 4 years ago

以下のようなコードで動かしてみたところ アラートで「NO1」「OK1」と出て「エラーはReferenceError: Can't find variable: fileUrl」と出ていました。これは正しいfileUrlが設定されていないということでしょうか。どこかでfileUrlを定義すればよろしいでしょうか。初歩的な質問ばかりで申し訳ありません。

$(document).on('change', '#profileImageFile', (e) => {
  const file = e.target.files[0];
  const user = ncmb.User.getCurrentUser();
  fileUpload(`${user.objectId}-${file.name}`, file)
    .then((fileUrl) => {
      $('.profileImage').attr('src', fileUrl);    
      // 自分の設定を更新
      return user
        .set('authData', {})
        .set('profileImage', fileUrl)
        .update()
    })
    .then(() => {
        ons.notification.alert('OK1');
        console.log('fileUrlは'+fileUrl);

    })
    .catch((err) => {
      ons.notification.alert('NO1');
      console.log('エラーは'+err);
    })
});
const filePath = (fileName) => {
  return `https://mb.api.cloud.nifty.com/2013-09-01/applications/${applicationId}/publicFiles/${fileName}`;

};
goofmint commented 4 years ago

書くなら $('.profileImage').attr('src', fileUrl); の上ですね。