Home > database >  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

Time:05-02

I'm trying to capture an image with the Android camera and upload it to an AWS S3 bucket. Using Angular 13 Ionic 6 and the Capacitor camera.

Finally I got the image to upload to S3, but when attempting to view it in the browser, I get an error:

 image ... cannot be displayed because it contains errors

The image size shown in the S3 bucket is always 48.5 Kb. I found a couple of reports with similar error messages but none helped.

In my 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 '';
    });
  }

And also:

  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);
    })
  }

My add-photo.component.ts - serving the above signup component:

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);
      
    });
  }
}

And the photo.service.ts - serving the above add-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;
  }

}

The 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;
    });

   }

}

Please help me in identifying what am I doing wrong. Thank you!

CodePudding user response:

The solution was to use Buffer while preparing the image payload to AWS S3:

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 '';
    });
  }
  • Related