In my front-end development, I am utilizing Vue.js. On the backend, I have set up Node.js, Express, and PostgreSQL with Sequelize. One of the challenges I encountered involved 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,
},
The image is stored as a Blob in the database, which has raised some concerns regarding best practices.
When accessing the object containing the image in my Vue template using this.item.image
, I noticed it was returning an Object of type Buffer
.
https://i.sstatic.net/PRpaY.png
Adding to Database
To add the item to the database from the browser, I implemented the following code 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>
These HTML elements rely on the following 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);
},
Within the vue template responsible for rendering the image, I included the following:
<div v-if="item.image">
<img :src="imgUrl" alt="Picture of item"/>
</div>
Rendering from Database
I attempted several methods, none of which seemed to work correctly:
createObjectUrl
sourced from here:
imgUrl(){
const objUrl = window.URL.createObjectURL(new Blob(this.item.image.data));
return objUrl;
}
Creating a base64 string as suggested 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;
}
Another attempt involved creating a new Uint8Array
and obtaining an objectUrl (taken from here):
imgUrl(){
const arrayBuffer = new Uint8Array(this.item.image);
const blob = new Blob([arrayBuffer], {type: "image/png"});
return window.URL.createObjectURL(blob);
}
Despite these efforts, including experiments with FileReader, the images still appeared broken without any errors in the console.
My hypothesis is that the issue lies in how I am submitting the data to the database. Specifically, the File attached as a property in the Ajax request may require conversion to a different format.