Crop An Image With Canvas
Cropping images in the browser can be done with the HTML5 canvas element. In this tutorial we’ll load an image from a local URL, crop the image, and present the result on the same page.
Okay, first we need an image. Let’s use the image below, it’s located at the URL: https://pqina.nl/media/test.jpeg

Our next goal is to load this image into a canvas element.
Loading an image in a canvas element
To draw an image to a canvas element we need to use the drawImage method on the 2d context of the canvas element.
<canvas id="my-canvas"></canvas>
This will create a 300 × 150 canvas on the page, we can adjust the width and height with the width and height attributes. For now we’ll try to draw our image.
// get a reference to the canvas element
const myCanvas = document.getElementById('my-canvas');
// then we need to access the 2d context of the canvas for drawing 2d imagery
const ctx = myCanvas.getContext('2d');
// now we draw the image
ctx.drawImage('/media/test.jpeg');
That doesn’t work unfortunately. The drawImage method expects the image in a different format, and it expects a dx and dy coordinate. Those are the x and y coordinates of the top left corner in the canvas where we start drawing the image.
We’ll load the URL into an <img> and then we’ll draw it to our <canvas>, I’ve put a red outline around it so we can clearly see it’s borders.
// get a reference to the canvas element and its 2d context
const myCanvas = document.getElementById('my-canvas');
const ctx = myCanvas.getContext('2d');
// the image we're going to draw
const myImage = new Image();
// we wait for the image to load, then we draw
myImage.onload = () => {
// draw myImage at 0,0
ctx.drawImage(myImage, 0, 0);
};
// the image we want to load
myImage.src = '/media/test.jpeg';
Tadaa, there’s our image. And it’s already cropped!
Cropping a square image in canvas
Let’s say we want to make a square crop. To achieve a square crop we’ll have to change the width and height of our canvas to the intended size of the resulting image.
<canvas id="my-canvas" width="256" height="256"></canvas>
Now we want to choose which part we crop, and that we can do with the dx and dy parameters.
Let’s say we want to crop the center. This means we need to use the canvas size and the image size to calculate the correct dx and dy coordinates.
We can get the image width and height using the naturalWidth and naturalHeight properties of the Image instance.
To calculate the center we subtract the image width from the canvas width and then we divide by 2, that puts the top left corner exactly where we want it.
myImage.onload = () => {
const dx = (myCanvas.width - myImage.naturalWidth) * 0.5;
const dy = (myCanvas.height - myImage.naturalHeight) * 0.5;
ctx.drawImage(myImage, dx, dy);
};
That’s it, that’s how you crop an image using the HTML canvas element.
We can supply more parameters to the drawImage to also control the scaling of the image. We can control the quality of the scaling using the imageSmoothingQuality property but at the time of this writing it’s not available on Firefox.
Downloading the resulting image
Okay, we have our resulting image on the screen but we want it in our downloads folder.
We can do so by converting the <canvas> into a Blob using the toBlob() method on the canvas element (not the 2d context).
We’ll use the downloadFile function which we wrote in another article.
Additionally we’ll wrap the toBlob call inside a try catch statement, meaning that if something goes wrong, the site doesn’t crash and we can nicely handle the error.
myImage.onload = () => {
// make the square crop
const dx = (myCanvas.width - myImage.naturalWidth) * 0.5;
const dy = (myCanvas.height - myImage.naturalHeight) * 0.5;
ctx.drawImage(myImage, dx, dy);
try {
// convert to a blob
myCanvas.toBlob(
// this function runs when the blob has been created
(blob) => {
if (blob === null) {
// something went wrong
return;
}
// we use the `downloadFile` function from this article:
// https://pqina.nl/blog/how-to-prompt-the-user-to-download-a-file-instead-of-navigating-to-it/
downloadFile(blob);
},
// the image type of the resulting blob
'image/jpeg',
// the image quality of the resulting blob, a lower number means more compression
0.5
);
} catch (err) {
// something went wrong
console.error(err);
}
};
Please note that when loading images from remote URLs it’s possible that the remote site doesn’t allow drawing their images to a canvas.
More information on canvas and remote images can be found on MDN.