DEV Community

Gobinda Adhikari
Gobinda Adhikari

Posted on

Cropping images into shapes in the browser: canvas clip paths vs SVG masks

Cropping images into shapes in the browser: canvas clip paths vs SVG masks

I build free browser tools, and one problem keeps coming up: letting users crop a photo into a circle, heart, star, or any custom shape — entirely client-side, no upload, no server. There are two solid ways to do it. Here's how they compare, with code.

Option 1: Canvas clip()

The canvas 2D API has clipping built in. Draw your shape path, call clip(), then draw the image — everything outside the path is discarded:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// define the shape (a heart, a star, whatever)
ctx.beginPath();
drawHeartPath(ctx, canvas.width, canvas.height);
ctx.clip();

// the image is now masked to the shape
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

const png = canvas.toDataURL('image/png'); // transparent outside the shape
Enter fullscreen mode Exit fullscreen mode

Pros: one API, fast, and toDataURL / toBlob gives you a transparent PNG for free. Cons: you're limited to what you can express as a canvas path, and anti-aliasing at the edge depends on the browser.

Option 2: SVG <mask> / <clipPath>

If your shapes are defined as SVG (which scales cleanly), apply them as a mask over an <image> element:

<svg viewBox="0 0 400 400">
  <defs>
    <clipPath id="star-clip">
      <path d="M200,20 L240,150 L380,150 L265,230 L305,360 L200,280 L95,360 L135,230 L20,150 L160,150 Z"/>
    </clipPath>
  </defs>
  <image href="photo.jpg" width="400" height="400" clip-path="url(#star-clip)"/>
</svg>
Enter fullscreen mode Exit fullscreen mode

Pros: resolution-independent, easy to offer 50+ shapes as reusable path definitions, and CSS can animate the mask. Cons: exporting the result as a standalone PNG still means round-tripping through canvas (drawImage of the SVG, then toBlob).

Which one I shipped

I use both: SVG paths as the shape library (easy to add new shapes, crisp at any size), canvas as the export engine (reliable transparent PNG output). The whole thing runs in the page — images never leave the user's device, so there's no upload wait and no privacy question.

It's live as a free tool if you want to see the result: Change Image Shape — pick a photo, choose from 50+ shapes, download. The editor is the same pipeline described above.

Takeaways

  • For simple masking with export, canvas clip() is the shortest path.
  • For a shape library, keep shapes as SVG path data and render/export via canvas.
  • Client-side processing removes an entire class of problems: no storage, no bandwidth bills, no GDPR headache for user photos.

If you've done shape masking differently — OffscreenCanvas, WebGL shaders — I'd like to hear how it went.

Top comments (0)