Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to render blob image in vue.js stored in database

I am using Vue.js in the front-end. I have Node.js, Express, PostgreSQL (with Sequelize ) on the backend.

I am storing an item in the database that includes a thumbnail image.

Database Model

const Item = sequelize.define('item', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    name: {
        type: Sequelize.TEXT,
        allowNull: false,
    },

    image: {
        type: Sequelize.BLOB('long'),
        allowNull: true,
    },

Database-wise, the image is being stored as a Blob and I think this is fine (and yes, I am aware that it's not best-practice to put images in a database).

I observe in the browser that the object that I am accessing in my Vue template with this.item.image is an Object of the type Buffer.

Console shows this is an Object with type Buffer

Adding to Database

I add the item to the database in the browser with this in my vue template:

     <label for="image" class="itemCreate__field itemCreate__field--image">
       <span class="itemCreate__fieldLabel">Image</span>
       <input id="file"  type="file" accept="image/*" @change="onFileChange"/>
        <img v-if="itemPreviewImage" :src="itemPreviewImage" />
     </label>

And that HTML relies on these methods:

     onFileChange(evt) {
        const files = evt.target.files || evt.dataTransfer.files;
        if (!files.length) return;
        this.createImage(files[0]);

    },
    createImage(file) {
        const image = new Image();
        const reader = new FileReader();

        reader.onload = evt => {
            this.itemPreviewImage = evt.target.result;
            this.item.image = evt.target.result;
        }

        reader.readAsDataURL(file);
    },

I have this in the vue template that renders the image:

        <div v-if="item.image">
            <img :src="imgUrl" alt="Picture of item"/>
        </div>

Rendering from Database

I have tried the following approaches, which do not work:

createObjectUrl borrowed from here:

    imgUrl(){
      const objUrl = window.URL.createObjectURL(new Blob(this.item.image.data));

      return objUrl;
    }

Creating a base64 string borrowed from here:

    imgUrl(){
        const intArray = new Uint8Array(this.item.image.data);
        const reducedArray = intArray.reduce((data, byte) => data + String.fromCharCode(byte), '');

        const base64String = `data:image/png;base64, ${btoa(reducedArray)}`;


        return base64String;
    }

Creating a new Uint8Array and then getting an objectUrl (borrowed here):

imgUrl(){
  const arrayBuffer = new Uint8Array(this.item.image);
  const blob  = new Blob([arrayBuffer], {type: "image/png"});

  return window.URL.createObjectURL(blob);

}

In all cases (including some attempts with FileReader), I get broken images. I don't get errors in the console, though.

I think the issue is that I am not submitting correct data to the database.

I am sending an Ajax request that has the File attached as a property, and I should probably convert it to ¿something else?

like image 469
paceaux Avatar asked May 03 '18 14:05

paceaux


People also ask

How do I display blob images in Vue?

BlobImage.vue * Loads the image as a blob and createObjectURL(). * Set the img tag's src to the object url. * Once the image is loaded, revoke the object url (avoid memory leak). * Notice that the page can still show the image, but the src blob is no longer valid.

How can I use img src in VUE JS?

To display an image with the img tag in vue, you can use v-bind:src directive, or :src . Or :src for short. Remember that :src expects a JavaScript expression, so if you want to use a string literal in :src you need to wrap the string in quotes.

Which database is best for Vue?

Firebase With Google's backing, Firebase is also a reliable Vue JS backend that coders can use. Developers can employ Firebase products like databases, cloud functions, hosting, and storage to build their Vue JS applications backends.


1 Answers

First, be sure you're getting a valid base64 string: https://codebeautify.org/base64-to-image-converter

Then try defining a getter to the Item model

const Item = sequelize.define('item', {
    ...
    image: {
        type: Sequelize.BLOB('long'),
        allowNull: true,
        get () { // define a getter
            const data = this.getDataValue('image')
            return data ? data.toString('base64') : ''
        },
        set(val) {
          this.setDataValue('image', val);
        }
    },
    ...
}

Computed property

imgURL () {
    return this.item.image
        ? 'data:image/png;charset=utf-8;base64,' + this.item.image 
        : '' // some default image

}
like image 56
Frondor Avatar answered Oct 25 '22 14:10

Frondor