Upload base64 string to Firebase Storage

12,682 views
Skip to first unread message

Luis Martinez

unread,
Jan 2, 2018, 12:56:46 PM1/2/18
to Firebase Google Group
Hello,

I am trying to create a Google function that will accept base64 string and save to the Firebase Storage. I've tried two versions, one derived from the docs using file.save() , and another found on Stackoverflow, they both seem to work however the image does not load nor does it allow me to created an download link (see attachment). I not am sure what the issues is, I've tried uploading files with and without "data:image/jpeg;base64,..." and the issue is the same. For now I will using the Firebase Javascript sdk which I want to avoid because I am want the Google function to handle data from the web and app client.

Any suggestions? 


Version 1
const { fileName, imgFile } = req.body;
const bucketRef = admin.storage().bucket();
const file = bucketRef.file(`directory/${fileName}`);

    file
.save(base64Img, {
      metadata
: {
        contentType
: 'image/jpeg',
        metadata
: {
          custom
: 'metadata'
       
},
       
public: true,
        validation
: 'md5'
     
},
   
}, err => {
     
if (err) {
        res
.send({ err });
     
}
      res
.send({ msg: 'image uploaded' });
   
});


Version 2
import stream from 'stream';

const { fileName, imgFile } = req.body;
const bucketRef = admin.storage().bucket();
const file = bucketRef.file(`directory/${fileName}`);

const bufferStream = new stream.PassThrough();
    bufferStream
.end(Buffer.from(imgFile, 'data_url'));
    bufferStream
.pipe(file.createWriteStream({
      metadata
: {
        contentType
: 'image/jpeg',
        metadata
: {
          custom
: 'metadata'
       
}
     
},
     
public: true,
      validation
: 'md5'
   
}))
     
.on('error', err => {
        res
.send({
          err
       
});
     
})
     
.on('finish', () => {
        res
.send({ msg: 'image uploaded' });
     
});


Screen Shot 2018-01-02 at 11.02.09 AM.png

Spencer Phippen

unread,
Jan 3, 2018, 3:07:20 PM1/3/18
to Firebase Google Group
Hello,

It looks like these aren't complete code samples, so I can't test them out exactly, but I've noticed a few things.

1. The Stackoverflow link in your answer doesn't link to anywhere. Maybe you forgot to put the link in?
2. In the second example, you call "Buffer.from(imgFile, 'data_url')", but in the versions of node that I tried I couldn't get "data_url" to work as a string encoding and didn't find anything about it in the documentation.
3. I'm not sure where you're getting "base64Img" from in your first example, but if that's a string containing base64-encoded data, then the code would probably be creating an object containing the characters in the base64 string, not the actual binary data from your image. Even if you can't get a download URL out of the Firebase Storage console, you should be able to use the Cloud-style Google Cloud Storage console at https://console.cloud.google.com to download your object and verify that it contains the data you meant to upload.

If you can whittle your code down a complete minimal example that reproduces the unexpected behavior, that would make it easier to figure out what's going on.

- Spencer P

Luis Martinez

unread,
Jan 12, 2018, 10:22:31 AM1/12/18
to Firebase Google Group
Hello, 

1) My apologies, this is the link I was referring to https://stackoverflow.com/questions/42879012/how-do-i-upload-a-base64-encoded-image-string-directly-to-a-google-cloud-stora, which what I based the 2nd code sample.
2) Correct, "data_url"  was a mistake, it should be "base64" from the node docs but even that didn't work as intended.
3) Yes, "base64Img" is the string "data:image/jpg;base64,R0l..." as such, the files 

I would like to be able to generate a download URL once it's uploaded, so that I can serve the image to different clients. I am not familiar with the console nor how it will allow me to achieve serving the images to clients. The web sdk allows for base64 string upload and returns a downloadURL, so I was hoping to have that functionality a Google Function instead so that I could simply send it base64 strings and get the downloadURLs. Does the make sense? I apologies if I does not. 

The 2 code examples essentially do the same, here's a simpler version of the 1st example. 

    // Google function accepts request containing base64 string
   
const { base64Img } = req.body

   
// Bucket reference
   
const
file = bucketRef.file(`directory/${fileName}`);
   
   
// file.save uses createWriteStream
    file.save(base64Img, {
      metadata
: {
        contentType
: 'image/jpeg',

Florian Duboc

unread,
Mar 12, 2018, 9:20:27 PM3/12/18
to Firebase Google Group
Hi,
I have the same problem with firebase ...
The file can not be downloaded from the Firebase console but can be downloaded from the Google Cloud platform.

Did you find a solution ?

Florian Duboc

unread,
Mar 13, 2018, 4:36:00 PM3/13/18
to Firebase Google Group
Ok, I get it to work.

I put the code just in case.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.publish = functions.https.onRequest((req, res) => {

    // Convert the base64 string back to an image to upload into the Google Cloud Storage bucket
    var base64EncodedImageString = req.body.Thumbnail64,
        mimeType = 'image/jpeg',
        fileName = 'Thumbnail64.jpg',
        imageBuffer = new Buffer(base64EncodedImageString, 'base64');

    var bucket = admin.storage().bucket();

    // Upload the image to the bucket
    var file = bucket.file('profile-images/' + fileName);
    file.save(imageBuffer, {
        metadata: { contentType: mimeType },
    }, ((error) => {

        if (error) {
            return res.status(500).send('Unable to upload the image.');
        }
            return res.status(200).send('Uploaded');
    }));
})

Subhash Rawat

unread,
Jan 2, 2020, 9:59:53 AM1/2/20
to Firebase Google Group
After spending, time got the success 

I didn't know how to @Florian code is Working but have used the same code it getting the same issues I checked the code there is "firebaseStorageDownloadTokens" is missing.. I use the below code which is working perfectly

const uuidv4 = require('uuid/v4');
const uuid = uuidv4();

    const os = require('os')
    const path = require('path')
    const cors = require('cors')({ origin: true })
    const Busboy = require('busboy')
    const fs = require('fs')
    var admin = require("firebase-admin");


    var serviceAccount = {
        "type": "service_account",
        "project_id": "xxxxxx",
        "private_key_id": "xxxxxx",
        "private_key": "---",
        "client_email": "",
        "client_id": "xxxxxxxx",
        "auth_uri": "https://accounts.google.com/o/oauth2/auth",
        "token_uri": "https://oauth2.googleapis.com/token",
        "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
        "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-5rmdm%40xxxxx.iam.gserviceaccount.com"
      }

    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        storageBucket: "xxxxx-xxxx" // use your storage bucket name
    });


    const app = express();
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
app.post('/uploadFile', (req, response) => {
    response.set('Access-Control-Allow-Origin', '*');
    const busboy = new Busboy({ headers: req.headers })
    let uploadData = null
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
        const filepath = path.join(os.tmpdir(), filename)
        uploadData = { file: filepath, type: mimetype }
        console.log("-------------->>",filepath)
        file.pipe(fs.createWriteStream(filepath))
      })

      busboy.on('finish', () => {
        const bucket = admin.storage().bucket();
        bucket.upload(uploadData.file, {
            uploadType: 'media',
            metadata: {
              metadata: { firebaseStorageDownloadTokens: uuid,
                contentType: uploadData.type,
              },
            },
          })

          .catch(err => {
            res.status(500).json({
              error: err,
            })
          })
      })
      busboy.end(req.rawBody)
   });




exports.widgets = functions.https.onRequest(app);
Reply all
Reply to author
Forward
0 new messages