I recently learned there seem to be multiple ways to display an image on a web page.
The first way is to directly assign the URL to an image element's URL
const img = new Image();
img.onload = () => {
document.querySelector("#myImage").src = url;
};
img.onerror = () => {};
img.src = imageUrl;
Another way I recently learned is using fetch
fetch(imageUrl)
.then((response)=>response.blob())
.then((blob)=>{
const objectUrl = URL.createObjectURL(blob)
document.querySelector("#myImage").src = objectUrl;
})
I have a few questions about both approaches:
I am familiar with fetch
but I normally use it to fetch JSON. The second way of using fetch
to get the image seems to me like we are fetching raw binary data of that image file over HTTP, while the first one we are delegating the browser to kick off a Get
request to fetch that image. But from the server's perspective, there are no differences in terms of how it sends the image down? Am I understanding this right?
In what situations we should favor one approach over the other? I feel like the second approach is going to have a lot of CORS problems than the first one, but not sure exactly why.
are there any other ways to display an image on a web page? I heard of base64 encoding/decoding a lot when people talk about images. Is base64 related to response.blob()
i.e. the second approach? Or it is different? if so, can someone please give me an example of using base64 to show an image?
lastly, I think displaying images has been a hole in my knowledge of frontend or web development. Please feel free to recommend any good resources on this subject.
var image = document. getElementbyId("imageid"); var url = document. getElementbyId("urlid"); image. src = url.
createElement('a'); // setting the src attribute to the (hopefully) valid URI from above img. src = src; // setting the href attribute to the (hopefully) valid URI from above a. href = href; // appending the 'img' to the 'a' a. appendChild(img); // inserting the 'a' element *after* the 'form' element parent.
To check if a url is an image, call the test() method on a regular expression that matches an image extension at the end of a string, e.g. . png or . jpg . The test() method will check if the url ends with an image extension and will return true if it does.
Sometimes, we want to verify that an URL is an image URL with JavaScript. In this article, we’ll look at how to verify that an URL is an image URL with JavaScript. To verify that an URL is an image URL with JavaScript, we can create our own function and that checks the URL we want to verify against our own regex.
To show the images on the web page, I am creating an <img> object and assigning the image url as the source to the <img> object. var img = document.createElement ('img'); // Create an <img> element. img.src = arrItems [i].Image; // The image source from JSON array.
In the above example, I am using a <div> element to show the data with the images using image URLs extracted from the JSON file. You can use a <table> instead of <div> to show the data. I have explained in detail about the XMLHttpRequest object here.
Then create respectively a variable from the image element and retrieve its value, this value can be either the <img> element or an instance of the Image class of JavaScript (you will need to set the src attribute manually with JavaScript). Then use the diff method of imagediff that expects as arguments the images to differentiate.
Here, you can see an image generated from base64 string characters, without any link
<img style="width:64px; height:64px;" src="data:image/png;base64,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"></img>
This is also helpful to embed image directly in code as text, pass it in as a url parameter or you can even put image in JSON file. In some cases, it also performs better than binary image with compression like gzip too.
fetch
is hardly subjected to CORS because it does not send cross-origin cookies (see MDN - using fetch). If you need more control you can use XMLHTTPRequest. The usage of blob is inherited from old web approaches, those times where ArrayBuffer
were not invented, and it was the only wrapper for binary data in the web environments. It is still supported for many reason.I think you have a bias toward the concept of a browser displaying an image.
So what a image really is? binary data.
Pratically there is only one way for your browser (or your computer in general) to display an image, that is to have a byte array that is a flatten view of the pixels of your image. So at the end of the day you will ALWAYS need to feed your broswer with binary data that is interpretable as a raw image (usually a set of rgb(a) pixels).
Yes, there is only "ONE" way to display an image on a computer. But there are different ways we can represent that image.
At low level, different computers represent numbers in different ways, so the web standards decided to represent images in so called RGB8 or RGBA8 encoding (Red-Green-Blue(-Alpha)-NumBits, 8 bits = 1 Byte). This means that each pixel is represented by an array of 4 bytes (numbers), each varying from 0 to 255. This array is the only thing your browser see as image.
At the end your image is something like this:
// using color(x, y) to describe the image pixels
[ red(0, 0), green(0, 0), blue(0, 0), alpha(0, 0), red(1, 0), ... ] =
[ 124, 12, 123, 255, 122, ... ]
Now that you can see an image as a linear array of pixels, we can decide how to write it down on a piece of paper (our "code"). The browser (usually and historically) parse every packet sent on the web in an HTML file as plain text, so we must use characters to describe our image, the standard is to ONLY use UTF-8 (character encoding, superset of ASCII). We can write it in JS as an array of numbers for example.
But take a look to the number 255. Each time you send that number on the newtork you are sending 3 characters: '2', '5', '5'. Web comunicates only with characters so... Is there a way to make a compact representation of that number in order to send less bytes as possible (saving those guys who have slow connection!)?
Base64 is the most famous encoding used to describe that linear array in the most compact way, because it compress the 255 characters into just 1 or 2 characters (depending on the sequence). Instead of representing number in base of 10, we can take rid of some characters we usually use as letters to represent more digits. So '11' become 'a', '12' => 'b', '13' => 'c', ..., '32' => 'a', ..., '63' => 'Z', '64' => '10', '65' => '11', ..., '128' => '20'
, and so on. Furthermore this algorithm exploit more low level representation to encode more digits in one single character (that's why u will see some '=' at the end sometimes).
Take a look on different representation of the same image:
// JavaScript Array
[ /* pixel 1 */ 124, 12, 123, 255, /* pixel 2 */ 122, 12, 56, 255 ] // 67 characters
// (30 without spaces and comments)
// Base64
fAx7w796DDjDvw== // 16 characters
// Base32
3sc3r7v3qc1o7vAb== // 18 characters (always >= Base64)
It's easy to see why they choose base64 as common algorithm (and this example counts just for 2 pixels).
(Base32 image example)
Now imagine to send a 4K image on the web, which has a dimension of 3'656 × 2'664. This means that you are sending on the internet 9'739'584 of pixels, with 4 bytes each, for a grand total of 38'958'336 bytes (~39MB). Furthermore imagine what a waste if the image is completely black (we can describe the whole image just with one pixel)... That's too much (especially for low connections), for this reason they invented some algorithms which can describe the image in a more compact way, we call them image format. PNG and JPEG/JPG are example of formats which compress the image (jpg 4k image ~8MB, png 4k image can vary from ~2MB to ~22MB depending on certain parameters and the image itself).
Someone keep the compression thing to a further level, enstabilishing the gzip
compression standard format (a generic compression algorithm over an already compressed image, or any other kind of file).
At the end of this journey you have just two different ways browsers allow you to draw content: URI
and ArrayBuffer
.
URI
: you can use it with <img>
and css, by setting src
property of the element or by setting any style property which can get an image URL
as input.ArrayBuffer
: by manipulating the <canvas>.context
buffer (that is just the linear array we discussed above)Obviously browsers allow also to convert or switch between the two ways.
URI
are the way we define a certain content, that can be a stored resource (URL
- all protocols but data
, for example http(s)://
, ws(s)://
or file://
) or a properly buffer described by a string (the data
protocol).
When you ask for an image, by setting the src
property, your browser parses the URL and, if it is a remote content, makes a request to retrieve it and parse the content in the proper way (format & encoding). In the same way, when you make a fetch
call you are asking the browser to request the remote content; the fetch
function has the possibility to get the response in different ways:
ArrayBuffer
, which is a representation of the linear array of the image, we discussed aboveBlob
, which is an abstract representation of a generic file-like object (which also encapsulate an internal ArrayBuffer
). The Blob
is something like a pointer to a file-like entity in the browser cache, so you don't need to download/request the same file multiple times.// ArrayBuffer from fetch:
fetch(myRequest).then(function(response) {
return response.arrayBuffer();
})
// Blob from fetch
fetch(myRequest).then(function(response) {
return response.blob();
})
// ArrayBuffer from Blob
blob.arrayBuffer();
So now you have to tell to the browser how to make sense of the content you get back from the response. You need to convert the data to a parsable url:
var encodedURI = `data:${format};${encoding},` + encodeBuffer(new Uint8Array(arrayBuffer));
image.src = encodedURI
// for base64 encoding
var encodeBuffer = function(buffer) { return window.btoa(String.fromCharCode.apply(null, buffer)); }
// for blobs
image.src = (window.URL || window.webkitURL).createObjectURL(blob);
Note that browsers supports other encodings than just base64, also base32 is available but, as we saw above, is not so convinient to use. Also there is no builtin function like btoa
to encode a buffer in base32.
Note also that the format value can be any kind of MIME type such as image/png|jpg|gif|svg
or text/plain|html|xml
, application/octet
, etc.. Obviously only image types are then shown as images.
When the resource is not requested from a remote server (with a file://
or data
protocol) the image is usually loaded syncronously, so as soon you set the URL, the browser will read, decode and put the buffer to display in your image. This has two consequences:
data
protocol for videos or huge data in the special section, at the end)URI
is a generic identifier for a resource, URL
is an identifier for a location where to retrieve the resource. Usually in a browser context are almost an overlapped concept, I found this image explain better than thousand words:
The data
is pratically an URI
, every request with a protocol is actually an URL
In your question you write this as an alternative method by "setting the image element url":
fetch(imageUrl)
.then((response)=>response.blob())
.then((blob)=>{
const objectUrl = URL.createObjectURL(blob)
document.querySelector("#myImage").src = objectUrl; // <-- setting url!
})
But watch out: you actually setting an image element source URL!
The <canvas>
element gives you the full control over an image buffer, also to further process it. You can literally draw your array in it:
var canvas = document.getElementById('mycanvas');
// or offline canvas:
var canvas = document.createElement('canvas');
canvas.width = myWidth;
canvas.height = myHeight;
var context = canvas.getContext('2d');
// exemple from array buffer
var arrayBuffer = /* from fetch or Blob.arrayBuffer() or also with new ArrayBuffer(size) */
var buffer = new Uint8ClampedArray(arrayBuffer);
var imageData = new ImageData(buffer, width, height);
context.putImageData(iData, 0, 0);
// example image from array (2 pixels)
var data = [
// R G B A
255, 255, 255, 255, // white pixel
255, 0, 0, 255 // red pixel
];
var buffer = new Uint8ClampedArray(data);
var imageData = new ImageData(buffer, 2, 1);
context.putImageData(iData, 0, 0);
(Note ImageData wants a RGBA array)
To get back the ArrayBuffer
(which you can also plug back in the image.src
after) you can do:
var imageData = context.getImageData(0, 0, canvas.width, canvas.heigth);
var buffer = imageData.data; // Uint8ClampedArray
var arrayBuffer = buffer.buffer; // ArrayBuffer
This is an example on how to process an image:
// reading image
var image = document.getElementById('myimage');
image.onload = function() {
// load image in canvas
context.drawImage(image, 0, 0);
// process your image
context.fillRect(20, 20, 150, 100);
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
imageData.data[0] = 255;
// converting back to base64 url
var resultUrl = window.btoa(String.fromCharCode.apply(null, imageData.data.buffer));
// setting image url and disabling onload
image.onload = null;
image.src = resultUrl;
};
// note src setted after onload
image.src = 'ANY-URL';
For this part I suggest you to take a look to Canvas Tutorial - MDN
Audio and Video are treated in the same way, but you must encode and format also the time and sound dimension in some way. You can load a audio/video from base64 string (not so good idea for videos) or display a video on a canvas
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