Uploaded image (base64) looks corrupted in firebase putString method - firebase

I am uploading an image(base64) to firebase with putString method
uploadTask = fireStorage.ref('/your/path/here').child('file_name').putString(snapshot, 'base64', { contentType: 'image/jpg' });
Its a valid base64 content (since its a huge string that's why I can paste it here. But I have already checked it by decoding it to image online) But it starts something like this
/9j/4AAQSkZJRgABAQAAkACQAAD/4QCMRXhpZgAATU0AKgAAAAgABQES
The uploaded(to firebase) image looks empty like a box of 1pixel.
This is the URL image
https://firebasestorage.googleapis.com/v0/b/manage-my-rides-1493889860531.appspot.com/o/lala%2Fchild.jpg?alt=media&token=63c9078a-7124-41a1-9349-6a2f2c6d8379
Code of firebase
var uploadedFile = await fireStorage.ref("lala").child("child.jpg").putString(snapshot, 'base64', {
contentType: 'image/jpg'
});
var url = await fireStorage.ref("lala").child("child.jpg").getDownloadURL();
console.log(url);

I've tried setting the base64 using various methods and it doesn't seem to work. The image gets seems to get corrupted during storage
Here's a quick workaround
fetch(YOUR_ORIGINAL_BASE_64_STRING)
.then(res => res.blob())
.then(blob =>
fireStorage.ref('/your/path/here').child('file_name').put(blob);
)
Example
var url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=="
let storageRef = firebase.storage().ref().child('image');
fetch(url)
.then(res => res.blob())
.then(blob =>
storageRef.put(blob).then(function(snapshot) {
console.log(snapshot)
console.log('Uploaded a blob!');
})
)

Related

The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.(Tried every answer)

I tried every answer related to my question on this site and google but it did not resolve my question.
I am trying to upload an image to my google bucket storage and get the download link.
I upload my image successfully. But the download link not working.
async uploadFiles(
imageBuffer: Buffer,
filename: string,
imageData: string,
file: Express.Multer.File,
) {
const bucket = admin.storage().bucket('mybucket.appspot.com');
const fullPath = `${uuid()}-${filename}`;
const bucketFile = bucket.file(fullPath);
await bucketFile.save(imageBuffer, {
contentType: file.mimetype,
gzip: true,
});
const [url] = await bucketFile.getSignedUrl({
action: 'read',
expires: '03-01-2500',
contentType: file.mimetype,
});
console.log(url);
return url;
}
This is my return URL value.
https://storage.googleapis.com/ecoms-dev.appspot.com/83a50c9d-8811-4209-964b-ebc3aeeed642-Screenshot%202022-06-10%20201411.png?GoogleAccessId=firebase-adminsdk-qa8ey%40ecoms-dev.iam.gserviceaccount.com&Expires=16730303400&Signature=PAVEwBs5iLTg6WZ6A17IN3gBC%2FbKtYNQkBHi5y7QKHgppDDGXmTxs6C%2FVSeKi9Qg5vTDn926VkrrVlNiVlOVb1D3PLnPJv1QAV0uholTzpWLuu6hST7DVkMfiDQ0dSgeRWauw06fqcBfGBR9iIrmzAtqlRVHGiukus7mly7ZtLQrwAzfu51qeK%2BNnqpeZdarkUIJA35fj%2FWsohP36qkd4ljRmtU%2FfwbK5QBtiP2uQ5PZrvL8p8%2BQkVWeo%2Fcc37pXUARAWubXv428wVryPHtU%2FYUaT5%2BNpWROmhbOXL9CsYfIqBXSfZZMF%2FKUQ%2F1W%2F7GC7Oe4xzUmFGw7dLEjPVkHiQ%3D%3D
But when I tried to paste this url into my chrome... It returns an error like my topic.
Any idea about that. I am stuck with this error all day.😢
I found a solution for my own answer.🤭😍
const file = admin.storage().bucket("my bucket").file(`profile_photos/${uid}`);
await file.save(base64Image, {
metadata: {
contentType: 'image/jpeg',
},
predefinedAcl: 'publicRead'
});
const metaData = await file.getMetadata()
const url = metaData[0].mediaLink

React Native base64 Image Upload to Firebase Storage

I am currently working on an App. The workflow I currently have is fairly simple.
A user creates an account, and then is taken to a page to populate their profile information. Name, description, and a few images.
I use expo's ImagePicker to get the image:
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 0.1,
allowsEditing: true,
aspect: [2, 3],
base64: true
});
Originally, I was using this to upload the images:
// Why are we using XMLHttpRequest? See:
// https://github.com/expo/expo/issues/2402#issuecomment-443726662
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", uri, true);
xhr.send(null);
});
const ref = firebase
.storage()
.ref()
.child(uuid.v4());
const snapshot = await ref.put(blob);
// We're done with the blob, close and release it
blob.close();
let url = await snapshot.ref.getDownloadURL();
return url;
The problem here is I looped through that function about 6 times, and I kept getting some obscure error.
Currently, I am attempting to upload the images using this:
const ref = firebase
.storage()
.ref()
.child(uuid.v4());
const snapshot = await ref.putString(b64Url, "data_url");
This works well on web, but in the native app I get the error:
FirebaseStorageError {
"code_": "storage/invalid-format",
"message_": "Firebase Storage: String does not match format 'base64': Invalid character found",
"name_": "FirebaseError",
"serverResponse_": null,
}
The last comment on this issue outlines the problem. To break it down: atob doesn't exist. This is the sole problem behind the error. To fix, I polyfilled it like this:
import { decode, encode } from "base-64";
if (!global.btoa) {
global.btoa = encode;
}
if (!global.atob) {
global.atob = decode;
}
However, the second problem is that:
Firebase also tries to use the native Blob class (implemented by react-native), but the react-native version of Blob incorrectly converts the Uint8Array data to a string, corrupting the upload.
I tried his solution of deleteing global.Blob and restoring it after the upload. Firebase must have become dependent upon blob though, because now it errors out since Blob doesn't exist. Edit: Blob is actually being called somewhere in AppEntry.bundle, the uploading works correctly.
I would like to keep my app in a managed workflow, so I would very much prefer not to eject.
My questions are as follows:
Where specifically in react-native is the broken Blob code that:
incorrectly converts the Uint8Array data to a string
Is there a way that I can, while avoiding errors or ejecting, upload 6 images at once to firebase storage? If so, how?
The solution I ended up following was this:
async function uploadImageAsync(uri) {
const ref = firebase
.storage()
.ref()
.child(uuid.v4());
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";
xhr.open("GET", uri, true);
xhr.send(null);
});
var mimeString = uri
.split(",")[0]
.split(":")[1]
.split(";")[0];
const snapshot = await ref.put(blob, { contentType: mimeString });
let url = await snapshot.ref.getDownloadURL();
return url;
}
I found that I could not seem to get firebase's putString function to work, but I could create a blob out of the string using XMLHttpRequest. Then I just upload the blob to firebase

Convert relative image to base64 or use your relative image to upload to firebase storage using node

Has anyone achieved this before? I keep getting the following error below.
I am also using base64-img to convert my local images to base64.
Error:
throw invalidFormat(format, 'Invalid character found');
^
FirebaseError: Firebase Storage: String does not match format 'base64': Invalid character found
Request:
...
import base64Img from 'base64-img';
const app = express()
app.get('/', function (req, res) {
res.send('hello world')
let url = './images/girl.jpg'
base64Img.base64(url, function(err, data) {
console.log(data)
let fileName = "girl.jpg";
const metadata = {
contentType: "image/jpeg"
};
let strImage = data.split("base64,")[1];
console.log(strImage)
let storageRef = storage.ref(`images/${fileName}`);
storageRef.putString(strImage, 'base64', metadata)
});
....
I decided to scratch converting my image to base64 and upload the local image. This was the original task I was going for. After much digging this works for uploading your relative image to firebase storage.
let filename = './images/girl.jpg' <--my local path in my project
const bucket = admin.storage().bucket();
bucket.upload(filename, {
//destination: 'users/images/girl.jpg', <---Optional if you want folders, leave blank for root
gzip: true,
metadata: {
cacheControl: 'public, max-age=31536000'
}
}).then(() => {
console.log(`${filename} uploaded.`);
}).catch(err => {
console.error('ERROR:', err);
});

Right way to show images stored in firebase.storage?

When my user uploads and image, the app saves it in firebase storage and gets the download-url and saves it in the database. I use the url in the database to show the image but it gets really really slow (< 2 seconds) to show the image. On the other hand, firebase database is blazing fast.
Is this the correct way to show images or am I doing something that is non performant?
Edit: I have seen other posts that also have slowness issues but none of them seem to have a solution (example). I live in Europe and storage is in the US. The images are under 400kb, so that shouldn't be an issue.
Code:
// creating reference
const imageRef = firebase.storage().ref(`/jobs/${currentUser.uid}/${jobUID}`).child(name)
// creating a Blob using fileReader
fs.readFile(uploadUri, 'base64')
.then((data) => {
console.log('data from readFile: ', data)
return Blob.build(data, { type: `${mime};BASE64` })
})
.then((blob) => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime, name: name })
.then(url => {
// URL used to display image
let imgUrl = url.downloadURL
// upload url to database
let storageRef = firebase.database().ref(`/jobs/activeJobs/${currentUser.uid}/${jobUID}/`);
storageRef.update(photo1).then(() => console.log('success'))
To retrieve the image I just place the downloadURL in an Image tag

Uploading Image to Firebase in React Native

I have two image paths in my component state
I try to upload one of the images inside of a function but get an error:
Firebase Storage: Invalid argument in 'put' at index 0: Expected Blob or file
and my function
submitImages = () => {
// Upload images to Firebase storage
let user = firebaseAuth.currentUser;
let imagesRef = storageRef.child('productImages/' + user.uid);
imagesRef.put(this.state.imageFront).then(snapshot => {
console.log('Uploaded ' + this.state.imageFront);
});
}
What should I be doing instead to get these images up to Firebase. Thanks!
What the error says is that you need to use a blob. You can use react-native-fetch-blob: https://github.com/wkh237/react-native-fetch-blob
Check out this example: https://github.com/dailydrip/react-native-firebase-storage/blob/master/src/App.js#L43-L69
I am posting my code since this was a bit frustrating for me:
To upload images to firebase.storage you need to upload the images as Blobs. If you don't know what Blobs are, don't worry: BLOB stands for Binary Large OBject.
Step 1.
npm install --save react-native-fetch-blob
Step 2.
// copy and paste this code where you will handle the file upload
import RNFetchBlob from 'react-native-fetch-blob'
const Blob = RNFetchBlob.polyfill.Blob;
const fs = RNFetchBlob.fs;
window.XMLHttpRequest = RNFetchBlob.polyfill.XMLHttpRequest;
window.Blob = Blob;
Step 3.
// The uploadImage function that you are going to use:
function uploadImage(uri, mime = 'image/jpeg', name) {
return new Promise((resolve, reject) => {
let imgUri = uri; let uploadBlob = null;
const uploadUri = Platform.OS === 'ios' ? imgUri.replace('file://', '') : imgUri;
const { currentUser } = firebase.auth();
const imageRef = firebase.storage().ref(`/jobs/${currentUser.uid}`)
fs.readFile(uploadUri, 'base64')
.then(data => {
return Blob.build(data, { type: `${mime};BASE64` });
})
.then(blob => {
uploadBlob = blob;
return imageRef.put(blob, { contentType: mime, name: name });
})
.then(() => {
uploadBlob.close()
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error)
})
})
}
So how do you call this function?
Pass the URI of the image as the first argument. In my case img1, img2, img3 where variables that pointed to the URIs of the images, that I wanted to upload which were on my phone. They looked something like '/Phone/Pics/imageToUpload.jpeg', etc.
As the second argument you can pass 'image/jpeg' and the last argument is the name that you want to give the image. Chose the name that you like.
But what if I have several images and want to upload them and want to handle the upload correctly. What if one upload succeeds and the other does not?
Do this then:
let imgPromises = [];
imgPromises.push(uploadImage(img1, 'image/jpeg', 'imageOne'));
imgPromises.push(uploadImage(img2, 'image/jpeg', 'imageTwo'));
imgPromises.push(uploadImage(img3, 'image/jpeg', 'imageOne'));
Promise.all(imgPromises).then(urls => {
// ALL IMAGES SUCCEEDED and you will get an array of URIS that you can save to your database for later use!
}).catch(error => {
// One OR many images failed the upload. Give feedback to someone.
})
You can use react-native-firebase to upload image to storge https://rnfirebase.io/
const storage = firebase.storage();
const sessionId = new Date().getTime();
const imageRef = storage.ref('images').child(`${sessionId}`);
return imageRef.putFile(uri);
So far this is the best method I found to upload a file/image to a Firebase Storage with React Native. This method does not use any third party libraries except for the Expo SDK.
Get the File URI of the image to upload. To do this we will need to use Expo ImagePicker. The best place to include this code block is on to a button with an onPress handler.
ImagePicker.launchImageLibraryAsync({
mediaTypes: "Images"
}).then((result)=>{
if (!result.cancelled) {
// User picked an image
const {height, width, type, uri} = result;
return uriToBlob(uri); // will follow later
}
})
Generate a BLOB from the image URI. There are a lot of third party libraries to help do this. But if you don't want to install a library, then you can use XMLHttpRequest. The React Native docs recommends we use the Fetch API, but right now we can't use it because it will throw an error that we can only fetch https:// urls, but our URI is a file://. There is a way to get pass this, but using XMLHttpRequest will make things a lot simpler.
uriToBlob = (uri) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function() {
// return the blob
resolve(xhr.response);
};
xhr.onerror = function() {
// something went wrong
reject(new Error('uriToBlob failed'));
};
// this helps us get a blob
xhr.responseType = 'blob';
xhr.open('GET', uri, true);
xhr.send(null);
});
}
We have our BLOB, let's upload it to Firebase. This part is pretty straightforward as explained in the Firebase Docs.
uploadToFirebase = (blob) => {
return new Promise((resolve, reject)=>{
var storageRef = firebase.storage().ref();
storageRef.child('uploads/photo.jpg').put(blob, {
contentType: 'image/jpeg'
}).then((snapshot)=>{
blob.close(); // let's free up the blob
resolve(snapshot);
}).catch((error)=>{
reject(error);
});
});
}
That's it, you can now upload a file to Firebase Storage. The key part to this is getting a File URI and converting it to a BLOB. You can read more about this method here.
For some time I used the Firebase JS SDK with React Native. Using this library, as referred in this thread you need to use a library like rn-fetch-blob (react-native-fetch-blob is not maintained anymore) in order to provide a blob to Firebase Storage put() method.
Recently I started using React Native Firebase. As they say in their website "Using the native Firebase SDKs with React Native Firebase allows you to consume device SDKs which don't exist on the Firebase JS SDK".
Using React-Native-Firebase you don't need any extra library to upload images to Firebase Storage, and your code gets much cleaner:
export const uploadImage = (path, mime = 'application/octet-stream') => {
return new Promise((resolve, reject) => {
const imageRef = firebase.storage().ref('images').child('filename.jpg');
return imageRef.put(path, { contentType: mime })
.then(() => {
return imageRef.getDownloadURL();
})
.then(url => {
resolve(url);
})
.catch(error => {
reject(error);
console.log('Error uploading image: ', error);
});
});
};
if you don’t mind using cloudinary, I show how to upload and then get the uploaded url to save to firebase
https://medium.com/#ifeoluwaking24/how-to-upload-an-image-in-expo-react-native-to-firebase-using-cloudinary-24aac981c87
Also you can try it snack but make sure you add your cloud_name and upload_preset
https://snack.expo.io/#ifeking/upload-to-cloudinary

Resources