Applying A Circular Crop Mask To An Image
Profile pictures are often masked by a circle. How can we present our images in such a circle. Lets explore two options, one where we use CSS and one where we actually mask the image data.
Applying the mask using CSS
Applying a circular mask to an image using CSS is quite straightforward. We only have to set the border-radius
property and we’re done.
<style>
img {
border-radius: 50%;
}
</style>
<img src="/media/cat.jpeg" alt="" />
But what if our image isn’t a square?
To prevent elliptic cats we have to make sure our image is a square.
<style>
img {
width: 128px;
height: 128px;
border-radius: 50%;
}
</style>
<img src="/media/cat.jpeg" alt="" />
Okay, but now our cat is squished. Let’s unsquish it using CSS object-fit
.
<style>
img {
width: 128px;
height: 128px;
object-fit: cover;
border-radius: 50%;
}
</style>
<img src="/media/cat.jpeg" alt="" />
Done!
Applying a Circular Mask using Canvas
To modify the actual image data we can use the <canvas>
element and apply the circular mask to the image itself.
Let’s use a file input element and apply the mask to the added file.
<input type="file" accept="image/*" />
<canvas hidden></canvas>
<script>
// get a reference to the file input
const fileInput = document.querySelector('input');
// get a reference to the output canvas
const canvas = document.querySelector('canvas');
// listen for the change event so we can capture the file
fileInput.addEventListener('change', (e) => {
// get a reference to the file
const file = e.target.files[0];
// let's load the image data
const image = new Image();
image.onload = () => {
// use min size so we get a square
const size = Math.min(image.naturalWidth, image.naturalHeight);
// let's update the canvas size
canvas.width = size;
canvas.height = size;
// draw image to canvas
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
// only draw image where mask is
ctx.globalCompositeOperation = 'destination-in';
// draw our circle mask
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(
size * 0.5, // x
size * 0.5, // y
size * 0.5, // radius
0, // start angle
2 * Math.PI // end angle
);
ctx.fill();
// restore to default composite operation (is draw over current image)
ctx.globalCompositeOperation = 'source-over';
// show canvas
canvas.hidden = false;
};
image.src = URL.createObjectURL(file);
});
</script>
Try it below!