upload image from Angular to aws s3 error: the image cannot be displayed because it contains errors

upload image from Angular to aws s3 error: the image cannot be displayed because it contains errors

我正在尝试使用 Android 相机拍摄图像并将其上传到 AWS S3 存储桶。 使用 Angular 13 Ionic 6 和 Capacitor 相机。

我终于得到了要上传到 S3 的图像,但是当我试图在浏览器中查看它时,出现错误:

 image ... cannot be displayed because it contains errors

S3 存储桶中显示的图像大小始终为 48.5 Kb。我发现了几份包含类似错误消息的报告,但 none 有所帮助。

在我的signup.component.ts:

  async uploadProfilePhotoToAws(txKey: string, fileName: string): Promise<string> {

    let image = await this.getBase64ImageFromUrl(this.profilePhotoUrl.split(',')[1]); 

    var data = {
      Key: 'test-key-profile-image', //txKey, 
      name: fileName + '.jpg', //Value: profiles/09720004658354.jpg
      value: image,
      ContentEncoding: 'base64',
      ContentType: 'image/jpeg',
      type: 'image/jpeg'
    };

    console.log('AWS data payload: ', JSON.stringify(data));

    //Upload profile image to AWS s3
    return this._aws.uploadDataFile(data).then(res => {
      if (res) {
        console.log('aws profile file returned: ', res);
        return res;
      }
    }).catch(err => {
      console.log('AWS profile upload error: ', err);
      return '';
    });
  }

还有:

  async getBase64ImageFromUrl(imageUrl) {
    var res = await fetch(imageUrl);
    var blob = await res.blob();
  
    return new Promise((resolve, reject) => {
      var reader  = new FileReader();
      reader.addEventListener("load", function () {
          resolve(reader.result);
      }, false);
  
      reader.onerror = () => {
        return reject(this);
      };
      reader.readAsDataURL(blob);
    })
  }

我的 add-photo.component.ts - 提供上述注册组件:

import { Component, EventEmitter, OnInit, Output, Input } from '@angular/core';
import { PhotoService } from '../../services/photo.service';
import { CameraDirection, CameraResultType } from '@capacitor/camera';

@Component({
  selector: 'app-add-photo',
  templateUrl: './add-photo.component.html',
  styleUrls: ['./add-photo.component.scss'],
})
export class AddPhotoComponent implements OnInit {

  @Output('photo') photo = new EventEmitter<string>();
  @Input() receivedPhotoPath: string;
  
  photoPath: string = "/assets/media/avatar.svg";

  constructor(public photoService: PhotoService) { }

  ngOnInit() {
    console.log('OnInit Received Photo Path: ', this.receivedPhotoPath);
    if (this.receivedPhotoPath!='') {
      this.photoPath = this.receivedPhotoPath;
    }
  }


  capturePhoto() {
    console.log('add-photo Component about to call the capturePhoto service');
    this.photoService.capturePhoto(CameraDirection.Front, CameraResultType.Uri).then((photoResult: string) => {
      
        console.log('Returned from capturePhoto: ' + JSON.stringify(photoResult));
        
        this.photoPath = photoResult;
        
        this.photo.emit(photoResult);
      
    }).catch((error) => {
      console.log('Failed profile picture capture. Error: ' + error.message);
      
    });
  }
}

photo.service.ts - 服务于上面的添加-photo.component:

import { Injectable } from '@angular/core';
import { Camera, CameraDirection, CameraResultType, CameraSource, Photo } from '@capacitor/camera';

@Injectable({
  providedIn: 'root'
})
export class PhotoService {

  public photoUrl: string;

  constructor() { }

  public async capturePhoto(direction: CameraDirection = CameraDirection.Rear, resultType: CameraResultType = CameraResultType.Uri): Promise<string> {

    const capturedPhoto = await Camera.getPhoto({
      resultType: resultType,
      source: CameraSource.Prompt,
      direction: direction,
      quality: 100
    });

    this.photoUrl = capturedPhoto.webPath;
    
    return this.photoUrl;
  }

}

aws-file-upload.service.ts:

import { Injectable } from '@angular/core';
import * as AWS from 'aws-sdk/global';
import * as S3 from 'aws-sdk/clients/s3';

import { environment } from '../../environments/environment';
import { PromiseResult } from 'aws-sdk/lib/request';
import { PutObjectOutput } from 'aws-sdk/clients/s3';
import { AWSError } from 'aws-sdk/global';

@Injectable({
  providedIn: 'root'
})
export class AwsFileUploadService {

  constructor() { }

  uploadDataFile(data: any) {
    const contentType = data.type;
    const bucket = new S3({
      accessKeyId: environment.awsAccessKey,
      secretAccessKey: environment.awsSecret,
      region: environment.awsRegion
    });
    const params = {
      Bucket: environment.awsBucket,
      Key: data.name, //manipulate filename here before uploading
      Body: data.value,
      ContentEncoding: 'base64',
      
      ContentType: contentType
    };


    var putObjectPromise = bucket.putObject(params).promise();
    return putObjectPromise.then(function(data) {
      console.log('succesfully uploaded the image! ' + JSON.stringify(data));
      return data;
    }).catch(function(err) {
      console.log(err);
      return err;
    });

   }

}

请帮助我确定我做错了什么。 谢谢!

解决方案是在为 AWS S3 准备图像负载时使用 Buffer:

async uploadProfilePhotoToAws(txKey: string, fileName: string): Promise<string> {

    console.log('Photo URL Before passed to Base64 transformation: ', this.profilePhotoUrl);
    let image = await this.getBase64ImageFromUrl(this.profilePhotoUrl); //Image saved corrupt in S3. Check why
    let buf = Buffer.from(image.toString().replace(/^data:image\/\w+;base64,/, ""), "base64");

    var data = {
      Key: txKey, 
      name: fileName + '.jpg',
      value: buf,
      ContentEncoding: 'base64',
      ContentType: 'image/jpeg',
      type: 'image/jpeg'
    };

    //Upload profile image to AWS s3
    return this._aws.uploadDataFile(data).then(res => {
      if (res) {
        console.log('aws profile file returned: ', res);
        return res;
      }
    }).catch(err => {
      console.log('AWS profile upload error: ', err);
      return '';
    });
  }