Search code examples
mysqlnode.jsexpresssequelize.jsblob

Saving image blob by decoding base64 with sequelize v5


I want to save received base64 string in mysql table in a BLOB field. I have used sequelize version 5 as my ORM and the model is defined as follows.

sequelize.define('PLAYER', {
        player_id: {
            primaryKey: true,
            type: DataTypes.INTEGER,
            allowNull: false,
            autoIncrement: true
        },
        player_name: DataTypes.STRING,
        player_image:  {
            type: DataTypes.BLOB('medium'),
            get () {
                 let data = this.getDataValue('player_image');
                 return data ? data.toString('base64') : '';
            }
    }
}

In my put method,

db.PLAYER.findByPk(req.params.playerId).then((player)=>{

  if (req.body.player_image) {
     const base64 = req.body.player_image.replace(/^data:image\/[a-z]+;base64,/, "");

     const blob = b64toBlob(base64, 'image/jpeg');
     player.player_image = blob;
  }

  player.player_name = req.body.player_name;

  player.save().then(() => {
      res.status(200).json(player);
  }).catch(function (err) {
      return next(err);
  });
});

For Base64 to Blob conversion.

const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
    const byteCharacters = atob(b64Data);
    const byteArrays = [];

    for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize);

        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }

        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
    }

    const blob = new Blob(byteArrays, { type: contentType });

    return blob;
}

A blob is saving in the table but my response body is as follows. I have converted BLOB to base64 before sending the response.

{ 
  "player_id": 1032,
  "player_name": "Oliver Driscoll",
  "player_image": "[object Blob]"
}

Which means the saved blob is actually "[object Blob]". Not the image.

The received base64 (req.body.player_image) for the end point is confirmed as correct. I am running out of time and don't know what to do as this is the requirement (Saving the image as blob).


Solution

  • I Know, this is a old issue. But i had this same problem, and after so many tries, i was able to solve it. So, if anyone have this problem in the future, i will let my solution here:

    In my case i was able to get a Blob already, from a fetch response. So i have in my code like this:

    await fetch(imageUrl)
    .then(async (response) => {
      // GET Blob Object from response; can use response.arrayBuffer() directly too
      let myBlobImg = await response.blob();
    
      // Convert Blob.ArrayBUffer to a Buffer
      let myBufferImg = Buffer.from(await myBlobImg.arrayBuffer());
    })
    

    Then i just save myBufferImg on DB, as a Buffer. In your case @silent_27 could be

    player.player_image = Buffer.from(await myBlobImg.arrayBuffer());
    

    I'm using SQlite3 DataBase on NodeJS with sqlite3^5.0.1 package.

    I save like this on my dataBase and works fine. I've tried save like myBlobImg.text();. But this away, i was not able to load on a <img src={}> html tag in my application.

    If anyone need to know, to show this BLOB on a <img> HTML, i just do a get on my DB to get my ProductObject and convert to a base64 image:

    // imageData is the Buffer saved on BD. imageData.data is an Array from Buffer
    let imgBase64 = Buffer.from(product.productImage.imageData.data).toString('base64');
    imgBase64 = `data:image/jpeg;base64,${imgBase64}`;
    //....
    <img src={imgBase64}>
    

    I Had to use Buffer.from again otherwhise if i just use like

    let imgBase64 = product.productImage.imageData.toString('base64');
    

    the imgBase64 would be "[Object ojbect]