最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to render blob image in vue.js stored in database - Stack Overflow

programmeradmin0浏览0评论

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.

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?

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.

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?

Share Improve this question edited May 3, 2018 at 20:01 paceaux asked May 3, 2018 at 14:48 paceauxpaceaux 1,8901 gold badge18 silver badges25 bronze badges 1
  • 1 I was having basically this exact same issue, in the middle of posting another question when I found this one, I got past it by uploading the base64 string as a dataType.TEXT. This does not feel like the right solution but for the small project I'm building not a big deal. Here is a repo with a small working example: postgres pic. master has datatype blob attempted, text-solution has the text solution. – ContextCue Commented Jul 27, 2018 at 22:23
Add a ment  | 

1 Answer 1

Reset to default 2

First, be sure you're getting a valid base64 string: https://codebeautify/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

}
发布评论

评论列表(0)

  1. 暂无评论