avatarCharmaine Chui

Summary

The webpage provides a comprehensive guide on displaying images in a web browser using client-side JavaScript, detailing three methods: HTML image tags, CSS background images, and the canvas element.

Abstract

The article titled "3 Ways To Display An Image onto Browser With Client-Side JavaScript" offers insights into enhancing productivity by utilizing portable, dependency-free tools in web development, particularly in the wake of WebAssembly advancements. It addresses the challenge of CORS restrictions by demonstrating how to use an HTML file input to upload images, which are then processed by JavaScript. The guide outlines three distinct techniques for rendering Base64-encoded images: embedding them in an <img> tag, setting them as a CSS background-image, and drawing them onto a <canvas> element. Each method is accompanied by code examples and discussions on their use cases, such as layout-specific requirements or complex scenarios involving frequent image updates. The author emphasizes the importance of understanding aspect ratios and pixel density for accurate image rendering and provides additional resources and related articles for further exploration.

Opinions

  • The author values productivity hacks, especially those that involve maximizing the portability and user-friendliness of digital tools.
  • The author suggests that the emergence of WebAssembly provides a significant incentive to build client-side web applications for daily work tasks.
  • The author believes that developers should set up a local server for local testing to avoid cross-origin resource sharing issues.
  • The author posits that a CSS-centric approach to image display is more appropriate when layout and positioning are a priority.
  • The author recommends using the canvas element for scenarios where frequent updates to image data are required, due to its efficiency and reusability.
  • The author provides a rule of thumb for preserving image aspect ratios and resolution when rendering images on a canvas, emphasizing the differentiation between actual and displayed dimensions.
  • The author encourages engagement with their work by inviting readers to follow them on Medium, star or fork their GitHub repository, and support them through a 'buy me a taco' donation link.

3 Ways To Display An Image onto Browser With Client-Side JavaScript

Lightweight. No plugins or dependencies. Full source code provided.

❝In face of workplace constraints, any individual who values his/her work productivity would naturally create means of overcoming respective hurdles.❞

That is without a doubt the greatest takeaway from my past 5 years of work. When it comes to productivity boosters, a highly effective hackaround I have acquired in the field of technology is to maximise portability of digital tools — i.e. Enabling said resources to be dependency-free and user-friendly. Following the emergence of WebAssembly (WASM), there is now greater incentive than ever to build client-side web applications to fulfil day-to-day work tasks.

Despite the fact that most web browsers have security protocols inplace such as the Cross-Origin Resource Sharing (CORS) Policy —

❝Developers who need to perform local testing should now set up a local server. As all files are served from the same scheme and domain (localhost) they all have the same origin, and do not trigger cross-origin errors.❞

— Source: CORSRequestNotHttp

(In short, unless the the web app is hosted on a server, all attempts to fetch or load any external resource by the browser including plaintext or image files would fail.)

— it is however still possible for a client-side web app to receive external data via alternative means such as a HTML form input:

<input id='uploadImg' type='file' />
Screencapture by Author | Case & point the above web app was built in pure client-side JavaScript. | Since the HTML component <input type=’file’ /> provides users the means to upload external resources, this in turn enables inputs to be processed.

As such, any file upload event can then be captured via client-side JavaScript to receive required image content:

var uploadImg=document.getElementById('uploadImg'); // file input
function readFileAsDataURL(file) {
  return new Promise((resolve,reject) => {
     let fileredr = new FileReader();
     fileredr.onload = () => resolve(fileredr.result);
     fileredr.onerror = () => reject(fileredr);
     fileredr.readAsDataURL(file);
  });
}
uploadImg.addEventListener('change', async(evt) => {
  let file = evt.target.files[0];
  if(!file) return;
  let b64str = await readFileAsDataURL(file);
/* TO DO CODE IMPLEMENTATION */
}, false);
  • In the above implementation, FileReader invokes readAsDataURL() and extracts any uploaded image as a Base64-Encoded string (assigned to the variable b64Str)

3 Ways to Render Base64-encoded Image Data —

  1. Image Tag
  2. Assign CSS Property — background-image: url(…)
  3. Canvas Element

Implementation Details

1. Image Tag <img />

By default, files with MIME type image/* tend to be embedded as <img /> HTML tags on web browsers as a means to convey visual information to its audience. The following JavaScript code snippet dynamically generates a HTML image component:

uploadImg.addEventListener('change', async(evt) => {
  let file = evt.target.files[0];
  if(!file) return;
  let b64str = await readFileAsDataURL(file);
/* TO DO CODE IMPLEMENTATION */
  let _IMG=await loadImage(b64str);
  let imgH=_IMG.naturalHeight;
  let imgW=_IMG.naturalWidth;
_IMG['style']['height']=`${imgH}px`;
  _IMG['style']['width']=`${imgW}px`;
  _IMG['style']['border'] ='1px solid #d3d3d3';
  document.body.appendChild(_IMG);
}, false);
/* Additional Utility Function */
const loadImage = (url) => new Promise((resolve, reject) => {
  const img = new Image();
  img.addEventListener('load', () => resolve(img));
  img.addEventListener('error', (err) => reject(err));
  img.src = url;
});

⚠ Important!

Image elements such as new Image() or document.createElement('img') requires the use of a Promise due to its asynchronous nature (hence the utility function loadImage()).

Illustration by Author | (1) <input id=’uploadImg’ type=’file’ /> is triggered when [Upload Image] is selected | (2) User then selects an image of choice (e.g. serotonin.png) | Image data is then embedded in a HTML Tag and displayed as shown above.

— In the event however when an image display prioritises layout and positioning (E.g. The Site Logo), a CSS-centric approach would be more appropriate instead.

2. Assign CSS Property — background-image: url(…)

Due to simplicity of use-case, only a few lines of code are required:

var cssDIVCard=document.getElementById('cssDIVCard');
uploadImg.addEventListener('change', async(evt) => {
  let file = evt.target.files[0];
  if(!file) return;
  let b64str = await readFileAsDataURL(file);
/* TO DO CODE IMPLEMENTATION */
  let _IMG=await loadImage(b64str);
  let imgH=_IMG.naturalHeight;
  let imgW=_IMG.naturalWidth;
cssDIVCard['style']['height'] = `${imgH}px`;
  cssDIVCard['style']['width'] = `${imgW}px`;
  cssDIVCard['style']['border'] ='1px solid #d3d3d3';
  cssDIVCard['style']['background-image']='url('+b64str+')';
  cssDIVCard['style']['background-position']='center';
  cssDIVCard['style']['background-repeat']='no-repeat';
  cssDIVCard['style']['background-size']='contain';
}, false);
  • Whereas on the frontend, an existing <div id='cssDIV'></div> component should be part of the page’s HTML markup.
Illustration by Author | (1) <input id=’uploadImg’ type=’file’ /> is triggered when [Upload Image] is selected | (2) User then selects an image of choice (e.g. serotonin.png) | CSS property value — [ background-image] of <div id=’cssDIV’><div/> is set to — [url:(<base64 string>)] and results in the above displayed.

On the other hand, to address complex use-cases such as Video-to-GIF File conversions:

It would be wise to embed an image onto a <canvas></canvas> element instead.

3. Canvas Element <canvas></canvas>

The unique advantage of rendering image data onto a <canvas></canvas> component is its low cost of reusability. Hence, a CANVAS is usually implemented when frequent updates to an Image’s data is required. Some instances include Scenario (1) — video animations and Scenario (2) — real-time image updates such as social media notifications. In both scenarios, as a consistent and continuous stream of image data is being processed, the ease of rendering each freeze frame onto the same CANVAS element is hence more efficient as compared to initialising a new HTML image element each time an update occurs.

var _ZOOM_FACTOR=1.0;
window.devicePixelRatio=3;
var scale = window.devicePixelRatio;
var canvasCard=document.getElementById('canvasCard');
uploadImg.addEventListener('change', async(evt) => {
  let file = evt.target.files[0];
  if(!file) return;
  let b64str = await readFileAsDataURL(file);
/* TO DO CODE IMPLEMENTATION */
  let _IMG=await loadImage(b64str);
  let imgH=_IMG.naturalHeight;
  let imgW=_IMG.naturalWidth;
let _CANVAS=document.createElement('canvas');
  _CANVAS['style']['border'] ='1px solid #d3d3d3';
  _CANVAS.id='imgCanvas';
  scaleCanvas(_CANVAS,_IMG,_ZOOM_FACTOR,imgH,imgW,scale);
  canvasCard.appendChild(_CANVAS);
}, false);
function scaleCanvas(_CANVAS,_IMG,_ZOOM_FACTOR,imgH,imgW,scale) {
  _CANVAS['style']['height'] = `${imgH}px`;
  _CANVAS['style']['width'] = `${imgW}px`;
  let cWidth=_ZOOM_FACTOR*imgW*scale;
  let cHeight=_ZOOM_FACTOR*imgH*scale;
  _CANVAS.width=cWidth;
  _CANVAS.height=cHeight;
  _CANVAS.getContext('2d').scale(scale, scale);
  _CANVAS.getContext('2d').drawImage(_IMG, 0, 0, imgW*_ZOOM_FACTOR, imgH*_ZOOM_FACTOR);
}

⚠ Important!

In order to preserve an image’s aspect ratios while retaining its original resolution, it is extremely important to differentiate between I & II

I. Actual Dimensions — height and width HTML values

<canvas width='100' height='100'></canvas>

II. Displayed Dimensions — height and width values in CSS Styling

<canvas style='width:100px;height:100px'></canvas>

As a rule of thumb, value of window.devicePixelRatio (pixel density) and _CANVAS.getContext('2D').scale() should be invoked when aspect ratios of the CANVAS element are modified.

Illustration by Author | (1) <input id=’uploadImg’ type=’file’ /> is triggered when [Upload Image] is selected | (2) User then selects an image of choice (e.g. serotonin.png) | CANVAS.getContext(‘2D’) then invokes drawImage() to set CANVAS view to image data as shown.

Demonstration of Web Application Tool

Screencapture by Author | Renders selected image via all 3 unique approaches simultaneously (Image, CSS, Canvas)
Image by Author | A static snapshot that displays selected image being rendered via all 3 unique approaches simultaneously (Image, CSS, Canvas)

FYI: Full code implementation is at my GitHub: HTML5-Image-Display (feel free to ★ it or 🔱fork it!) or try it out at demo!

Many thanks for persisting to the end of this article! ❤ Hope you have found this guide useful and feel free to follow me on Medium if you would like more GIS, Data Analytics & Web application-related content. Would really appreciate it — 😀

— 🌮 Please buy me a Taco ξ(🎀˶❛◡❛)

— Feel free to explore the following articles as well (each implementation deep-dives into distinct aspects of similar/related domains):

(1) HTML5, DOM Elements & Encoding Image Content

(2) NodeJS to/from Browser Plugin Compatibility Issues

(3) Other Client-Side JavaScript Productivity Tools

JavaScript
Canvas
Html5
Image
CSS
Recommended from ReadMedium