How to render blob image in vue.js stored in database
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
}
paceaux
I'm a Principal Solutions Consultant for EXLRT. I build websites for companies on the Fortune 500 and 100 list. For fun, I study foreign languages. My degrees are in French and Spanish, and I'm currently learning Hebrew, Arabic, and Portuguese. But I've dabbled with Mandarin Chinese, Russian, and Arabic in the past. I'd like to work in and around translation or natural language processing.I built my own part-of-speech tagger for fun.
Updated on June 23, 2022Comments
-
paceaux almost 2 years
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 typeBuffer
.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?
-
paceaux about 6 yearsI tried that exact code and ended up with
<img src="data:image/png;charset=utf-8;base64[object Object]" alt="Picture of item">
I think I need to somehow stringify that object in my computed prop -
paceaux about 6 yearsUpon Closer review, it looks like the base64 apparently isn't valid. So that means there's a problem with how I'm submitting the image to the database
-
Frondor about 6 yearsYou should be passing a Buffer to
item.image
before saving it. Add the code to the question so we can check if that's ok. Also, try settinglong
length toSequelize.BLOB('long')
-
paceaux about 6 yearsI've updated the question to include how I'm adding the file. I also modified my model. How can I be sure that I'm passing a buffer? in my
createImage
method in my "add" template, it doesn't work even if I trythis.item.template = file
... This is my ignorance as I'm not sure I know when a file becomes a buffer and vice versa -
ContextCue almost 6 yearsAs a side note I tried these things: passed ArrayBuffer, converted with FileReader / passed base64 string (w and wo substr) / passed just the file from
new FileReader()
/ passed the file fromfs-web
fileRead... a few of these options could be decoded withatob
but the string was not valid after decoding.