Hi,
I've build my own aws helper class which handle a simple upload of an image which I taken with the iOS Camera ( expo.Camera.takePictureAsync({base64:true})
).
I tried different approaches to upload the local file with no success and I came through the following solution:
Code Snippet
// convert base64 content to binary data object
var buf = new Buffer.from(base64, 'base64');
// upload file with aws-amplify Storage class
Storage.put('image.jpeg', buf, opt);
What is the current behavior?
Convert from base64 to binary taking a lot of time with big images ( 4MB ).
Converting base64 takes >10sec var buf = new Buffer.from(base64, 'base64');
Upload takes >10sec Storage.put('image.jpeg', buf, opt);
In sum the upload of an 4MB pic will take more than 20 seconds.
What is the expected behavior?
Can I use the local file to upload to S3 bucket instead of handling base64 strings.
Is there a solution to archive a simple image file upload with expo and aws-amplify?
My Stack
Full code of my Class
import Amplify, { Storage } from 'aws-amplify';
import aws_exports from './aws-exports';
import { Buffer } from 'buffer';
Amplify.configure(aws_exports);
Storage.configure({
bucket: "MY_BUCKET",
level: "public",
});
export default class AWSHelper {
constructor() {}
upload(folder, filename, base64, type, metadata) {
return new Promise((resolve, reject) => {
var bufBase64 = base64.replace(/^data:image\/\w+;base64,/,"");
// 4MB String takes 10 seconds
var buf = new Buffer.from(bufBase64, 'base64');
var opt = {
contentType: type || 'image/jpeg',
metadata: metadata || null
};
// 4MB buf takes 10 seconds
Storage.put(folder + '/' + filename, buf, opt)
.then (result => {
resolve(result);
})
.catch(err => {
reject(err);
});
});
}
}
Many thanks for any help!
Appreciate it!
I am facing the same problem on Android.
My Stack
takePicture = async ()=>{
if (this.camera) {
this.capturedImage = await this.camera.takePictureAsync({base64:true})
}
}
savePicture = ()=>{
fileName = this.capturedImage.uri.replace(/^.*[\\\/]/, '')
key = 'images/'+fileName
Storage.put(key, this.capturedImage.uri)
.then(result => {
console.log(result)
})
.catch(err => {});
}
Here's what I have tried:
this.capturedImage.uri
: The local file path of the captured imagethis.capturedImage.base64
: The base64 encoded string of the image'data:image/jpg;base64,'+this.capturedImage.base64
: Adding prefix to the base64 stringNone of the above 3 things have worked for me. The file with the given key
is created in S3 bucket,but is corrupted & cannot be used.
1) Please provide an example for how to do this. The docs show example of uploading only a txt
file which seems insufficient for understanding the usage of Storage.put
2) react-native & expo now support Blob
, so, if it can be used here, please provide an example for that too
EDITED
The following example works for me. It uses react-native's fetch
method to get the local file and then use blob()
to create a blob which is then sent as the file. Here is the modified savePicture
function:
savePicture = async ()=>{
fileName = this.capturedImage.uri.replace(/^.*[\\\/]/, '')
key = 'images/'+fileName
const response = await fetch(this.capturedImage.uri);
const blob = await response.blob();
Storage.put(key, blob)
.then(result => {
console.log(result)
})
.catch(err => {});
}
It seems hacky,but, it works.But, it still isn't fast enough. There is a certain amount of wait after which the response comes back. It would be great if someone could provide the correct way to upload an image to S3.
I'm not using expo and I cannot find any documentation on how to upload an image. I tried the method suggested by @kanteankit , but I'm getting an error for fetching the url. I don't really want to debug this error because I feel as though there's a better solution than fetching for the blob.
Here is how I achieved it! Must have the latest RN (if your using expo like I am, it must be SDK 26)
fetch(image.uri)
.then(response => response.blob())
.then(Buffer => Storage.put(key, Buffer))
.then(x => console.log('SAVED IMAGE WITH KEY', x) || x)
.catch(err => console.log("IMAGE UPLOAD ERROR", err));
@kpolley I tryed that solution but it throws me an error.
Hi,
thanks for the help but I am having still the same problem with the performance. :(
Is there any other solution to achieve better performance with the upload?
@Rafaell416: Could you please check if the pic really accessible or try to copy the file to your local app folder Expo.FileSystem.copyAsync
.
I've created a new issue for my blob upload problem with published expo app and will close this one.
Conclusion
Expo 26.0 with react-native 0.54 and the blob type will reduce the upload time with 4MB images on ios from 30 seconds to 5 seconds.
return new Promise(async (resolve, reject) => {
const response = await fetch(uri);
const blob = await response.blob();
Storage.put(folder + '/' + filename, blob, { contentType: 'image/jpeg' })
.then(result => resolve(result))
.catch(err => reject({error: err, object: blob}));
});
Expo 26.0 - Storage.put - blob - "Expected params.Body to be a string" #632
I know this is closed and probably doesn't need this medium post, but maybe it'll help someone.
https://medium.com/@ballenwillis/react-native-write-files-to-s3-with-aws-amplify-f4b32f96d22e
Also I honestly have no recollection of seeing this issue or commenting on it 7 months ago lol. And we're using expo now.
@ballenwillis you saved my day!!! thank you so much. I was able to follow the same procedure for my ionic 4 app to upload the image taken from android camera to s3 bucket
@ballenwillis I really wish your post had come up in my google searches. Spent wayyyyy too much time trying to debug this.
Why do the official amplify docs still show the incorrect example? react-native-fetch-blob
isn't even maintained anymore...
Submitted a PR to the docs: https://github.com/aws-amplify/docs/pull/716
Most helpful comment
I know this is closed and probably doesn't need this medium post, but maybe it'll help someone.
https://medium.com/@ballenwillis/react-native-write-files-to-s3-with-aws-amplify-f4b32f96d22e
Also I honestly have no recollection of seeing this issue or commenting on it 7 months ago lol. And we're using expo now.