Reputation: 3814
TL;DR
I'm trying to fetch
and image, convert it to base64, and put the data url into an img
's src
attribute, but it's not working:
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const base64 = window.btoa(blob);
const content = `data:image/jpeg;base64,${base64}`;
tag.setAttribute("src", content);
}
The details, as well as some other methods, which do work follow.
I have been experimenting with different ways to lazy load:
$ mkdir lazy
$ cd lazy
$ wget https://upload.wikimedia.org/wikipedia/commons/7/7a/Lone_Ranger_and_Silver_1956.jpg # any other example image
now create a file called index.html
with this in it:
<script>
// this works
function setAttribute(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
tag.setAttribute("src", path);
}
// this doesn't work for some reason
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const base64 = window.btoa(blob);
const content = `data:image/jpeg;base64,${base64}`;
tag.setAttribute("src", content);
}
// this works too
async function works(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
const content = URL.createObjectURL(blob);
tag.setAttribute("src", content);
}
</script>
<a href="javascript: setAttribute('example');">set attribute</a><br />
<a href="javascript: ajax('example');">data url</a><br />
<a href="javascript: works('example');">object url</a><br />
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg"></img><br />
and start a server in that folder:
$ python -m SimpleHTTPServer # or whichever local webserver
and then when I look at it in chrome I get this:
The first and third links both work:
However, the middle link does not:
Here is what the three links do to the tag respectively:
works:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="Lone_Ranger_and_Silver_1956.jpg">
does not work:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="data:image/jpeg;base64,W29iamVjdCBCbG9iXQ==">
works:
<img id="example" data-src="Lone_Ranger_and_Silver_1956.jpg" src="blob:http://localhost:8000/736a9e18-c30d-4e39-ac2e-b5246105c178">
That data url in the non working example also looks too short. So what am I doing wrong?
Upvotes: 1
Views: 5338
Reputation: 3814
Thanks for the suggestion @dolpsdw. window.btoa
doesn't do what I thought it would. If anybody is trying to do the same thing, instructions for reading a blob into a data url are here: https://stackoverflow.com/a/18650249/5203563
I have created this wrapper that fits right into my program as follows:
(it even adds in the data:image/jpeg;base64,
part for you and works out the mime type from the blob)
function readBlob(b) {
return new Promise(function(resolve, reject) {
const reader = new FileReader();
reader.onloadend = function() {
resolve(reader.result);
};
// TODO: hook up reject to reader.onerror somehow and try it
reader.readAsDataURL(b);
});
}
async function ajax(id) {
const tag = document.getElementById(id);
const path = tag.getAttribute("data-src");
const response = await fetch(path);
const blob = await response.blob();
// const base64 = window.btoa(blob);
// const content = `data:image/jpeg;base64,${base64}`;
const content = await readBlob(blob);
tag.setAttribute("src", content);
}
this gives me the much longer data url that I expected:
Upvotes: 5
Reputation: 78
When you have the inmemory blob Just generate a url for that blob
var url = urlCreator.createObjectURL(blob)
Then create a new IMG with JavaScript and invoke decode method
const img = new Image();
img.src = url;
img.decode()
.then(() => {
document.body.appendChild(img);
})
.catch((encodingError) => {
// Do something with the error.
})
Maybe you want also to revoke URL after load with
URL.revokeObjectURL(objectURL)
About why the window.btoa does not work, its because is for string to base64 only.
Read about blob to base64 conversión here. But is a more elegant solution createObjectURL.
Upvotes: 2