I'm looking for the best solution to compress images that's I receive and need to store in my database.
Actually, I convert an image in base64 and then send it to the server.
handleImage = e => {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
image: reader.result
});
}
this.setState({ imgchange: true })
}
And then send the current image in state to the server. But with the low quality image it's fine but when I try to upload a medium-high quality I can't save it on the server, I need a method to compress the image.
Have you any idea to achieve this? Can you show me an example?
Best npm package you can use for image compression is browser-image-compression. Tested in React and Redux.
Install npm install browser-image-compression --save
async await syntax:
import React from "react";
import imageCompression from 'browser-image-compression';
function photoUpload() {
async function handleImageUpload(event) {
const imageFile = event.target.files[0];
console.log('originalFile instanceof Blob', imageFile instanceof Blob); // true
console.log(`originalFile size ${imageFile.size / 1024 / 1024} MB`);
const options = {
maxSizeMB: 1,
maxWidthOrHeight: 1920,
useWebWorker: true
}
try {
const compressedFile = await imageCompression(imageFile, options);
console.log('compressedFile instanceof Blob', compressedFile instanceof Blob); // true
console.log(`compressedFile size ${compressedFile.size / 1024 / 1024} MB`); // smaller than maxSizeMB
await uploadToServer(compressedFile); // write your own logic
} catch (error) {
console.log(error);
}
}
return (
<>
<div>
<input type="file" accept="image/*" onChange={event => handleImageUpload(event)}/>
</div>
</>
);
}
export default photoUpload;
For more in details can check on NPM
I've done this in a React/Redux app before with image libraries that ultimately produce a compressed JPG file - if that works for you, then using something like Jimp is an option. It was made for node, but I installed it for use in the browser, and used it like so:
Jimp.read('image.jpg').then((image) => {
if (image.bitmap.data.length > MAX_IMAGE_SIZE) {
image.quality(80); // some value of 'quality'
}
// do something else with the image
});
You can do some fiddling to figure out what the right quality of JPG is right for your app, and adjust accordingly.
When I was using this, I threw together an onDrop function that processed images a lot like you do - I won't guarantee that this code is super clean or super efficient - it came from a throwaway prototype - but it should get you started on the right path:
handleFileDrop(e) {
e.stopPropagation();
e.preventDefault();
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.onload = (function(inputFile) {
return function(e) {
var imageBlob = new Blob([e.target.result], {type: inputFile.type});
var src = URL.createObjectURL(imageBlob)
Jimp.read(src, (err, image) => {
// do stuff here
});
})(file);
reader.readAsArrayBuffer(file);
}
you can use react-image-file-resizer library to compress image
import Resizer from 'react-image-file-resizer';
Resizer.imageFileResizer(
file, //is the file of the new image that can now be uploaded...
maxWidth, // is the maxWidth of the new image
maxHeight, // is the maxHeight of the new image
compressFormat, // is the compressFormat of the new image
quality, // is the quality of the new image
rotation, // is the rotatoion of the new image
responseUriFunc, // is the callBack function of the new image URI
outputType // is the output type of the new image
);
For Example:
import React, { Component } from 'react';
import Resizer from 'react-image-file-resizer';
class App extends Component {
constructor(props) {
super(props);
this.fileChangedHandler = this.fileChangedHandler.bind(this);
}
fileChangedHandler(event) {
var fileInput = false
if(event.target.files[0]) {
fileInput = true
}
if(fileInput) {
Resizer.imageFileResizer(
event.target.files[0],
300,
300,
'JPEG',
100,
0,
uri => {
console.log(uri)
},
'base64'
);
}
}
render() {
return (
<div className="App">
<input type="file" onChange={this.fileChangedHandler}/>
</div>
);
}
}
export default App;
For Details you can read this documentation
import React from "react";
import imageCompression from "browser-image-compression";
function imageOrientation(image) {
var img = new Image();
img.src = image;
return { width: img.naturalWidth, height: img.naturalHeight };
}
const imageCompressionFile = async (image) => {
const options = {
maxSizeMB: 5,
maxWidthOrHeight: 1080,
useWebWorker: true,
};
let { width, height } = imageOrientation(URL.createObjectURL(image));
let compress_file;
if (width > height) {
if (width > 400) {
// landscape
let compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
} else {
// No landscape
compress_file = await image;
}
} else if (width < height) {
// portrait
if (height > 400) {
let compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
} else {
// No portrait
compress_file = await image;
}
} else {
const compressedFile = await imageCompression(image, options);
compress_file = await compressedFile;
}
return await compress_file;
};
function APP() {
async function handleImageUpload(event) {
const image = event.target.files[0];
let fileData = await imageCompressionFile(image);
}
return (
<>
<div>
<input
type="file"
accept="image/*"
onChange={(event) => handleImageUpload(event)}
/>
</div>
</>
);
}
export default APP;
Related
IMAGE OF THE PROBLEM This is part of a custom Cached Image component. It will sometimes render a corrupted image on first load and no previous cache, when it is first downloaded. As far as I know this happens only on Android and could be related to internet speed, but of that I am not sure. The code is:
import { Image } from 'react-native'
import * as FileSystem from 'expo-file-system'
import PropTypes from 'prop-types'
const NoImage = require('../../assets/NoImage.png');
const CachedImage = props => {
const { source: { uri }, cacheKey } = props
let filesystemURI = `${FileSystem.cacheDirectory}${cacheKey}`
const [imgSOURCE, setImgSOURCE] = useState({ uri: filesystemURI })
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
const componentIsMounted = useRef(true)
useEffect(() => {
componentIsMounted.current = true;
if (componentIsMounted.current) {
setImgSOURCE({ uri: filesystemURI })
}
return () => {
componentIsMounted.current = false
}
}, [cacheKey])
useEffect(() => {
filesystemURI = `${FileSystem.cacheDirectory}${cacheKey}`
const loadImage = async ({ fileURI }) => {
try {
// Use the cached image if it exists
const metadata = await FileSystem.getInfoAsync(fileURI).catch(function (error) {
console.log('There has been a problem with the getInfo operation: ' + error.message);
// ADD THIS THROW error
throw error;
});
if (!metadata.exists) {
// download to cache
if (componentIsMounted.current) {
setImgSOURCE(NoImage)
FileSystem.downloadAsync(
uri,
fileURI
).then(({ uri, status, headers }) => {
if (componentIsMounted.current) {
//sleep(100);
setImgSOURCE({ uri: uri })
}
})
.catch(function (error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
// ADD THIS THROW error
throw error;
});
}
}
} catch (err) {
console.log('cache image error:' + err)
if (componentIsMounted.current) {
setImgSOURCE({ uri: uri })
}
}
}
loadImage({ fileURI: filesystemURI })
return () => {
componentIsMounted.current = false
}
}, [cacheKey])
return (
<Image
{...props}
onError={() => { setImgSOURCE(NoImage) }}
source={imgSOURCE}
/>
)
}
CachedImage.propTypes = {
source: PropTypes.object.isRequired,
cacheKey: PropTypes.string.isRequired,
}
export default CachedImage
I have added a commented-out sleep before the setState for the image but haven't properly tested it. expo-file-system version is 13.1.3. It has also happened to other people:
React-native expo FileSystem.downloadAsync corrupted images
We face the same issue with Expo SDK45 and expo-file-system 14.0.0. I have the following logic in place (see code snippet) and can confirm that onError is never triggered and we still see a partial image sometimes and not the 'missing.png'. My current assumption is, that this is rather an image caching than image loading issue. Usually the image displays ok after a refresh of the screen.
import imgNone from '../../assets/images/missing.png';
const [imgSrc, setImgSrc] = useState(imageSrc(element.media[0]))
<View>
<Image key={element.media[0]} source={imgSrc} onError={() => setImgSrc(imgNone)} alt={i18n.t('global.missingImage')} size='sm'/>
</View>
Forgot to mention: I did some fiddling with image width and height and was able to display 'old' versions of the image after the image was reloaded. That as well led to the image caching assumption.
can I access the device camera and take a photo in ReactJs? The goal is to create a component that allows the camera to take pictures with the click of a button. According to my studies, I should use mediaDevices, but I am looking for a sample code in ReactJs. Please provide me with a sample code, or if you have experience implementing this, please guide me.
I have prepared a sample code that can be used as a component. This code snippet is applicable to devices that also have two cameras. If you want to take a video instead of a photo, you can also enable the audio feature in the outputs.
import React from "react";
class App extends React.Component {
constructor() {
super();
this.cameraNumber = 0;
this.state = {
imageDataURL: null,
};
}
initializeMedia = async () => {
this.setState({ imageDataURL: null });
if (!("mediaDevices" in navigator)) {
navigator.mediaDevices = {};
}
if (!("getUserMedia" in navigator.mediaDevices)) {
navigator.mediaDevices.getUserMedia = function (constraints) {
var getUserMedia =
navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (!getUserMedia) {
return Promise.reject(new Error("getUserMedia Not Implemented"));
}
return new Promise((resolve, reject) => {
getUserMedia.call(navigator, constraints, resolve, reject);
});
};
}
//Get the details of video inputs of the device
const videoInputs = await this.getListOfVideoInputs();
//The device has a camera
if (videoInputs.length) {
navigator.mediaDevices
.getUserMedia({
video: {
deviceId: {
exact: videoInputs[this.cameraNumber].deviceId,
},
},
})
.then((stream) => {
this.player.srcObject = stream;
})
.catch((error) => {
console.error(error);
});
} else {
alert("The device does not have a camera");
}
};
capturePicture = () => {
var canvas = document.createElement("canvas");
canvas.width = this.player.videoWidth;
canvas.height = this.player.videoHeight;
var contex = canvas.getContext("2d");
contex.drawImage(this.player, 0, 0, canvas.width, canvas.height);
this.player.srcObject.getVideoTracks().forEach((track) => {
track.stop();
});
console.log(canvas.toDataURL());
this.setState({ imageDataURL: canvas.toDataURL() });
};
switchCamera = async () => {
const listOfVideoInputs = await this.getListOfVideoInputs();
// The device has more than one camera
if (listOfVideoInputs.length > 1) {
if (this.player.srcObject) {
this.player.srcObject.getVideoTracks().forEach((track) => {
track.stop();
});
}
// switch to second camera
if (this.cameraNumber === 0) {
this.cameraNumber = 1;
}
// switch to first camera
else if (this.cameraNumber === 1) {
this.cameraNumber = 0;
}
// Restart based on camera input
this.initializeMedia();
} else if (listOfVideoInputs.length === 1) {
alert("The device has only one camera");
} else {
alert("The device does not have a camera");
}
};
getListOfVideoInputs = async () => {
// Get the details of audio and video output of the device
const enumerateDevices = await navigator.mediaDevices.enumerateDevices();
//Filter video outputs (for devices with multiple cameras)
return enumerateDevices.filter((device) => device.kind === "videoinput");
};
render() {
const playerORImage = Boolean(this.state.imageDataURL) ? (
<img src={this.state.imageDataURL} alt="cameraPic" />
) : (
<video
ref={(refrence) => {
this.player = refrence;
}}
autoPlay
></video>
);
return (
<div className="App">
{playerORImage}
<button onClick={this.initializeMedia}>Take Photo</button>
<button onClick={this.capturePicture}>Capture</button>
<button onClick={this.switchCamera}>Switch</button>
</div>
);
}
}
export default App;
I've created a function that takes care of resizing a image, now i want to return the resized image from the function.
I'm working with react and know i can fix the problem by using the state but i don't like this solution..
Tried returning every different scope, but i still get a undefined response. Also when i return the reader itself, i get the old data.
Interface
interface IHTMLInputEvent extends Event {
target: HTMLInputElement & EventTarget;
}
the resize function
function resizeImage(file: IHTMLInputEvent, width: number) {
const fileName = file.target.files[0].name;
const reader = new FileReader();
reader.readAsDataURL(file.target.files[0]);
reader.onload = (event) => {
const img = new Image();
img.src = event.target.result.toString();
img.onload = () => {
const elem = document.createElement('canvas');
const scaleFactor = width / img.width;
elem.width = width;
elem.height = img.height * scaleFactor;
const ctx = elem.getContext('2d');
ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
ctx.canvas.toBlob((blob) => {
return new File([blob], fileName, { type: 'image/jpeg', lastModified: Date.now() });
}, 'image/jpeg', 1);
};
};
}
function for handling the upload(so far)
function handleUpload(e: IHTMLInputEvent) {
const resizedImage = resizeImage(e, 600);
}
input field
<input
className={classes.inputForUpload}
accept='image/*'
type='file'
ref={uploadImage}
onChange={(e: IHTMLInputEvent) => handleUpload(e)}
/>
I would like to return the new created image.
You can solve this using Promise,
function resizeImage(file: IHTMLInputEvent, width: number) {
return new Promise((resolve, reject) => {
const fileName = file.target.files[0].name;
const reader = new FileReader();
reader.readAsDataURL(file.target.files[0]);
reader.onload = (event) => {
const img = new Image();
img.src = event.target.result.toString();
img.onload = () => {
const elem = document.createElement('canvas');
const scaleFactor = width / img.width;
elem.width = width;
elem.height = img.height * scaleFactor;
const ctx = elem.getContext('2d');
ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
ctx.canvas.toBlob((blob) => {
resolve(new File([blob], fileName, {
type: 'image/jpeg',
lastModified: Date.now()
}));
}, 'image/jpeg', 1);
};
};
});
}
With async, await ,
async function handleUpload(e: IHTMLInputEvent) {
const resizedImage = await resizeImage(e, 600);
// do you suff here
}
JSX,
<input
className={classes.inputForUpload}
accept='image/*'
type='file'
ref={uploadImage}
onChange={async (e: IHTMLInputEvent) => await handleUpload(e)}
/>
May I ask why you don't like the solution of using state? This seems like a pretty standard use case.
Your state could look something like this:
state = {
imageDescription: '',
imageUrl: null
};
Your action handler would simply setState upon success like so:
img.onload = () => {
...
this.setState({ imageDescription: fileName, imageSrc: img.src })
};
Finally your render function would look something like this:
render() {
const { imageDescription, imageUrl } = this.state;
return (
<Fragment>
<input
className={classes.inputForUpload}
accept='image/*'
type='file'
ref={uploadImage}
onChange={(e: IHTMLInputEvent) => handleUpload(e)}
/>
<img src={imageUrl} alt={imageDescription} />
</Fragment>
)
}
P.S. you can delete handleUpload and call resizeImage directly.
Heyy, i am trying to upload a cropped image to firebase.
I would prefer to use the ionic native "image-picker" and "Crop".
I really dont know how to upload the image after cropping it, because it only returns the path of the new image.
I have already tryed something like this. This worked, but i was not able to crop the image. But as i mentioned, i would prefer using the native tools anyways.
export interface UploadData {
name: string;
filepath: string;
size: number;
}
uploadFile(event: FileList) {
// The File object
const file = event.item(0);
// Validation for Images Only
if (file.type.split('/')[0] !== 'image') {
console.error('unsupported file');
return;
}
// The storage path
const path = `whatever/${new Date().getTime()}_${file.name}`;
// File reference
const fileRef = this.storage.ref(path);
// The main task
this.task = this.storage.upload(path, file, { customMetadata });
this.snapshot = this.task.snapshotChanges().pipe(
finalize(() => {
// Get uploaded file storage path
this.UploadedFileURL = fileRef.getDownloadURL();
this.UploadedFileURL.subscribe(resp => {
this.addImagetoDB({
name: file.name,
filepath: resp,
size: this.fileSize
});
}, error => {
console.error(error);
});
}),
tap(snap => {
this.fileSize = snap.totalBytes;
})
);
}
addImagetoDB(image: UploadData) {
const id = this.db.createId();
// Set document id with value in database
this.imageCollection.doc(id).set(image).then(resp => {
console.log(resp);
}).catch(error => {
console.log('error ' + error);
});
}
}
This is how i would like to do it. But i really have no idea, how to upload it at this point.
pickImage() {
this.imagePicker.getPictures(this.imagePickerOptions).then((results)
=> {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < results.length; i++) {
this.cropImage(results[i]);
}
}, (err) => {
alert(err);
});
}
cropImage(imgPath) {
this.crop.crop(imgPath, { quality: 50 })
.then(
newPath => {
// ?????
},
error => {
alert('Error cropping image' + error);
}
);
}
Sorry, i am very new to this stuff.
Thanks for your help :)
It seems that you might be able to do this without the crop feature being needed.
These are the options according to the docs:
options = {
// Android only. Max images to be selected, defaults to 15. If this is set to 1, upon
// selection of a single image, the plugin will return it.
maximumImagesCount: int,
// max width and height to allow the images to be. Will keep aspect
// ratio no matter what. So if both are 800, the returned image
// will be at most 800 pixels wide and 800 pixels tall. If the width is
// 800 and height 0 the image will be 800 pixels wide if the source
// is at least that wide.
width: int,
height: int,
// quality of resized image, defaults to 100
quality: int (0-100),
// output type, defaults to FILE_URIs.
// available options are
// window.imagePicker.OutputType.FILE_URI (0) or
// window.imagePicker.OutputType.BASE64_STRING (1)
outputType: int
};
So you could use:
options = {
maximumImagesCount: 3,
width: 800,
height: 600,
quality: 50,
outputType: 1
};
From what I've been researching you could then put the image into Firebase Storage using:
storageRef.putString("Your base64 string substring variable", 'base64');
I'm not sure if this is enough to get you fixed up but I thought I would post what I had found anyway.
I just tried this, but it dosnĀ“t work too. I have no idea why...
constructor(private imagePicker: ImagePicker, private crop: Crop,
private file: File) {
let storageDb = firebase.storage();
this.storageRef = storageDb.ref();
}
pickImage() {
this.imagePicker.getPictures(this.imagePickerOptions).then((results)
=> {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < results.length; i++) {
this.cropImage(results[i]);
}
}, (err) => {
alert(err);
});
}
cropImage(imgPath) {
this.crop.crop(imgPath, { quality: 50 })
.then(
newPath => {
try {
let n = newPath.lastIndexOf("/");
let x = newPath.lastIndexOf("g");
let nameFile = newPath.substring(n + 1, x + 1);
this.file.readAsArrayBuffer(newPath, nameFile).then((res) => {
let blob = new Blob([res], { type: "image/jpeg" });
var uploadTask = this.storageRef.child('images/' + this.event.id).put(blob);
uploadTask.on('state_changed', (snapshot) => {
let url = uploadTask.snapshot.downloadURL;
this.croppedImagepath = url;
}, (error) => {
alert("error: " + error);
}, () => {
alert("uploaded");
let url = uploadTask.snapshot.downloadURL;
this.croppedImagepath = url;
})
})
}
catch (z) {
alert('error beim erstellen des blobs' + z);
}
},
error => {
alert('Error cropping image' + error);
}
);
}
Problem
I am trying to create an app with react native and firebase. One of the features I would like for this app is the ability to upload images. I am having some trouble uploading the images to firebase storage though. I am using expo's image picker to find the path of the image that the user wants to upload, but once I have the path I don't know how to convert that to something I can upload to firebase.
Can somebody help me convert the path of an image to something I can upload to firebase storage with react native?
What I've tried
I tried using:
_pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
MediaTypeOptions: 'Images',
quality: 0.4,
_uploadAsByteArray = async (pickerResultAsByteArray, progressCallback) => {
try {
var metadata = {
contentType: 'image/jpeg',
};
var storageRef = firebase.storage().ref();
var ref = storageRef.child('images/'+expoID+'/'+this.state.time)
let uploadTask = ref.put(pickerResultAsByteArray, metadata)
uploadTask.on('state_changed', function (snapshot) {
progressCallback && progressCallback(snapshot.bytesTransferred / snapshot.totalBytes)
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log('Upload is ' + progress + '% done');
}, function (error) {
console.log("in _uploadAsByteArray ", error)
}, function () {
var downloadURL = uploadTask.snapshot.downloadURL;
console.log("_uploadAsByteArray ", uploadTask.snapshot.downloadURL)
this.setState({imageUploaded:true})
});
} catch (ee) {
console.log("when trying to load _uploadAsByteArray ", ee)
}
}
convertToByteArray = (input) => {
var binary_string = this.atob(input);
var len = binary_string.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
bytes[i] = binary_string.charCodeAt(i);
}
return bytes
}
atob = (input) => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
let str = input.replace(/=+$/, '');
let output = '';
if (str.length % 4 == 1) {
throw new Error("'atob' failed: The string to be decoded is not correctly encoded.");
}
for (let bc = 0, bs = 0, buffer, i = 0;
buffer = str.charAt(i++);
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = chars.indexOf(buffer);
}
return output;
}
uploadImage(bsfdata){
this.setState({imageUploaded:false})
this._uploadAsByteArray(this.convertToByteArray(bsfdata), (progress) => {
this.setState({ progress:progress })
})
}
base64:true,
});
/* if (!result.cancelled) {
this.setState({ image: result.uri });
let formData = new FormData();
formData.append('photo', {
uri,
name: `photo.${fileType}`,
type: `image/${fileType}`,
});}*/
this.uploadImage(result.base64);
};
}
I've tried it with the commented code added, which doesn't upload anything, and I've tried it with how the code is now, which gives me the error Can currently only create a Blob from other Blobs, and the uploading progress never gets above 0%.
If you are using expo (>=26), then you can do it easily with the following lines of code.
uploadImage = async(imageUri) => {
const response = await fetch(imageUri);
const blob = await response.blob();
var ref = firebase.storage().ref().child("image.jpg");
return ref.put(blob);
}
Reference: https://youtu.be/KkZckepfm2Q
Refer this link - https://github.com/dailydrip/react-native-firebase-storage/blob/master/src/App.js#L43-L69
Following block of code is working fine.
uploadImage(uri, mime = 'application/octet-stream') {
return new Promise((resolve, reject) => {
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri
let uploadBlob = null
const imageRef = FirebaseClient.storage().ref('images').child('image_001')
fs.readFile(uploadUri, 'base64')
.then((data) => {
return Blob.build(data, { type: `${mime};BASE64` })
})
.then((blob) => {
uploadBlob = blob
return imageRef.put(blob, { contentType: mime })
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL()
})
.then((url) => {
resolve(url)
})
.catch((error) => {
reject(error)
})
})
}
You need to install rn-fetch-blob module:
npm install --save rn-fetch-blob
Then, do the following:
import RNFetchBlob from 'rn-fetch-blob';
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
function uploadImage(path) {
const imageFile = RNFetchBlob.wrap(path);
// 'path/to/image' is where you wish to put your image in
// the database, if you would like to put it in the folder
// 'subfolder' inside 'mainFolder' and name it 'myImage', just
// replace it with 'mainFolder/subfolder/myImage'
const ref = firebase.storage().ref('path/to/image');
var uploadBlob = null;
Blob.build(imageFile, { type: 'image/jpg;' })
.then((imageBlob) => {
uploadBlob = imageBlob;
return ref.put(imageBlob, { contentType: 'image/jpg' });
})
.then(() => {
uploadBlob.close();
return ref.getDownloadURL();
})
.((url) => {
// do something with the url if you wish to
})
.catch(() => {
dispatch({
type: UPDATE_PROFILE_INFO_FAIL,
payload: 'Unable to upload profile picture, please try again'
});
});
}
Please do ask if there's any part of the code that you don't understand. To upload multiple images, simply wrap this code with a for loop. Or if you want to make sure that every image is uploaded without any error, use Promise
Not sure whom this might help, but if you're using MediaLibrary to load images from the gallery, then the uri comes in the format of uri = file:///storage/emulated/0/DCIM/Camera/filename.jpg
In this case, using fetch(uri) didn't help me get the blob.
But if you use fetch(uri.replace("file:///","file:/")) and then follow #sriteja Sugoor's answer, you'll be able to upload the file blob.
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
let uploadBlob;
await fs
.readFile(params?.file.path, 'base64')
.then((data) => {
return Blob.build(data, {type: `BASE64`});
})
.then((blob) => {
uploadBlob = blob;
console.log(uploadBlob, 'uploadBlob');
});