Movatterモバイル変換


[0]ホーム

URL:


  1. Web
  2. Web APIs
  3. Canvas API
  4. Canvas tutorial
  5. Pixel manipulation with canvas

Pixel manipulation with canvas

Until now we haven't looked at the actual pixels of our canvas. With theImageData object you can directly read and write a data array to manipulate pixel data. We will also look into how image smoothing (anti-aliasing) can be controlled and how to save images from your canvas.

The ImageData object

TheImageData object represents the underlying pixel data of an area of a canvas object.Itsdata property returns aUint8ClampedArray (orFloat16Array if requested) which can be accessed to look at the raw pixel data; each pixel is represented by four one-byte values (red, green, blue, and alpha, in that order; that is, "RGBA" format). Each color component is represented by an integer between 0 and 255. Each component is assigned a consecutive index within the array, with the top left pixel's red component being at index 0 within the array. Pixels then proceed from left to right, then downward, throughout the array.

TheUint8ClampedArray containsheight ×width × 4 bytes of data, with index values ranging from 0 to (height ×width × 4) - 1.

For example, to read the blue component's value from the pixel at column 200, row 50 in the image, you would do the following:

js
const blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2];

If given a set of coordinates (X and Y), you may end up doing something like this:

js
const xCoord = 50;const yCoord = 100;const canvasWidth = 1024;const getColorIndicesForCoord = (x, y, width) => {  const red = y * (width * 4) + x * 4;  return [red, red + 1, red + 2, red + 3];};const colorIndices = getColorIndicesForCoord(xCoord, yCoord, canvasWidth);const [redIndex, greenIndex, blueIndex, alphaIndex] = colorIndices;

You may also access the size of the pixel array in bytes by reading theUint8ClampedArray.length attribute:

js
const numBytes = imageData.data.length;

Creating an ImageData object

To create a new, blankImageData object, you should use thecreateImageData() method. There are two versions of thecreateImageData() method:

js
const myImageData = ctx.createImageData(width, height);

This creates a newImageData object with the specified dimensions. All pixels are preset to transparent.

You can also create a newImageData object with the same dimensions as the object specified byanotherImageData. The new object's pixels are all preset to transparent black.This does not copy the image data!

js
const myImageData = ctx.createImageData(anotherImageData);

Getting the pixel data for a context

To obtain anImageData object containing a copy of the pixel data for a canvas context, you can use thegetImageData() method:

js
const myImageData = ctx.getImageData(left, top, width, height);

This method returns anImageData object representing the pixel data for the area of the canvas whose corners are represented by the points (left,top), (left+width,top), (left,top+height), and (left+width,top+height). The coordinates are specified in canvas coordinate space units.

Note:Any pixels outside the canvas are returned as transparent black in the resultingImageData object.

This method is also demonstrated in the articleManipulating video using canvas.

Creating a color picker

In this example, we are using thegetImageData() method to display the color under the mouse cursor.For this, we need the current position of the mouse, then we look up the pixel data at that position in the pixel array thatgetImageData() provides.Finally, we use the array data to set a background color and a text in the<div> to display the color.Clicking on the image will do the same operation but uses the selected color.

html
<table>  <thead>    <tr>      <th>Source</th>      <th>Hovered color</th>      <th>Selected color</th>    </tr>  </thead>  <tbody>    <tr>      <td>        <canvas width="300" height="227"></canvas>      </td>      <td></td>      <td></td>    </tr>  </tbody></table>
js
const img = new Image();img.crossOrigin = "anonymous";img.src = "/shared-assets/images/examples/rhino.jpg";const canvas = document.getElementById("canvas");const ctx = canvas.getContext("2d");img.addEventListener("load", () => {  ctx.drawImage(img, 0, 0);  img.style.display = "none";});const hoveredColor = document.getElementById("hovered-color");const selectedColor = document.getElementById("selected-color");const pick = (event, destination) => {  const bounding = canvas.getBoundingClientRect();  const x = event.clientX - bounding.left;  const y = event.clientY - bounding.top;  const pixel = ctx.getImageData(x, y, 1, 1);  const data = pixel.data;  const rgbColor = `rgb(${data[0]} ${data[1]} ${data[2]} / ${data[3] / 255})`;  destination.style.background = rgbColor;  destination.textContent = rgbColor;  return rgbColor;};canvas.addEventListener("mousemove", (event) => pick(event, hoveredColor));canvas.addEventListener("click", (event) => pick(event, selectedColor));
body {  font-family: sans-serif;}.color-cell {  color: white;}th {  width: 30%;}td {  font-family: monospace;  font-weight: bold;  padding-left: 1rem;}

Hover your cursor anywhere over the image to see the result in the "Hovered color" column.Click anywhere in the image to see the result in the "Selected color" column.

Painting pixel data into a context

You can use theputImageData() method to paint pixel data into a context:

js
ctx.putImageData(myImageData, dx, dy);

Thedx anddy parameters indicate the device coordinates within the context at which to paint the top left corner of the pixel data you wish to draw.

For example, to paint the entire image represented bymyImageData to the top left corner of the context, you can do the following:

js
ctx.putImageData(myImageData, 0, 0);

Grayscaling and inverting colors

In this example, we iterate over all pixels to change their values, then we put the modified pixel array back onto the canvas usingputImageData().Theinvert function subtracts each color from the max value,255.Thegrayscale function uses the average of red, green and blue. You can also use a weighted average, given by the formulax = 0.299r + 0.587g + 0.114b, for example.SeeGrayscale on Wikipedia for more information.

html
<canvas width="300" height="227"></canvas><form>  <input type="radio" name="color" value="original" checked />  <label for="original">Original</label>  <input type="radio" name="color" value="grayscale" />  <label for="grayscale">Grayscale</label>  <input type="radio" name="color" value="inverted" />  <label for="inverted">Inverted</label>  <input type="radio" name="color" value="sepia" />  <label for="sepia">Sepia</label></form>
js
const canvas = document.getElementById("canvas");const ctx = canvas.getContext("2d");const img = new Image();img.crossOrigin = "anonymous";img.src = "/shared-assets/images/examples/rhino.jpg";img.onload = () => {  ctx.drawImage(img, 0, 0);};const original = () => {  ctx.drawImage(img, 0, 0);};const invert = () => {  ctx.drawImage(img, 0, 0);  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);  const data = imageData.data;  for (let i = 0; i < data.length; i += 4) {    data[i] = 255 - data[i]; // red    data[i + 1] = 255 - data[i + 1]; // green    data[i + 2] = 255 - data[i + 2]; // blue  }  ctx.putImageData(imageData, 0, 0);};const grayscale = () => {  ctx.drawImage(img, 0, 0);  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; // red    data[i + 1] = avg; // green    data[i + 2] = avg; // blue  }  ctx.putImageData(imageData, 0, 0);};const sepia = () => {  ctx.drawImage(img, 0, 0);  const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);  const data = imageData.data;  for (let i = 0; i < data.length; i += 4) {    let r = data[i], // red      g = data[i + 1], // green      b = data[i + 2]; // blue    data[i] = Math.min(Math.round(0.393 * r + 0.769 * g + 0.189 * b), 255);    data[i + 1] = Math.min(Math.round(0.349 * r + 0.686 * g + 0.168 * b), 255);    data[i + 2] = Math.min(Math.round(0.272 * r + 0.534 * g + 0.131 * b), 255);  }  ctx.putImageData(imageData, 0, 0);};const inputs = document.querySelectorAll("[name=color]");for (const input of inputs) {  input.addEventListener("change", (evt) => {    switch (evt.target.value) {      case "inverted":        return invert();      case "grayscale":        return grayscale();      case "sepia":        return sepia();      default:        return original();    }  });}

Click different options to view the result in action.

Zooming and anti-aliasing

With the help of thedrawImage() method, a second canvas, and theimageSmoothingEnabled property, we are able to zoom in on our picture and see the details. A third canvas withoutimageSmoothingEnabled is also drawn to allow a side by side comparison.

html
<table>  <thead>    <tr>      <th>Source</th>      <th>Smoothing enabled = true</th>      <th>Smoothing enabled = false</th>    </tr>  </thead>  <tbody>    <tr>      <td>        <canvas width="300" height="227"></canvas>      </td>      <td>        <canvas width="200" height="200"></canvas>      </td>      <td>        <canvas width="200" height="200"></canvas>      </td>    </tr>  </tbody></table>
body {  font-family: monospace;}

We get the position of the mouse and crop an image of 5 pixels left and above to 5 pixels right and below.Then we copy that one over to another canvas and resize the image to the size we want it to. In the zoom canvas we resize a 10×10 pixel crop of the original canvas to 200×200:

js
const img = new Image();img.crossOrigin = "anonymous";img.src = "/shared-assets/images/examples/rhino.jpg";img.onload = () => {  draw(img);};function draw(image) {  const canvas = document.getElementById("canvas");  const ctx = canvas.getContext("2d");  ctx.drawImage(image, 0, 0);  const smoothCtx = document.getElementById("smoothed").getContext("2d");  smoothCtx.imageSmoothingEnabled = true;  const pixelatedCtx = document.getElementById("pixelated").getContext("2d");  pixelatedCtx.imageSmoothingEnabled = false;  const zoom = (ctx, x, y) => {    ctx.drawImage(      canvas,      Math.min(Math.max(0, x - 5), image.width - 10),      Math.min(Math.max(0, y - 5), image.height - 10),      10,      10,      0,      0,      200,      200,    );  };  canvas.addEventListener("mousemove", (event) => {    const x = event.layerX;    const y = event.layerY;    zoom(smoothCtx, x, y);    zoom(pixelatedCtx, x, y);  });}

Saving images

TheHTMLCanvasElement provides atoDataURL() method, which is useful when saving images. It returns adata URL containing a representation of the image in the format specified by thetype parameter (defaults toPNG). The returned image is in a resolution of 96 dpi.

Note:Be aware that if the canvas contains any pixels that were obtained from anotherorigin without using CORS, the canvas istainted and its contents can no longer be read and saved.SeeSecurity and tainted canvases.

canvas.toDataURL('image/png')

Default setting. Creates a PNG image.

canvas.toDataURL('image/jpeg', quality)

Creates a JPG image. Optionally, you can provide a quality in the range from 0 to 1, with one being the best quality and with 0 almost not recognizable but small in file size.

Once you have generated a data URL from your canvas, you are able to use it as the source of any<img> or put it into a hyperlink with adownload attribute to save it to disc, for example.

You can also create aBlob from the canvas.

canvas.toBlob(callback, type, encoderOptions)

Creates aBlob object representing the image contained in the canvas.

See also

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp