HTML5 Canvas: How To Add Text To An Image (10 Working Demos)

This guide has a lot of code samples to help you load an image and write text on top of the image for a wide variety of situations.

Some of the topics covered will be:

  • Loading an image from a URL or image tag
  • Sizing the canvas based on the image size
  • Adding text to an image like a watermark
  • Solving the “word wrap” problem when adding text to an image using canvas
  • Writing text with a custom font (loaded via CSS or JS)

The Main Issue / Challenge / Trick That Comes Up

When trying to add text on top of an image, the main issue that people usually face is the sequence of events..

  • We need to first load the image
  • After that is complete…
  • We need to write the text on top of the image

This seems obvious, but the way the JS code is structured gets tricky..

So, since both the steps are interrelated, this is going to be an “in-depth guide” to both loading the image and THEN writing text on top of it. 

Step 1: Loading An Image (A Few Different Ways, Based On Your Needs)

Option 1: Loading An Image From A URL & Setting The Width & Height Of The Canvas To Match The Image

The plan for us to do this is as follows:

  1. Create a new “Image” via JavaScript (docs from MDN) (let img = new Image();)
  2. For that Image, write a function to say what happens after the loading of the image is completed. (image.onload = ..)
  3. Once the image is loaded, we get the width and height of the image, so we can use that to set the width and height of the canvas
  4. Finally, we draw the image on top of the canvas using the “drawImage” function. (docs from MDN)

The code..

let loadImageOnCanvasAndResizeCanvasToFitImage = (canvas, imageUrl) => {
  // Get the 2D Context from the canvas
  let ctx = canvas.getContext("2d");

  // Create a new Image
  let img = new Image();

  // Setting up a function with the code to run after the image is loaded
  img.onload = () => {
    // Once the image is loaded, we will get the width & height of the image
    let loadedImageWidth = img.width;
    let loadedImageHeight = img.height;

    // Set the canvas to the same size as the image.
    canvas.width = loadedImageWidth;
    canvas.height = loadedImageHeight;

    // Draw the image on to the canvas.
    ctx.drawImage(img, 0, 0);
  };

  // Now that we have set up the image "onload" handeler, we can assign
  // an image URL to the image.
  img.src = imageUrl;
};

An here is the live working example..

See the Pen
Canvas Loading A Image From URL
by Khoj Badami (@livefiredev)
on CodePen.

The “drawImage” function..

As you can see above, the “drawImage” function is used to draw the text on top of an image.

There are a few different ways you could use the function like:

  1. drawImage(image, dx, dy)
  2. drawImage(image, dx, dy, dWidth, dHeight)
  3. drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)

Now, in the above code, we have use the first method. But, in other situations, we will have to use the other function signatures.

What the different parameters mean..

explanation of the "drawImage" parameters used to draw image on top of the canvas

This image is from the MDN docs about the function.

As you can see you have a lot of control. Using the parameters, you can take even a small part of the image and place it anywhere on the canvas.

You probably guessed it, but the “s” prefix means “source”. Also the “d” prefix means “destination”.

So, the different parameters mean the following: 

  • dx: When placing the image on the canvas (in its destination) what should be the x coordinate of the top right corner.
  •  dy: When placing the image on the canvas (in its destination) what should be the y coordinate of the top right corner.
  • dWidth & dHeight: What should be the width and height of the image on the canvas.
  • sWidth & sHeight in combination with sx, & sy:  What should be the “window” (in terms of width and height, starting at sx and sy) we crop out of the source image to place it on the canvas.

The method signature we have used above is:

drawImage(image, dx, dy)

In this form, we are saying: “I want the whole image. And place it at the dx, dy coordinates on my canvas” (As you can see from the the image above, the 0,0 point is the top left corner.)

Option 2: Loading An Image From An IMG Tag & Setting The Width & Height Of The Canvas To Match The Image

So, here we will assume that you already have an IMG tag on your page with the image. This is not likely, because then you would have 2 places on your page with the same image. But still, lets make that assumption.

Let’s look at the code..

function loadCanvasWithImageBasedOnImagTag(imageID, canvasID) {
   // get the image
  let theImage = document.getElementById(imageID);
  
  // get the canvas
  let theCanvas = document.getElementById(canvasID);

  // get the canvas 2D context
  let ctx = theCanvas.getContext("2d");
  
  // Create a function to run after the image is loaded
  let runAfterImageIsLoaded = () => {
    
    // set the canvas width and height to the image
    theCanvas.width = theImage.width;
    theCanvas.height = theImage.height;
    
    // Draw the image on the canvas
    ctx.drawImage(theImage, 0, 0);  
  }
  
  // If we can access the image width, then the image must already be loaded!
  if ( theImage.width ) {
    runAfterImageIsLoaded();
  }
  
  // Just incase the image is not loaded, then we will set up the function to be run
  // as soon as the image gets loaded..
  theImage.onload = runAfterImageIsLoaded;
}

And here is a live demo..

See the Pen
HTML5 Canvas Loading An Image From An Image Tag
by Khoj Badami (@livefiredev)
on CodePen.

Option 3: Loading An Image Where The Canvas Has A Fixed Size & The Image Is Larger & We FIT The Image Inside The Canvas Without Cropping

In this situation, the image has a width or height that is bigger than the canvas. So, we have scale the image down and centre it and place it in the middle of the canvas.

For example:

So, the end result will look like this…

Image loaded into a smaller canvas scaled to fit in the center

The plan to achieve this is as follows:

  1. Figure out how much we need to “scale down” the image.
  2. Reduce the width and height of the image by that “scale factor”
  3. Place the image in the centre of the canvas

If you want a detailed explanation of how this code works check this article. It explains how the “scale image to fit / fill canvas” problem is solved.

The code to achieve all this is as follows:

img.onload = () => {
    // Once the image is loaded, we will get the width & height of the image
    let loadedImageWidth = img.width;
    let loadedImageHeight = img.height;

    // get the scale
    // it is the min of the 2 ratios
    let scale_factor = Math.min( canvas.width/img.width, canvas.height/img.height );
    
    // Lets get the new width and height based on the scale factor
    let newWidth = img.width * scale_factor;
    let newHeight = img.height * scale_factor;
        
    // get the top left position of the image
    // in order to center the image within the canvas
    let x = ( canvas.width/2 ) - ( newWidth/2 );
    let y = ( canvas.height/2 ) - ( newHeight/2 );
    
    // When drawing the image, we have to scale down the image
    // width and height in order to fit within the canvas
    ctx.drawImage(img, x, y, newWidth, newHeight);
};

And here is the working demo…

See the Pen
Loading An Image Where The Canvas Has A Fixed Size, We FIT The Image Inside The Canvas Without Cropping
by Khoj Badami (@livefiredev)
on CodePen.

Option 4: Loading An Image That Is Larger Than The Canvas, And Filling The Canvas With The Image (some cropping of the image will occur)

First let us look at how the result looks when an image of size: 402×599 is made to “fill up” a canvas of size: 400×400

image of size: 402x599 is made to "fill up" a canvas of size: 400x400

The code the achieve this is almost exactly the same as before. The only difference is when we try to calculate the “scale” we look for the max ratio instead of the min. (see line 9 below)

If you want a detailed explanation of how this code works check this article. It explains how the “scale image to fit / fill canvas” problem is solved.

Below is the code:

// Setting up a function with the code to run after the image is loaded
  img.onload = () => {
    // Once the image is loaded, we will get the width & height of the image
    let loadedImageWidth = img.width;
    let loadedImageHeight = img.height;

    // get the scale
    // it is the min of the 2 ratios
    let scaleFactor = Math.max( canvas.width/img.width, canvas.height/img.height);
    
    // Finding the new width and height based on the scale factor
    let newWidth = img.width * scaleFactor;
    let newHeight = img.height * scaleFactor;
    
    // get the top left position of the image
    // in order to center the image within the canvas
    let x = ( canvas.width/2 ) - ( newWidth/2 );
    let y = ( canvas.height/2 ) - ( newHeight/2 );
    
    // When drawing the image, we have to scale down the image
    // width and height in order to fit within the canvas
    ctx.drawImage(img, x, y, newWidth, newHeight);
  };

And here is the code in action..

See the Pen
Untitled
by Khoj Badami (@livefiredev)
on CodePen.

Step 2: Writing Text On Top Of An Image (A Few Different Ways, Based On Your Needs)

Now that the image is loaded, we can start to write text on top of it.

Below we will look at some code snippets to handle various text writing needs.

Adding Text To An Image Like A Watermark

Here is a function that can be used..

let loadImageOnCanvasAndThenWriteText = (canvas, imageUrl, textToWrite, textStyleOptions, xCordOfText, yCordOfText) => {
  // Get the 2D Context from the canvas
  let ctx = canvas.getContext("2d");

  // Create a new Image
  let img = new Image();

  // Setting up a function with the code to run after the image is loaded
  img.onload = () => {
    // Once the image is loaded, we will get the width & height of the image
    let loadedImageWidth = img.width;
    let loadedImageHeight = img.height;

    // Set the canvas to the same size as the image.
    canvas.width = loadedImageWidth;
    canvas.height = loadedImageHeight;

    // Draw the image on to the canvas.
    ctx.drawImage(img, 0, 0);

    // Set all the properties of the text based on the input params
    ctx.font = `${textStyleOptions.fontSize}px ${textStyleOptions.fontFamily}`;
    ctx.fillStyle = textStyleOptions.textColor;
    ctx.textAlign = textStyleOptions.textAlign;
    
    // Setting this so that the postion of the text can be set
    // based on the x and y cord from the top right corner
    ctx.textBaseline = "top";
    
    // Finanlly addeing the text to the image
    ctx.fillText(textToWrite, xCordOfText, yCordOfText);
  };

  // Now that we have set up the image "onload" handeler, we can assign
  // an image URL to the image.
  img.src = imageUrl;
};

As you can see above, once the image is loaded, we start to draw the text on the image.

The code to call the function looks like this..

// Setting up the canvas
let theCanvas = document.getElementById("myCanvas");

// Some image URL..
let imageUrl =
  "https://livefiredev.com/wp-content/uploads/2022/08/mona-lisa.jpeg";

let textStyleOptions = {
  fontSize: 30,
  fontFamily: "Arial",
  textColor: "rgba(255, 255, 255, 0.4)",
  textAlign: "left"
};

let textToWrite = "© daVinci - Year 1503";

let xCordOfText = 10;
let yCordOfText = 10;

// Load image on the canvas & then write text
loadImageOnCanvasAndThenWriteText(
  theCanvas,
  imageUrl,
  textToWrite,
  textStyleOptions,
  xCordOfText,
  yCordOfText
);

Finally here is a working demo..

See the Pen
Adding Text To An Image Like A Watermark
by Khoj Badami (@livefiredev)
on CodePen.

Writing Text On Top Of An Image With Word Wrap

HTML5 Canvas does not have any built in “line break” and “word wrap” system. However, we can use the “measureText function to figure out how much space the text to be drawn will take.

Below is a function you can use for this purpose..

function getLines(ctx, text, maxWidth) {
  var words = text.split(" ");
  var lines = [];
  var currentLine = words[0];

  for (var i = 1; i < words.length; i++) {
    var word = words[i];
    var width = ctx.measureText(currentLine + " " + word).width;
    if (width < maxWidth) {
      currentLine += " " + word;
    } else {
      lines.push(currentLine);
      currentLine = word;
    }
  }
  lines.push(currentLine);
  return lines;
}

I have modified the code in the above example to use this function. The new function is as follows:

let loadImageOnCanvasAndThenWriteText = (
  canvas,
  imageUrl,
  textToWrite,
  textStyleOptions,
  xCordOfText,
  yCordOfText,
  textBoundingBoxWidth
) => {
  // Get the 2D Context from the canvas
  let ctx = canvas.getContext("2d");

  // Create a new Image
  let img = new Image();

  // Setting up a function with the code to run after the image is loaded
  img.onload = () => {
    // Once the image is loaded, we will get the width & height of the image
    let loadedImageWidth = img.width;
    let loadedImageHeight = img.height;

    // Set the canvas to the same size as the image.
    canvas.width = loadedImageWidth;
    canvas.height = loadedImageHeight;

    // Draw the image on to the canvas.
    ctx.drawImage(img, 0, 0);

    // Set all the properties of the text based on the input params
    ctx.font = `${textStyleOptions.fontSize}px ${textStyleOptions.fontFamily}`;
    ctx.fillStyle = textStyleOptions.textColor;
    ctx.textAlign = textStyleOptions.textAlign;

    // Setting this so that the postion of the text can be set
    // based on the x and y cord from the top right corner
    ctx.textBaseline = "top";

    // Get lines array
    let arrayOfLines = getLines(ctx, textToWrite, textBoundingBoxWidth);
    
    // Set line height as a little bit bigger than the font size
    let lineheight = textStyleOptions.fontSize + 10;
    
    // Loop over each of the lines and write it over the canvas
    for (let i = 0; i < arrayOfLines.length; i++) {
      ctx.fillText(arrayOfLines[i], xCordOfText, yCordOfText + ( i * lineheight ) );
    }
  };

  // Now that we have set up the image "onload" handeler, we can assign
  // an image URL to the image.
  img.src = imageUrl;
};

As you can see, it now takes an extra parameter that defines the “width of the bounding box” around the text.

Lets have a look at all of this in a working demo..

See the Pen
Writing Text On Top Of An Image With Word Wrap
by Khoj Badami (@livefiredev)
on CodePen.

Writing Text On Top Of An Image With Word Wrap (Center Align)

Almost everything here remains the same. The reason I am mentioning this is because you need to look out for some unexpected behaviour.

When you set the “textAlign” property as “center”, the middle of the text becomes the “x” and “y” cord of the text on which everything is based. So, you need to set it appropriately.

Below is a working example..

See the Pen
Writing Text On Top Of An Image With Word Wrap (Center Align)
by Khoj Badami (@livefiredev)
on CodePen.

Writing Text On Top Of An Image With A Custom Font (Loaded Via CSS)

So, when you load fonts via CSS, something like..

<link href="https://fonts.googleapis.com/css2?family=Mouse+Memoirs&display=swap" rel="stylesheet">

In the “head” section of the document, the font can be used to write text on the canvas just like any other text.

But, there is an issue to look out for…

You might find that “sometimes, the font loads and sometimes it does not“. This is happening because the font is loaded after the JS is run.

You can fix this by doing the following….

// Use the JS font load function as below
// and run all your canvas setting up code only after
// the font is completed loading..
document.fonts.load('100px "Mouse Memoirs"').then(() => {
  
  // Setting up the canvas
  let theCanvas = document.getElementById("myCanvas");

  // Some image URL..
  let imageUrl =
    "https://livefiredev.com/wp-content/uploads/2022/08/mona-lisa.jpeg";

  let textStyleOptions = {
    fontSize: 25,
    fontFamily: "Mouse Memoirs",
    textColor: "rgba(255, 255, 255, 0.9)",
    textAlign: "left"
  };

  let textToWrite =
    "The Mona Lisa is one of the most valuable paintings in the world.";

  let xCordOfText = 10;
  let yCordOfText = 10;

  let textBoundingBoxWidth = 350;

  // Load image on the canvas & then write text
  loadImageOnCanvasAndThenWriteText(
    theCanvas,
    imageUrl,
    textToWrite,
    textStyleOptions,
    xCordOfText,
    yCordOfText,
    textBoundingBoxWidth
  );
  
});

In the previous examples, we were doing all of our canvas code after the document was loaded. As you can see above. Now, we are doing it after the custom fonts are loaded.

Below are the MDN docs for the above “load” function.

Here is a live example..

See the Pen
Writing Text On Top Of An Image With A Custom Font (Loaded Via CSS)
by Khoj Badami (@livefiredev)
on CodePen.

Writing Text On Top Of An Image With A Custom Font (Loaded Via JS)

Some times, you might need to load the font you want to use on the canvas “dynamically”. Maybe the use is selecting the font from a drop down. So, lets see how to tackle that situation next.

So, in order to get this done, you can use the Web Font Loader JS libray.

Here is a CDN link for the the same..

<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js"></script>

Using the library to load Google fonts is quite simple. See the sample code below..

WebFont.load({
  google: {
    families: ["Mouse+Memoirs:400"]
  },
  active: () => {
    doAllTheCanvasStuff();
  }
});

As you can see you just have to specify the font name and weights you want and also what should happen after the fonts are loaded using the “active” key.

Note: This JS library NOT ONLY supports Google Fonts, but many other font sources.

Here is a working example..

See the Pen
Writing Text On Top Of An Image With A Custom Font (Loaded Via JS)
by Khoj Badami (@livefiredev)
on CodePen.

Bonus Tip: Add A Dark Overly To Make The Text More Readable When Writing Text Over The Image

Before we write the text, lets just create a slight overlay on top of the image. This will help the text stand out.

All you have to do is create a rectangle and fill the canvas with it after the image is loaded and before you write the text.

// Create a rectangle and fill the canvas with it
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, loadedImageWidth, loadedImageHeight);

Here is the live example.

See the Pen
Add A Dark Overly To Make The Text More Readable When Writing Text Over The Image
by Khoj Badami (@livefiredev)
on CodePen.