Web Development: How to load an image into a canvas element

Canvas has been around for a good while now and sees quite good browser support. It’s an immensely powerful tool for some use cases and something as simple as loading up an image into it is slightly more involved than your average img tag so we’ve taken the time to put together a bit of a tutorial on the drawImage() method of CanvasRenderingContext2D which is what we use to draw an image to a canvas!

As with most things Canvas we’ll need a canvas object and an appropriate context (this tutorial only covers 2D projects), for this task we’ll also need an image object (specifically a HTMLImageElement which is simply a reference to an img element – any old image obtained with document.querySelector or similar methods would also work fine). Any old HTML page will work for the mark-up, we’ll create everything we need via JS so just add a script tag or create a file and reference it via a script tag whatever your method of preference is. We use an event listeners appropriately so as to make sure DOM is all good to go and so that the script can be dropped anywhere reasonable (header/body etc.) and still work.

document.addEventListener("DOMContentLoaded", ()=> {
  // Create a canvas element and add it to the document 
  //    the same as writing <canvas></canvas> in your HTML
  let canvas = document.createElement('canvas');
  document.body.appendChild(canvas);

  // Obtain a 2d canvas context (specifically a CanvasRenderingContext2D)
  let ctx = canvas.getContext('2d');

  // Create an image object and set its source (similar to <img src='images/image.jpg' />)
  // We just create the element and don't append it to the document as we'll render it to canvas
  let image = new Image();
  image.src = 'images/image.jpg';
});

So this gets us all we need… well almost! The image might still be loading! So let’s wait for it to load so that we can both determine its dimensions, resize the canvas accordingly and then draw it to the canvas.

// Add this in before the closing });
image.addEventListener('load', (e)=>{
    canvas.width = image.naturalWidth;
    canvas.height= image.naturalHeight;
    ctx.drawImage(image, 0,0);
});

So the final snippet should look like this:

document.addEventListener("DOMContentLoaded", ()=> {
  // Create a canvas element and add it to the document 
  //    the same as writing <canvas></canvas> in your HTML
  let canvas = document.createElement('canvas');
  document.body.appendChild(canvas);

  // Obtain a 2d canvas context (specifically a CanvasRenderingContext2D)
  let ctx = canvas.getContext('2d');

  // Create an image object and set its source (similar to <img src='images/image.jpg' />)
  // We just create the element and don't append it to the document as we'll render it to canvas
  let image = new Image();
  image.src = 'images/image.jpg';
  image.addEventListener('load', (e)=>{
    canvas.width = image.naturalWidth;
    canvas.height= image.naturalHeight;
    ctx.drawImage(image, 0, 0);
  });
});

More drawImage() examples

CanvasRenderingContext2D.drawImage() has a few useful variations, it allows optionally specifying both position and size of the source and destination (the MDN reference is great if you want to learn more. In the example above we simply specify we want to draw our image at a destination of 0,0 (x, y) on the canvas. The example below can be used by simply replace the ctx.drawImage call with one of the examples snippets below.

Scaling an image

The following example will draw at 0, 0 and at 1/4 the images original size maintaining proportions (half the width and height)

// 'd' variable prefix denotes destination
let dx = 0;
let dy = 0;
let dWidth = image.naturalWidth / 2;
let dHeight =image.naturalHeight /2;

ctx.drawImage(image, dx, dy, dWidth, dHeight);

Copying part of a source image whilst positioning & scaling it in a canvas target

Another powerful option is if you wish you can specify both source and destination x, y, width and heights, this enables us to copy a portion of an image and position + scale it all in one call. Say for example you want to copy from a sprite sheet that’s a grid of 32px squares and scale it down for a game that uses a 16px grid in some views and say we want to take the first sprite and draw it to 48,48. You could achieve this by doing something like:

// 's' variable prefix denotes source
let sx = 0;
let sy = 0;
let sWidth = 32;
let sHeight = 32;

// 'd' variable prefix denotes destination
let dx = 48;
let dy = 48;
let dWidth = 16;
let dHeight = 16;

ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);

CanvasRenderingContext2D.drawImage() is quite the powerful tool especially when coupled with some of HTML5 other canvas functions. With the examples included with a little work you could make a browser based image scaler, or the start of rendering sprite based maps or characters for a game among other things. Enjoy!