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
1 Answer
Reset to default 2First, 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
}