【问题标题】:How to render blob image in vue.js stored in database如何在存储在数据库中的 vue.js 中呈现 blob 图像
【发布时间】:2020-07-22 16:18:15
【问题描述】:

我在前端使用 Vue.js。我在后端有 Node.js、Express、PostgreSQL(带有 Sequelize )。

我在数据库中存储了一个包含缩略图的项目。

数据库模型

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,
    },

在数据库方面,图像被存储为 Blob,我认为这很好(是的,我知道将图像放入数据库不是最佳实践)。

我在浏览器中观察到,我在 Vue 模板中使用this.item.image 访问的对象是Buffer 类型的对象。

添加到数据库

我在我的 vue 模板中将项目添加到浏览器中的数据库中:

     <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>

而 HTML 依赖于这些方法:

     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);
    },

我在渲染图像的 vue 模板中有这个:

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

从数据库渲染

我尝试了以下方法,但都不起作用:

createObjectUrl借自here

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

      return objUrl;
    }

创建一个从here借来的base64字符串:

    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;
    }

创建一个新的Uint8Array,然后得到一个objectUrl(借用here):

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

  return window.URL.createObjectURL(blob);

}

在所有情况下(包括一些使用 FileReader 的尝试),我都会得到损坏的图像。不过,我没有在控制台中收到错误。

认为问题是我没有向数据库提交正确的数据。

我正在发送一个将文件作为属性附加的 Ajax 请求,我可能应该将它转换为 ¿ 其他东西?

【问题讨论】:

  • 我基本上遇到了同样的问题,在发布另一个问题的过程中,当我发现这个问题时,我通过将 base64 字符串上传为dataType.TEXT 解决了这个问题。这感觉不是正确的解决方案,但对于我正在构建的小项目来说没什么大不了的。这是一个带有一个小型工作示例的存储库:postgres picmaster 尝试使用数据类型 blob,text-solution 使用文本解决方案。

标签: javascript postgresql vue.js blob sequelize.js


【解决方案1】:

首先,确保你得到一个有效的base64 字符串:https://codebeautify.org/base64-to-image-converter

然后尝试为Item 模型定义一个getter

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);
        }
    },
    ...
}

计算属性

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

}

【讨论】:

  • 我尝试了那个确切的代码并最终得到&lt;img src="data:image/png;charset=utf-8;base64[object Object]" alt="Picture of item"&gt; 我想我需要在我的计算道具中以某种方式将该对象字符串化
  • 经过仔细审查,看起来 base64 显然无效。所以这意味着我将图像提交到数据库的方式存在问题
  • 您应该在保存之前将缓冲区传递给item.image。将代码添加到问题中,以便我们检查是否可以。另外,尝试将long长度设置为Sequelize.BLOB('long')
  • 我已更新问题以包括我如何添加文件。我还修改了我的模型。我如何确定我正在传递缓冲区?在我的“添加”模板中的createImage 方法中,即使我尝试this.item.template = file,它也不起作用...这是我的无知,因为我不确定文件何时成为缓冲区,反之亦然
  • 作为旁注,我尝试了这些事情:传递 ArrayBuffer,使用 FileReader 转换/传递 base64 字符串(w 和 wo substr)/仅从 new FileReader() 传递文件/从 fs-web 传递文件fileRead... 其中一些选项可以使用atob 解码,但解码后字符串无效。
猜你喜欢
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2017-08-19
  • 1970-01-01
  • 2013-01-16
  • 2021-11-16
  • 1970-01-01
相关资源
最近更新 更多