I'm pretty new using React Native (Expo in this case) and Firebase database.
My problem is that when I upload an image in my app thanks to Image Picker, the link is a local link, so reading only with my device, and then deleted when I erase the cache
Here is my code :
useEffect(() => {
(async () => {
if (Platform.OS !== "web") {
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
}
}
})();
}, []);
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 1,
});
if (!result.cancelled) {
setImage(result.uri);
}
};
// My current image is locate to : "file:///data/user/0/host.exp.exponent/cache/
// ExperienceData/ImagePicker/2abe4097-05ed-4d23-5648-f279d5a6f995.jpg"
// And what I want is to locate my image to : "https://someting..."
So I want to convert this image uri link in a url link, to be shared and never erased.
Anyone has an idea about how to proceed ?
Thanks a lot !
Let's break down the problem as below :
1. Pick an image from the Media Library.
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
quality: 1,
});
if (!result.cancelled) {
setImage(result.uri);
}
};
2. Fetch Image BLOB Data
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", [IMAGE_URI_HERE], true);
xhr.send(null);
});
3. Upload image BLOB to a remote server (Firebase Storage)
const metadata = { contentType: "image/jpg" };
const imgRef = firebase.storage().ref('folderName/fileName');
await imgRef.put(blob, metadata);
// We're done with the blob, close and release it
blob.close();
// Image permanent URL
const imgURL = await imgRef.getDownloadURL();
Related
This is my ReactNative code
const changeAvatar = async () => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.cancelled) {
const image = await fetchImageFromUri(result.uri);
const uploadUrl = await uploadImage(image);
}
}
const fetchImageFromUri = async (uri) => {
const response = await fetch(uri);
const blob = await response.blob();
return blob;
};
const uploadImage = async (image) => {
var formdata = new FormData();
formdata.append("blob", image, image._data.name);
formdata.append("nameeee", "nameeee");
var requestOptions = {
method: 'POST',
body: formdata,
redirect: 'follow'
};
fetch(global.domain + "/api/profile/avatar", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
And this is my ASP .NET Web API code to handle file upload
[Route("avatar")]
[HttpPost]
public async Task<object> Avatar([FromForm] string nameeee, [FromForm] IFormFile blob)
{
return "";
}
I have test my API by using postman to upload a file, it's work great.
But's in my ReactNative code, the file chooser handle convert selected image to blob, so it can't upload to the API. What do i need to modify my ReactNative code to upload selected image to web API ?
I am using expo-image-picker and if I select an image in android emulator and save it, I cannot see the image I saved from emulator when I enter the program with my real device. In other words, with whichever device I save the picture, it only appears on that device. It does not appear on other devices. How can I solve this?
I am using API for database operations (with axios)
Here is the code
const PickImage = async () => {
allowPhotoRequests()
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
base64: true
})
if (!result.cancelled) {
setImage(result.uri) // I think I have to do something here
}
Submit code:
const addPet = async () => {
try {
petApi.post('/', {
userId: userId,
Age: age,
Weight: weight,
userName: currentUser,
userPhone: currentUserPhone,
petImage: image,
city: city,
district: district
})
.then(function (response) {
alert('Success!')
})
}
catch (error) {
console.log(error);
}
}
Example image output:
file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540yas1nkiziltas%252FPettyApp/ImagePicker/cb2923b3-5de8-4692-8244-0ce9b987001a.jpg
There are 2 ways you can solve this problem as you're using this Expo:
Submit image data as base64
Review that backend API support BLOB and you can fetch BLOB with code
below.
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", [YOUR_FILE_PATH_URI], true);
xhr.send(null);
});
// Use blob after fetch
console.log(blob)
// We're done with the blob, close and release it
blob.close();
You are saving the petImage in your patApi database for a specific userId. On any device, to get that image, you need to fetch this data again, I don't see you fetching this image data back after you post it. This is the part you are missing.
I want to play a video but i face the can't play this video file error
When I try it with this link, the video is properly downloaded and also played but with this link, it says the video file is corrupt.
const downloadFile = () => {
const uri = "instagram.com/p/CET9SzMpCYg/?utm_source=ig_web_copy_link"
let fileUri = FileSystem.documentDirectory +"video.mp4";
FileSystem.downloadAsync(uri,fileUri)
.then(({ uri }) => { saveFile(uri); })
.catch(error => { console.error(error); })
}
const saveFile = async fileUri => {
const { status } = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (status === "granted") {
const asset = await MediaLibrary.createAssetAsync(fileUri);
await MediaLibrary.createAlbumAsync("Download", asset, false);
alert('Saved to Downloads');
}
}
I am trying to save captured images and video recording from phone camera to my device gallery, but I get permission denied and error message stating that CameraRoll.saveToCameraRoll(tag, type) is deprecated. Use the save function instead.
takePicture = async () => {
if (this.camera) {
const options = { quality: 1 };
const data = await this.camera.takePictureAsync(options);
//save photo
CameraRoll.saveToCameraRoll(data.uri, 'photo').then(onfulfilled => {
ToastAndroid.show(onfulfilled, ToastAndroid.SHORT);
}).catch(error => {
ToastAndroid.show(`${error.message}`, ToastAndroid.SHORT);
});
}
};
Assuming you are using the new version of CameraRoll the function saveToCameraRoll is being deprecated in favor of the save function. Only change that you have to do is to change saveToCameraRoll to save like below
takePicture = async () => {
if (this.camera) {
const options = { quality: 1 };
const data = await this.camera.takePictureAsync(options);
//save photo
CameraRoll.save(data.uri, 'photo').then(onfulfilled => {
ToastAndroid.show(onfulfilled, ToastAndroid.SHORT);
}).catch(error => {
ToastAndroid.show(`${error.message}`, ToastAndroid.SHORT);
});
}
};
I need way to upload image to firebase
i tried to use react-native-fetch-blob library
but I think there is something wrong with installing the library
No need to use react-native-fetch-blob. Here is how I do it on my project.
Install both react-native-firebase and react-native-image-picker. Follow the installation steps from their documentation guide.
Then implement 2 small functions to do image pick and upload to firebase. Here is the sample code.
// 1. Import required library
import firebase from 'react-native-firebase';
import ImagePicker from 'react-native-image-picker';
// 2. Create a function to pick the image
const pickImage = () => {
return new Promise((resolve, reject) => {
ImagePicker.showImagePicker(pickerOptions, response => {
if (response.didCancel) return;
if (response.error) {
const message = `An error was occurred: ${response.error}`;
reject(new Error(message));
return;
}
const { path: uri } = response;
resolve(uri);
});
});
};
// 3. Create a function to upload to firebase
const uploadImage = async (fileName, uri) {
return new Promise(
(resolve, reject) => {
firebase
.storage()
.ref(`uploads/${filename}`)
.putFile(uri)
.then(resolve)
.catch(reject);
}
);
}
Then simply firing both function as you need, here is the sample to pick and immediately upload it.
const pickImageAndUpload = async () => {
const uri = await pickImage();
const fileName = 'someImage.jpg';
const { state, downloadURL } = await uploadImage(fileName, uri);
}
async function uploadImageAsync(itemImage, passedParameter, ItemName, ItemDesc, ItemPrice, ItemWeight) {
const response = await fetch(itemImage);
const blob = await response.blob();
console.log("uri of the elements ius", blob)
var storageRef = firebase.storage().ref();
var file = blob
var metadata = {
contentType: 'image/jpeg',
};
const timeStamp = Date.now();
var uploadTask = storageRef.child('CategoryDescription' + "/" + `${passedParameter}` + "/" + `${ItemName}`).put(file, metadata);
//For image pick
pickImage = async () => {
const { CAMERA, CAMERA_ROLL } = Permissions;
const permissions = {
[CAMERA]: await Permissions.askAsync(CAMERA),
[CAMERA_ROLL]: await Permissions.askAsync(CAMERA_ROLL),
};
if (permissions[CAMERA].status === 'granted' && permissions[CAMERA_ROLL].status === 'granted') {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: false,
aspect:[4,3],
quality: 0.5,
});
// console.log(result);
if (!result.cancelled) {
this.setState({ itemImage: result.uri });
}
}