Firebase storage is uploading image as 9B file - javascript

I am working on a program to upload image. I am using "expo-image-picker" to pick the image and it is correctly updating the "image" state as we can see below. Code executes and image file gets uploaded in Firebase storage but its uploaded as 9 bytes file and not as full 2.4 mb image.
Please help me understand the mistake that I am making.
image value:
file:///var/mobile/Containers/Data/Application/15A92FD5-894C-47D6-ABEF-36F73CA7F778/Library/Caches/ExponentExperienceData/%2540anonymous%252Fapp26Apr-a5cceae1-72c0-4cec-a926-ffb46822d087/ImagePicker/C7ABC0E1-80FC-4B87-A1AD-8B6DD4A1BB9A.jpg
uploadUri value:
/var/mobile/Containers/Data/Application/15A92FD5-894C-47D6-ABEF-36F73CA7F778/Library/Caches/ExponentExperienceData/%2540anonymous%252Fapp26Apr-a5cceae1-72c0-4cec-a926-ffb46822d087/ImagePicker/C7ABC0E1-80FC-4B87-A1AD-8B6DD4A1BB9A.jpg
filename value:
C7ABC0E1-80FC-4B87-A1AD-8B6DD4A1BB9A.jpg
const uri = image;
const filename = uri.substring(uri.lastIndexOf("/") + 1);
const uploadUri = Platform.OS === "ios" ? uri.replace("file://", "") : uri;
firebase
.storage()
.ref(filename)
.put(uploadUri)
.then((value) => {
console.log("Image uploaded");
});

I could find the solution of using blob to save the image. Sharing it below in case anyone faces same issue.
let uri = image;
const filename = uri.substring(uri.lastIndexOf("/") + 1);
const uploadUri = Platform.OS === "ios" ? uri.replace("file://", "") : uri;
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", uri, true);
xhr.send(null);
});
firebase
.storage()
.ref()
.child("user/" + userid)
.put(blob)
.then((uri) => {
console.log(uri);
})
.catch((error) => {
console.log(error);
});

I faced the same problem and found the solution after a couple of hours. You have to convert your image to a file/blob format and put it on put().
The solution is like below code :
fetch(filePath)
.then(response => {
return response.blob();
})
.then(blob => {
const storageRef = firebase.storage().ref().child('test.png');
storageRef.put(blob).then(snapshot => {
console.log('Uploaded a blob or file!');
});
});

Related

Getting pdf file from from express and treating it as if it from an input

i am trying to make a component that take a pdf from input or an already uploaded one and then extract pages from it and uploaded again
when choosing a file from input (choosing file from my computer)
i am using this
const handleFileChange = async (event) => {
const file = event.target.files[0];
setFiles(event.target.files[0])
const fileName = event.target.files[0].name
setFileName(fileName);
const fileReader = new FileReader();
fileReader.onload = async () => {
const pdfBytes = new Uint8Array(fileReader.result);
const pdfDoc = await PDFDocument.load(pdfBytes);
setPdfDoc(pdfDoc);
setPdfBlob(pdfBytes)
};
fileReader.readAsArrayBuffer(file);
setShowPdf(true)
};
we get a pdfDoc and a Unit8Array
then i use the pdfDoc to get pages and extract a new pdf file....
this works fine
now when selecting a file that we already uploaded
i use this to ping the api to get the file
const handleGetFile = async (url) => {
const headers = {
Authorization: "Bearer " + (localStorage.getItem("token")),
Accept: 'application/pdf'
}
await axios.put(`${process.env.NEXT_PUBLIC_API_URL}getPdfFileBlob`, {
pdfUrl: `https://handle-pdf-photos-project-through-compleated-task.s3.amazonaws.com/${url}`
}, { responseType: 'arraybuffer', headers }).then((res) => {
const handlePdf = async () => {
const uint8Array = new Uint8Array(res.data);
const pdfBlob = new Blob([uint8Array], { type: 'application/pdf' });
setPdfBlob(uint8Array)
// setPdfDoc(pdfBlob) .....? how do i create a pdf doc from the unit8array
}
handlePdf()
}).catch((err) => {
console.log(err)
})
}
this the the end point i am pinging
app.put('/getPdfFileBlob',async function(req,res){
try {
console.log(req.body.pdfUrl)
const url =req.body.pdfUrl;
const fileName = 'file.pdf';
const file = fs.createWriteStream(fileName);
https.get(url, (response) => {
response.pipe(file);
file.on('finish', () => {
file.close();
// Serve the file as a response
const pdf = fs.readFileSync(fileName);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader( 'Content-Transfer-Encoding', 'Binary'
);
res.setHeader('Content-Disposition', 'inline; filename="' + fileName + '"');
res.send(pdf);
});
});
} catch (error) {
res.status(500).json({success:false,msg:"server side err"})
}
})
after getting this file here is what am trying to do
const handlePageSelection = (index) => {
setSelectedPages(prevSelectedPages => {
const newSelectedPages = [...prevSelectedPages];
const pageIndex = newSelectedPages.indexOf(index);
if (pageIndex === -1) {
newSelectedPages.push(index);
} else {
newSelectedPages.splice(pageIndex, 1);
}
return newSelectedPages;
});
};
const handleExtractPages = async () => {
for (let i = pdfDoc.getPageCount() - 1; i >= 0; i -= 1) {
if (!selectedPages.includes(i + 1)) {
pdfDoc.removePage(i);
}
}
await pdfDoc.save();
};
well in the first case where i upload the pdf file from local storage i get a pdfDoc
console of pdf Doc and pdfBlob
and when i select already existing file i can't find a way to transfer unit8array buffer to pdf doc
log of pdfBlob and no pdf doc
what i want is transform the pdfblob to pdfDcoument or get the pdf document from the array buffer so i can use getpages on it

How to make firebase image path work as an image on different devices on React Native?

I have a function that requests the user for an image from their phone. Once this is given, the path is uploaded to firebase and looks something like this:
file:///var/mobile/Containers/Data/Application/9C627709-0F0C-4A2A-939E-9206DA91032C/Library/Caches/ExponentExperienceData/%2540user%252FAPP/ImagePicker/1B5D0907-8ED5-46DC-B216-7DEF7992C1BF.jpg"
The problem is that on the attempt to display it only displays on the phone that this image has been uploaded on, since other devices do not possess this image.
How can I convert the firebase path/image into an image that is displayable in all phones, even though this image does not exist on all users devices?
Here is some important bits of code:
function that gets the library image
const addImage = async () => {
let image = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!image.cancelled) {
setGalleryImage(image.uri);
}
};
function that adds the image to firebase:
const createPhoto = async () => {
await db
.collection("data")
.doc(route?.params?.docId)
.set(
{
galleryImage,
}
)
.then(() => {
})
.catch(error => alert(error));
};
Jsx that displays the image:
<Image
source={{ uri: galleryImage }}
onLoadStart={() => setIsLoading(true)}
onLoadEnd={() => setIsLoading(false)}
/>
Any help is appreciated
This is because, you are saving the local path of the image, hence it can not be displayed on other phones. You need to upload the image to a storage bucket and save the URL of that image on the db.
Convert image to blob
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function() {
resolve(xhr.response);
};
xhr.onerror = function() {
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
// image.uri is the local path of the image on the device
xhr.open("GET", image.uri, true);
xhr.send(null);
})
Upload image to storage
const storageRef = ref(storage, `profile-pictures/${userContext.user.uid}/${name}`);
const task = uploadBytesResumable(storageRef, blob)
task.on('state_changed', (snapshot) => {
const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100
}, (err) => {
reject(err)
}, () => {
getDownloadURL(task.snapshot.ref)
.then((downloadURL) => {
// image successfully uploaded, save "downloadURL" in your db
})
})

Getting the download URL of an uploaded image synchronously in Firebase Storage

I'm using Firestore and Storage in a React Native project and I'm working on a feature that migrates SQLite data into Firebase. Once the user signs in for the first time, the migration process runs synchronously. Among the data to migrate there are base64 images and no matter what I do, despite using async/await everywhere, I get the DownloadURL "too late", after the migration process is done and the new data from Firestore is listed. So, I cant show the images at first, I have to reload the app.
My code:
const upload64BaseImage = async (photo, docRef) => {
try {
//fetch doesn't work with base64 images and Firebase Cloud Storage
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", photo, true);
xhr.send(null);
});
const imageRef = ref(storage, `images/${docRef}.jpg`);
const metadata = {
contentType: "image/jpeg",
};
const snapshot = await uploadBytes(imageRef, blob, metadata);
const downloadUrl = await getDownloadURL(snapshot.ref);
return downloadUrl;
} catch (error) {
console.log(`error`, error.message);
}
};
const createNewDocument = async (userId, data) => {
try {
const newUserRef = doc(collection(db, "users"));
const myTimestamp = Timestamp.fromDate(new Date(data.Birthdate));
const downloadUrl = await upload64BaseImage(data.Photo, newUserRef.id);
//crear un objeto
const newUserObjetc = {
UserId: userId,
Birthdate: myTimestamp,
Name: data.Name,
Surname: data.Surname,
Photo: downloadUrl || null,
};
await setDoc(newUserRef, newUserObjetc);
return newUserRef.id;
} catch (error) {
console.log(`error`, error.message);
}
};

Uploading an image to Firebase with React-Native

I'm using this method to try upload image to Firebase with my React-Native app because it seems to be a very common example on the internet, However I think it is quite old and I suspect that it no longer works on newer versions of React-Native.
Can someone please show me the correct way to save images in Firebase storage, thank you!
const uploadImage = (uri, imageName, mime = 'image/jpg') => {
return new Promise((resolve, reject) => {
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '')
: uri;
let uploadBlob = null
const imageRef = firebase.storage().ref('images/').child(imageName)
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 can just use the putFile method.
Here is my FirebaseStorageService with saveImage method (I'm using RN 0.53 and react-native-firebase 4.1.0):
saveImage(ref, image, imageName, onSuccess, onError){
LOG.debug("FirebaseStorageService :: saveImage ", {ref:ref, image:image, imageName:imageName});
var firebaseStorageRef = firebase.storage().ref(ref);
const imageRef = firebaseStorageRef.child(imageName + ".jpeg");
LOG.debug("FirebaseStorageService :: imageRef ", {imageRef:imageRef});
imageRef.putFile(image.path, {contentType: 'image/jpeg'}).then(function(){
return imageRef.getDownloadURL();
}).then(function(url){
LOG.debug("Image url", {url:url});
onSuccess(url);
}).catch(function(error){
LOG.error("Error while saving the image.. ", error);
onError(error);
});
}
The image is the one returned by react-native-image-crop-picker. User can choose between open camera and open gallery and it returns an image object.
The path property of the image object is just a string like "file://.." for Android and "/Users/..." for iOS.

React Native multiple images

Could you show me source code about uploading multiple images? I have tried to upload multiple images to my firebase. So i'm using react-native-image-crop picker for select images, and then react native-fetch-blob for convert the images before upload to firebase. After select images, i'm looping the arrays then converting to fetch blob inside looping. But sometimes it works but sometimes the images url is empty. I hope i can find the answer here
Try this:
const uploadImages = (photos) => {
const uploadImagePromises = _.map(photos, (p, index) => uploadImage({ uri: p, imageName: "image_" + index }))
const urls = await Promise.all(uploadImagePromises)
console.log(urls);
}
const uploadImage = ({ uri, imageName }) => {
const Blob = RNFetchBlob.polyfill.Blob
const fs = RNFetchBlob.fs
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest
window.Blob = Blob
const mime = 'image/jpg'
return new Promise((resolve, reject) => {
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri
let uploadBlob = null
const imageRef = firebase.storage().ref('/images/').child(imageName)
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()
resolve(imageRef.getDownloadURL())
})
.catch(error => {
console.log("error", error);
reject()
})
})
}

Categories