如何将从Ionic相机中拍摄的图像上传到Firebase?

4

我已经成功使用Ionic相机API拍摄了一张照片:

  async pickImage(sourceType: CameraSource) {
    const image = await Camera.getPhoto({
      quality: 90,
      allowEditing: true,
      resultType: CameraResultType.Uri,
      source: sourceType,
    });
    console.log(image);
  }

这给了我这个:

输入图像描述

我也发现可以使用Angular Fire Storage上传,但我无法弄清如何连接这两个API。我真的不明白中间的格式是什么,我应该向相机API请求哪种格式,并且我应该向AngularFireStorage API提供哪种格式。

我尝试过这个:

const filePath = 'name-your-file-path-here';
const ref = this.storage.ref(filePath);
const task = ref.put(image.webPath);
task
  .snapshotChanges()
  .pipe(finalize(() => console.log(ref.getDownloadURL())))
  .subscribe();

但是我遇到了这个错误:

ERROR Error: Uncaught (in promise): FirebaseStorageError: {"code_":"storage/invalid-argument","message_":"Firebase Storage: Invalid argument in `put` at index 0: Expected Blob or File.","serverResponse_":null,"name_":"FirebaseError"}

非常感谢您的支持和关注 :)


我希望有人能够耐心地为你编写样板代码。我的评论是 - 通常情况下,您不需要请求格式。它返回什么就是什么。Camera.getPhoto({显然返回一个Promise,如果需要,您可以将其转换为Observable。Firebase也是一样 - 它们都可以相互转换为Promise或Observable。 - Julius Dzidzevičius
@Bitman 是的,但是 Camera.getPhoto 获取的格式是(DATA_URL、FILE_URI或NATIVE_URI),然后 promises 返回一个不同的值。对于 AngularFireStorage 也是如此,有不同的值被接受。我知道 observable。如果你检查我提供的代码,它在 observable 上等待,但我不知道如何将这个对象转换为 angularFireAuth 接受的对象。所以,问题与 Promise/Observable/async 没有任何关系。 - J4N
确实如此。因为你正在等待它,所以你得到的是一个已解决的 Promise 结果。如果没有使用 async 和 await,你可以将这个 Promise 转换为 Observable。 - Julius Dzidzevičius
完全正确,但我仍然不明白知道如何将Promise转换为Observable如何帮助我知道应该请求哪种格式的Camera.getPhoto,在angularFireStorage上调用哪个方法以及应该进行什么转换。 - J4N
我记得 angularfire 使用 Observables,而原生的 firebase 使用 Promises。如果你使用 angularfire,显然使用 Observables 可能会更容易。但这就是我所能提供的全部帮助了。希望有人能够跟随你的路线,因为需要理解的内容还是相当多的。我建议分享一下你尝试过的内容,这样别人就可以更容易地帮助你了。 - Julius Dzidzevičius
@Bitman:我知道如何订阅Observable和Promise,但我不知道要使用哪种方法和哪些参数,这就是这个问题的关键。 - J4N
2个回答

2

"webpath"不是文件或blob,您需要在调用put之前将其转换。在ionic网站上有如何转换的示例。

https://ionicframework.com/docs/angular/your-first-app/3-saving-photos

private async readAsBase64(cameraPhoto: CameraPhoto) {
  // Fetch the photo, read as a blob, then convert to base64 format
  const response = await fetch(cameraPhoto.webPath!);
  const blob = await response.blob();

  return await this.convertBlobToBase64(blob) as string;  
}

convertBlobToBase64 = (blob: Blob) => new Promise((resolve, reject) => {
  const reader = new FileReader;
  reader.onerror = reject;
  reader.onload = () => {
      resolve(reader.result);
  };
  reader.readAsDataURL(blob);
});

谢谢,我在寻找解决方案的时候经常看到你的名字 :). 但是有没有不将它转换为base64字符串的方法?我在多个地方读到过这是一个相当昂贵的操作,从技术上讲,我不明白为什么在发送blob之前需要转换为base64? - J4N
获取 Blob 后,您可以将其传递给 Firebase 并上传... 您不必使用字符串。 - Aaron Saunders
检查我的代码,这就是我尝试做的,但是我遇到了一个错误。 - J4N
我也遇到了完全相同的问题。即使我尝试使用来自iOS的Firebase Web SDK 9上传base64数据,但无论我尝试什么都会出现错误。当从本地主机ionic应用程序在浏览器中运行时,它可以正常工作,但是在iOS上尝试使用photo.path而不是photo.webPath时会出现错误。你有没有找到解决方法? - Matt

1
这是我的示例代码,它正常工作,希望它能有所帮助。

ambilpoto2(){
    const image =  Camera.getPhoto({
      quality: 90,
      allowEditing: true,
      resultType: CameraResultType.Uri
    });
    image.then((res:any)=>{
      this.gambar = res.webPath;
      this.gambarnya.nativeElement.src = this.gambar;
      this.blob=this.readAsBase64(this.gambar);
      console.log(this.blob); 
    })
  }

  private async readAsBase64(cameraPhoto: any) {
    const response = await fetch(cameraPhoto);
    const blob = await response.blob();
    return await this.convertBlobToBase64(blob) as string;  
  }
  
  convertBlobToBase64 = (blob: Blob) => 
    new Promise(
      (resolve, reject) => {
      const reader = new FileReader;
      reader.onerror = reject;
      reader.onload = () => {
          resolve(reader.result);
      };
      reader.readAsDataURL(blob);
    });
  }

and here my code for php server

//get base64 of image from client end
    $imageBase64 = $post['poto'];
    if ($imageBase64!='') {
        //function call
        $unique_name = uploadbase64image($imageBase64);
    }
    function uploadbase64image($base64) {
        $direktori = "domain/api/upload/"; 
        $imgname= $direktori.date("Y-m-d-H-i-s") . ".png";
        $new_image_url ="upload/". $imgname;
        $base641 = 'data:image/png;base64,' . $base64;
        $base642 = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $base64));
        file_put_contents($new_image_url, $base642);
        return $uniname;
    }

with DataUrl Result Type

ambilpoto(){
    const image =  Camera.getPhoto({
      quality: 90,
      allowEditing: true,
      resultType: CameraResultType.DataUrl
    });
    image.then((res:any)=>{
      this.gambar = res.dataUrl;this.gambarnya.nativeElement.src = this.gambar;
      console.log(this.gambar); 
    })
    
  }

enter code here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接