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 '';
});
}
我正在尝试使用 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 '';
});
}