Save base64 encoded image to Firebase Storage

29,243

Solution 1

The latest version of the Firebase SDK supports base64 image uploads. Simply use the putString method from Firebase Storage.

https://firebase.google.com/docs/reference/js/firebase.storage

One small caveat is that sometimes you'll have a base64 String with unnecessary whitespace. For example, I've found that the cordova Camera plugin returns base64 with unnecessary whitespace. The Storage SDK will fail to upload this because JavaScript can't perform it's native atob function - something the Firebase JS does under the hood. You'll have to strip the whitespace - see DOM Exception 5 INVALID CHARACTER error on valid base64 image string in javascript

Solution 2

You only need to use the putString function without converting the BASE64 to blob.

firebase.storage().ref('/your/path/here').child('file_name')
.putString(your_base64_image, ‘base64’, {contentType:’image/jpg’});

Make sure to pass the metadata {contentType:’image/jpg’} as the third parameter (optional) to the function putString in order for you to retrieve the data in an image format.

or simply put:

uploadTask = firebase.storage().ref('/your/path/here').child('file_name').putString(image, 'base64', {contentType:'image/jpg'});
uploadTask.on(firebase.storage.TaskEvent.STATE_CHANGED, // or 'state_changed'
  function(snapshot) {
    // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
    var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
    console.log('Upload is ' + progress + '% done');
    switch (snapshot.state) {
      case firebase.storage.TaskState.PAUSED: // or 'paused'
        console.log('Upload is paused');
        break;
      case firebase.storage.TaskState.RUNNING: // or 'running'
        console.log('Upload is running');
        break;
    }
  }, function(error) {
    console.log(error);
}, function() {
  // Upload completed successfully, now we can get the download URL
  var downloadURL = uploadTask.snapshot.downloadURL;
});

You can then use the downloadURL to save to firebase.database() and/or to put as an src to an <img> tag.

Solution 3

Yes, it's possible now. You should use Firebase Storage new method called putString. You may read spec here.

So, Firebase spec says that you have now two methods to store Base64 string and Base64url string:

// Base64 formatted string
var message = '5b6p5Y+344GX44G+44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
ref.putString(message, 'base64').then(function(snapshot) {
  console.log('Uploaded a base64 string!');
});

// Base64url formatted string
var message = '5b6p5Y-344GX44G-44GX44Gf77yB44GK44KB44Gn44Go44GG77yB';
ref.putString(message, 'base64url').then(function(snapshot) {
  console.log('Uploaded a base64url string!');
})

From my experience, using putString(message, 'base64url') constantly returns Error about bad formated Base64 string code: "storage/invalid-format", message: "Firebase Storage: String does not match format 'base64': Invalid character found". The solution is to cut off beginning of string data:image/jpeg;base64, and use first method instead putString(message, 'base64'). Then it works.

Solution 4

If you use canvas.toBlob() you'll get the byte[] that you need to pass into Firebase Storage.

Quick example:

function save() {
    var canvas = document.getElementById("canvas");
    canvas.toBlob(blob => {
      var storage = firebase.app().storage().ref();
      var name = id + "/" + (new Date()).getTime() + ".png";
      var f = storage.child("drawings/" + name);
      var task = f.put(blob);
      task.on('state_changed', function(snapshot) {
      }, function(error) {
        console.error("Unable to save image.");
        console.error(error);
      }, function() {
        var url = task.snapshot.downloadURL;
        console.log("Saved to " + url);

        var db = firebase.database();
        var chats = db.ref().child("chats");
        chats.child(id).child("drawingURL").set(url);
      });
    });
  };

Otherwise you'll have to convert the base64 yourself, for example with atob().

Solution 5

This solution works for me using the Google Cloud Storage API.
But it should work also with the Firebase one by replacing the file.save with the ref put method.

const file = storage.file(file_path_in_gs)
const contents = new Uint8Array(Buffer.from(base64ImgStr, 'base64'))
  file.save(contents,
    {
      contentType: img_type,
      metadata: {
        metadata: {
          contentType: img_type,
          firebaseStorageDownloadTokens: uuid()
        }
      }
    }
    , () => { })
Share:
29,243
Sebastian Sandqvist
Author by

Sebastian Sandqvist

Updated on June 08, 2020

Comments

  • Sebastian Sandqvist
    Sebastian Sandqvist about 4 years

    Using firebase 3.0.x, is it possible to save a base64 encoded image to the new Firebase Storage service?

    I am using canvas to resize images in the browser prior to uploading them, and output them as a base64 jpeg. I know that the Storage api can accept Blobs, but IE9 support is needed for my current project.

  • Sebastian Sandqvist
    Sebastian Sandqvist about 8 years
    I wish I could use .toBlob, but it isn't supported at all by Safari or IE<10. Even the polyfill is not supported by IE9.
  • Hobbyist
    Hobbyist about 8 years
    You could also convert the b64 to a blob manually, see my answer.
  • Miguel Peguero
    Miguel Peguero over 6 years
    I solved this issue by addin : let file = image.split(',')[1] storeRef(file,'base64', {contentType:'image/png'}); //take only the image data
  • oded bartov
    oded bartov over 3 years
    where did you get the first object 'firebase'? what is this object?
  • oded bartov
    oded bartov over 3 years
    where did you get the first object 'ref'? what is this object?
  • oded bartov
    oded bartov over 3 years
    where should i use the putString method? the firebase-admin don't has it
  • oded bartov
    oded bartov over 3 years
    But how do you get the 'ref' for this? i struggle for a long time about it
  • Niño Angelo Orlanes Lapura
    Niño Angelo Orlanes Lapura almost 3 years
    @odedbartov that's the firebase instance
  • Wilfred Almeida
    Wilfred Almeida over 2 years
    The const contents = new Uint8Array(Buffer.from(base64ImgStr, 'base64')) is important. I did contents=base64ImgStr and it didn't work.