How to render utf8 encoded blob in VueJS/Javascript - javascript

I am trying to convert a binary blob which is fetched from database into an image which I can render with an <img>-Tag.
In my Laravel backend I return the blob/data like this:
$user = User::find($id);
$user->photo = utf8_encode($user->photo); // $user->photo is saved as blob in MySQL database
return $user;
The reason why I use utf8_encode is that the data is returned as JSON.
In VueJS I did try the following to render the image:
<input type="file" #change="onFileSelect">
<img :src="setImage(userdata.photo)">
setImage(image) {
let objurl = window.URL.createObjectURL(new Blob([image]));
return objurl;
}
onFileSelect(e) {
this.userdata.photo = e.target.files[0];
}
If I select a file in input the image is rendered accordingly. But when I fetch my data from server it should load the saved image.
If I console.log(image) inside the setImage(image) method after the server request I get the following output:
PNG
IHDRu<ÔFiCCPICC ProfileHWXSÉ[RIh¤ÞD)Ò¥Ð"Hl$PBL"vdQÁµØÐUE×ÈZ±E±÷e],ØPyºú½÷¾w¾ïÜûçÌÿ̽w­®Dj+ÎÆ3Ç¥¤2I0t.O&aÅÆF(÷Ê»ëQܯ8+¸~ÿ¯¢ÃÈx ±§óe¼\÷ð$Ò|ÞÐn55_¢À ÖÂ!(p¦
(pº
W*}âØïLãr¥h6C;³ y4oBì"æÄh!à ¹|# §ÀÐاÇùÎôAN.7s«jQ
9D$äp§ýíøß#a&FÄ)j}»©À4»ÅéÑ1ëBüAÄWúCRòD?j±aÏÄ.|nH$Ä&s¢£ÔöôQb¸BÐBQ>'A=w#¯æ¬æÅÅà)¥ÛÀãüOȳYjþBgÿm0!Y3F-%EC¬ ±,;>RåY ÙÑ>Ry"k}âð?6)C§öæÊêÅEh5®Ê&D¨yvð¸Êü
!nY<Ù¸¨ZøPUíØ%8Q]/Ö!ÉSÏ}-ÉUûãTAN¸Ân ±¬ ^=ÈRÅGKòcTyâéYÜѱª|ðBØ 0j:ÈY#ÔÖÝÔ
©FÂHA&gµeF²rD¯ñ üÈç+G Ú¿ZUWg¡-PÎÈO Î þ+g£%ÇÐ"ú):æU1ö³-Qj|©5àI%#aDÜÀýð(x
ê{ã>Ù~ó'bG°fìvHWÑcå*§Ì'ò~ÇUÇTtRæRïÒåòY5/(T¼;O2M*Êæ3YðÍ/rļáÃn.®ð­­ø¨^S=ßÄHçm|nGi÷÷÷øf#ãP¨ÝßlöЯpf>O.-PÙpÅ¿PZð2fÀ
If I pass that stuff to my setImage() method I do not get any error. The blob URL is created but the <img> Tag just shows an "empty" image.
And so on. Is there a way how I can convert this utf8_encoded blob into something useful?

I cannot comment, so had to post as an answer. I will remove if needed.
You could use a library to handle blob parsing on the front-end.
https://www.npmjs.com/package/blob-util
That library has built in ES module support, so should work out-of-the-box with Vue.

Related

How do I encode (base64) a PDF file's blob using javascript and decode in PHP to save in SQL?

I have been trying for days now to build a file uploader using AJAX and PHP. I was able to upload images without any issue. But whenever it comes to PDF, I end up with blank pages.
Here is what I tried using FileReader:
for(const [key, file] of Object.entries($('input').prop('files'))){
const reader = new FileReader()
reader.onload = function(event){
var object = {
name:file.name,
size:file.size,
type:file.type,
content:reader.result,
}
API.post("file/upload/?csrf="+CSRF,object,{
success:function(result,status,xhr){
console.log(result)
}
})
}
reader.readAsDataURL(file)
}
And in PHP:
// $_POST['content'] = base64_decode(str_replace('data:' . $_POST['type'] . ';base64,', '', $_POST['content']));
// $_POST['content'] = base64_decode($_POST['content']);
$_POST['content'] = base64_decode(urldecode($_POST['content']));
The results I got:
Uploading an images: Ok!
Uploading a single page PDF: PDF File only contains a blank page.
The results are the same using the 3 methods (readAsDataURL,readAsBinaryString,readAsText).
Using readAsText I keep getting: Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range.
Validated once saved in SQL using phpMyAdmin 5.
Expected results should be that any file type should be saved correctly.
NOTE: The API class is just a small class that includes parameters for $.post so I don't have to type them all the time.
First problem was that I was storing binary data in SQL which isn't meant for this type of use. This caused the SQL Database to corrupt the binary data.
Therefore, I redesign my file storage using locally stored Binary files (.bin) and SQL to provide all meta data of the files including the Path and more advanced ACL.
To secure the data, I use a rewrite rule RewriteRule ^data/.*$ - [F,L]. This prevents user from directly accessing the binary data. Therefore securing the file.
Once the changes made, I was able to save files through the application's API using the readAsDataURL method to retrieve the encoded binary data and send it over to the PHP API.

How to view blob data directly using html

How do you view a blob data that is from a sql database file (.db .db3 and others) and view it on web browser by only using a single html file? The blob data are probably meant to be seen as an image file (jpg, png and others)
Let's say I have a blob data like this:
du�� C�BVwv�q8q7k�1�H�asfdasdfasdf�#s;47sk"as��'7hib-�3$asdffdsfa�a�����U�����P������
And I want to put that single blob data directly (without calling the database file, just using the value of the blob itself) inside a html file so I can directly open it from my browser without installing other software or setting up a local server inside my computer.
I'm sorry if I explain this weirdly, I rarely code, I honestly don't know anything about sql or that server thingamajig, I just want to view the blob file.
You could use Blob. Here I construct a blob and then turn it back into a string that I insert in the document.body.
var array = ['<p>Hello World!</p>'];
var blob = new Blob(array, {type : 'text/html'});
const reader = new FileReader();
reader.addEventListener('loadend', e => {
document.body.innerHTML += e.target.result;
});
reader.readAsText(blob);
And I guess that the Filereader can also read a file if needed.

Showing binary PDF in browser Javascript

I have a MSSQL Server Database with files stored as a column Content of type VARBINARY(MAX) in a SQL table.
I developed a backend Node.js server with Express.js to access the database. In this backend I have a route called /api/file/:id_file which takes the content of the file with id_file
async getFile(req,res){
const {id_file} = req.query
const file= await db.Files.findOne({
where:{
'Id': id_file,
}
})
res.contentType('application/pdf')
res.send(file.Content)
}
Then in frontend using Javascript, I have an iframe
<iframe id="view" src="" style='height: 500px; width: 1000px;' />
And I use an ajax request to get the file. When I have the response, I just convert it to blob and set the src attribute of iframe element with the base64 encoding of the blob
const reader = new FileReader();
reader.onload = () => {
const b64 = reader.result.replace(/^data:.+;base64,/, "");
$('#view').attr('src','data:application/pdf;base64,'+ b64);
};
reader.readAsDataURL(new Blob([resp.data], { type: "application/pdf" }));
When I try to request a file and show, I see a blank PDF, nothing is shown.
Am I missing any step to convert the content of the file to base64?
You don't need a filereader since you're not reading a file from the filesystem or user input; you already have the file pulled down from the API. If your binary pdf data is in resp.data then you just need to use btoa
creates a Base64-encoded ASCII string from a binary string
$('#view').attr('src','data:application/pdf;base64,'+ btoa(resp.data));

PouchDB returning wrong image attachment type

I'm trying to get PouchDB to return a small image attachment. When I upload the image through Fauxton, my app successfully returns a Blob with type: 'image/svg+xml' that renders correctly in my <img> element (using URL.createObjectURL).
However, if I have the user upload an image, and then put the file Blob to my remote Pouch database, I have problems. In this case, PouchDB.getAttachment() now returns a Blob with type: 'application/octet-stream' instead of 'image/svg+xml', despite having uploaded it with the correct content_type. This image does not render, giving me a generic browser img placeholder.
Why could this be occurring?
Step 1 Here is how I retrieve the image from the user:
var image = new Blob([fs.readFileSync(fileLocation, 'utf-8')], {
type: 'image/svg+xml'
})
Step 2 Here is how I put my document (and attachment) to PouchDB:
var doc = await PouchDB.get(docID, {attachments: true})
doc._attachments = {
'logo.svg': {
content_type: 'image/svg+xml',
data: image
}
}
await PouchDB.put(doc)
You got 2 problems with reading your file. First is that you can't treat binary data as UTF8 (may not be a real problem with SVG file, but with other images surely is), and the second one is that you have to base64 encode it.
There are many different approaches to base64 encode a blob, but the easiest solution would be to change the method of putting it from put to putAttachment. Something like this:
HTML:
...
<input type="file" id="inputFile">
...
JS:
...
var inputFile = document.querySelector('#inputFile');
var file = inputFile.files[0];
db.putAttachment('mydoc', 'myfile', file, file.type).then(...)
...

Convert image from readAsDataURL to readAsBinaryString

Using the filereader API it is possible to show a preview of the file, by reading the file with readAsDataURL
What I am trying to do is:
The user selects a file
A preview is shown, so that the user has some feedback.
If the user is satisfied, he submits the data to the backend.
Implementing step 3 can be done by re-reading the file with readAsBinaryString, but this looks problematic because the data could have disappeared or changed on disk. So What I would like is to convert the data returned from readAsDataURL to the format returned by readAsBinaryString. How can I do this?
Another alternative would be to submit the data to the backend as returned by readAsDataURL, but I would like to avoid that, since that would require special handling on the backend in my case.
Like CBroe said, you dont need to read the file twice.
JS :
handleFileSelectThumbFile(evt){
var files = evt.target.files;
var file = files[0];
// You can get the mime type like this.
var thumbMIME = files[0]['name'].split('.').pop();
if (files && file) {
var reader = new FileReader();
reader.onload = function(readerEvt) {
// Split the readerEvt.target.result by a ','.
// You can send the binaryString variable to the server.
// Its base64 encoded already.
var binaryString = readerEvt.target.result.split(',')[1];
// Set the image preview to the uploaded image.
$('.img-preview').prop('src', readerEvt.target.result);
}.bind(this);
reader.readAsDataURL(file);
}
}
HTML :
<input type="file" onChange={this.handleFileSelectThumbFile} required/>
<img src='http://placehold.it/300' class='img-preview'/>
You can read the MIME type from the first part of readerEvt as well. Look at CBroe's comment above.

Categories