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?
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.
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.
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.
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);
}
},
...
}
imgURL () {
return this.item.image
? 'data:image/png;charset=utf-8;base64,' + this.item.image
: '' // some default image
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With