直到目前為止,我們還沒真正了解 pixels 在 canvas上的運用。使用ImageData物件,可直接對pixel 裡的陣列資料讀(read)寫(write)。在接下的內容中,也可了解到如何使影像平滑化(反鋸齒)及如何將影像保存在canvas之中。

ImageData物件

ImageData 物件代表canvas區中最基礎的像素。

包含它只可讀的屬性:

width
影像中的寬度,以pixels為單位
height
影像中的高度,以pixels為單位
data
Uint8ClampedArray 代表一維陣列包含RGBA 格式。整數值介於0到255之間(包含255)。

data 屬性返回一個Uint8ClampedArray,它可被當作為pixel的初始資料。每個pixel用4個1byte值做代表分別為透明值(也就是RGBA格式)。每個顏色組成皆是介於整數值介於0到255之間。而每個組成在一個陣列中被分配為一個連續的索引。從左上角 pixel 的紅色組成中的陣列由索引 0 為始。Pixels 執行順序為從左到右,再由上到下,直到整個陣列。

Uint8ClampedArray  包含height × width× 4 bytes的資料,同索引值從0到 (height×width×4)-1

例如,讀取影像的藍色組成的值。從pixel 的第200欄、第50行,你可以照著下面的步驟:

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

使用Uint8ClampedArray.length屬性來讀取影像pixel的陣列大小

var numBytes = imageData.data.length;

創造一個 ImageData物件

可以使用createImageData()方法創造一個全新空白的ImageData 物件。

這裡有兩種createImageData()的方法:

var myImageData = ctx.createImageData(width, height);

這個方法是有規定大小尺寸.所有pixels預設是透明的黑色。

下面的方法一樣是由anotherImageData參考尺寸大小,由ImageData 物件創造一個與新的一樣的大小。這些新的物件的pixel皆預設為透明的黑色。

var myImageData = ctx.createImageData(anotherImageData);

得到pixel資料的內容

可以使用getImageData()這個方法,去取得canvas內容中ImageData 物件的資料含pixel 數據(data) 

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

這個方法會返回ImageData物件,它代表著在這canvas區域之中pixel 的數據(data) 。從各角落的點代表著 (left,top), (left+width, top), (left, top+height), and (left+width, top+height)。這些作標被設定為canvas 的空間座標單位。

注釋: 在ImageData 物件中,任何超出canvas外的pixels皆會返回透明的黑色的形式。

這個方法也被展示在使用canvas操作影像之中。

調色盤

這個範例使用getImageData() 方法去顯示在鼠標下的顏色。

首先,需要一個正確的滑鼠點layerX​​​​​​​和 layerY。在從getImageData() 提供pixel 陣列中(array)該點的pixel 數據(data) 。最後,使用陣列數據(array data)在<div>中設置背景色和文字去顯示該色。

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
img.onload = function() {
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
};
var color = document.getElementById('color');
function pick(event) {
  var x = event.layerX;
  var y = event.layerY;
  var pixel = ctx.getImageData(x, y, 1, 1);
  var data = pixel.data;
  var rgba = 'rgba(' + data[0] + ', ' + data[1] +
             ', ' + data[2] + ', ' + (data[3] / 255) + ')';
  color.style.background =  rgba;
  color.textContent = rgba;
}
canvas.addEventListener('mousemove', pick);

在內容中寫入pixel 資料

可以使用putImageData() 方法將自訂pixel 數據(data) 放入內容中:

ctx.putImageData(myImageData, dx, dy);

dx 和 dy參數表示填入你所希望的座標,將它代入內容中左上角的pixel 數據(data)。

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

ctx.putImageData(myImageData, 0, 0);

灰階和負片效果

In this example we iterate over all pixels to change their values, then we put the modified pixel array back to the canvas using putImageData(). The invert function simply subtracts each color from the max value 255. The grayscale function simply uses the average of red, green and blue. You can also use a weighted average, given by the formula x = 0.299r + 0.587g + 0.114b, for example. See Grayscale on Wikipedia for more information.

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
  draw(this);
};

function draw(img) {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
  var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
  var data = imageData.data;
    
  var invert = function() {
    for (var 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);
  };

  var grayscale = function() {
    for (var i = 0; i < data.length; i += 4) {
      var 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);
  };

  var invertbtn = document.getElementById('invertbtn');
  invertbtn.addEventListener('click', invert);
  var grayscalebtn = document.getElementById('grayscalebtn');
  grayscalebtn.addEventListener('click', grayscale);
}

放大和平滑化(反鋸齒)

With the help of the drawImage() method, a second canvas and the imageSmoothingEnabled property, we are able to zoom into our picture and see the details.

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.

zoomctx.drawImage(canvas, 
                  Math.abs(x - 5), Math.abs(y - 5),
                  10, 10, 0, 0, 200, 200);

Because anti-aliasing is enabled by default, we might want to disable the smoothing to see clear pixels. You can toggle the checkbox to see the effect of the imageSmoothingEnabled property (which needs prefixes for different browsers).

var img = new Image();
img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg';
img.onload = function() {
  draw(this);
};

function draw(img) {
  var canvas = document.getElementById('canvas');
  var ctx = canvas.getContext('2d');
  ctx.drawImage(img, 0, 0);
  img.style.display = 'none';
  var zoomctx = document.getElementById('zoom').getContext('2d');
 
  var smoothbtn = document.getElementById('smoothbtn');
  var toggleSmoothing = function(event) {
    zoomctx.imageSmoothingEnabled = this.checked;
    zoomctx.mozImageSmoothingEnabled = this.checked;
    zoomctx.webkitImageSmoothingEnabled = this.checked;
    zoomctx.msImageSmoothingEnabled = this.checked;
  };
  smoothbtn.addEventListener('change', toggleSmoothing);

  var zoom = function(event) {
    var x = event.layerX;
    var y = event.layerY;
    zoomctx.drawImage(canvas,
                      Math.abs(x - 5),
                      Math.abs(y - 5),
                      10, 10,
                      0, 0,
                      200, 200);
  };

  canvas.addEventListener('mousemove', zoom);
}

儲存圖片

The HTMLCanvasElement provides a toDataURL() method, which is useful when saving images. It returns a data URI containing a representation of the image in the format specified by the type parameter (defaults to PNG). The returned image is in a resolution of 96 dpi.

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 URI from you canvas, you are able to use it as the source of any <image> or put it into a hyper link with a download attribute to save it to disc, for example.

You can also create a Blob from the canvas.

canvas.toBlob(callback, type, encoderOptions)
Creates a Blob object representing the image contained in the canvas.

延伸閱讀

文件標籤與貢獻者

 此頁面的貢獻者: pig3629
 最近更新: pig3629,