Canvas Manipulating Images

Beginner
⏱️ 12 min read
📚 Updated: Aug 2025
🎯 Live + 3 Examples
drawImage + Pixels

What You’ll Learn

Canvas can draw images and then manipulate them in two main ways:

  • Geometry transforms: scale, rotate, flip, and crop using drawImage() + transforms.
  • Pixel effects: read and modify raw RGBA pixels using getImageData() / putImageData().

⚡ Quick Reference

Draw & scale drawImage(img, dx, dy, dw, dh)

Scale to dw/dh while drawing

Crop + scale drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)

Crop source then draw

Pixels getImageData / putImageData

Edit RGBA values

👀 Live Preview — Crop, Rotate & Filter

This demo generates a sample image (or you can upload one), then lets you crop, rotate, scale, flip, and apply pixel effects.

generated · 100% · 0°

Tip: pixel effects here use getImageData(). If you draw cross‑origin images without CORS, browsers block pixel reads with a security error.

1

Scale an Image with drawImage()

Scaling is built into drawImage() via destination width/height.

script.js
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const img = new Image();

img.onload = () => {
  // Draw image scaled to 200×150
  ctx.drawImage(img, 20, 20, 200, 150);
};

img.src = '/images/example.jpg';
2

Rotate (Transform) Before Drawing

Rotate around the canvas center by translating first, then rotate, then draw around (0,0).

script.js
ctx.clearRect(0, 0, canvas.width, canvas.height);

ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI / 180 * 25);

// draw centered
ctx.drawImage(img, -img.width / 2, -img.height / 2);
ctx.restore();
3

Grayscale Filter with getImageData()

Pixel manipulation edits the ImageData.data array (RGBA values in the range 0..255).

script.js
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;

for (let i = 0; i < data.length; i += 4) {
  const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
  data[i] = avg;     // R
  data[i + 1] = avg; // G
  data[i + 2] = avg; // B
}

ctx.putImageData(imageData, 0, 0);

💡 Best Practices

Do

  • Use ctx.save()/ctx.restore() around transforms
  • Use the 9-argument drawImage() to crop and scale in one step
  • Cache intermediate results using an offscreen canvas when applying many effects
  • Prefer same-origin images (or proper CORS) if you need getImageData()
  • Set imageSmoothingEnabled / imageSmoothingQuality when scaling

Don’t

  • Forget that transforms are cumulative (always restore)
  • Run heavy pixel loops every frame on large canvases without profiling
  • Assume uploaded/cross-origin images always allow pixel reads
  • Mutate ImageData.data without clamping to 0..255
  • Over-allocate new ImageData each time when you can reuse buffers

❓ Frequently Asked Questions

Use drawImage(img, x, y, width, height). The destination width/height scales the image.
Use drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) to crop a source rectangle then draw it to the destination.
If the canvas is tainted by a cross-origin image without CORS headers, browsers block pixel reads for security.
Use ctx.filter for simple effects while drawing. Use pixel manipulation for custom effects (but it can be slower).

Next: Canvas Pattern

Create repeating fills and textures using createPattern().

Canvas Pattern →

About the author

Mari Selvan M P
Mari Selvan M P 🔗

Developer, cloud engineer, and technical writer

  • Experience 12 years building web and cloud systems
  • Focus Full Stack Development, AWS, and Developer Education

I write practical tutorials so students and working developers can learn by doing—from databases and APIs to deployment on AWS.

4 people found this page helpful