Canvas 10
像素操作
我们可以通过ImageData对像操纵像素数据,直接读取和写入像素数据。
ImageData对象
该对象存储着canvas对象真实的像素数据,包含下列这些只读属性:
- width —— 图像的宽度 像素为单位
- height —— 图像的高度 像素为单位
- data —— 一个Unit8ClampedArray类型的一维数组,按顺序包含每个像素的位置(RGBA) 范围是0-255
我们可以通过data属性访问到原始像素数据,每个四个字节表示一个像素
对应RGBA颜色通道,每个像素由四个字节组成,每个颜色通道使用一个字节表示(0-255)
红色通道在对应像素向量中索引为0
像素数据的对应数据是从左到右然后从上至下。
Uint8ClampedArray包含宽度高度4的Unit8ClampedArray类型字节数据
我要读取50行200列的像素的蓝色通道值
const blueComponent = imageData.data[50 * (imageData.width * 4) + 200 * 4 + 2];
表示获取某个像素位置的颜色值
const getColorIndicesForCoord = (x, y, width) => {
const red = y * (width * 4) + x * 4;
return [red, red + 1, red + 2, red + 3];
};
读取Unit8ClampedArray.length属性来获取像素数组的大小(字节为单位)
var numBytes = imageData.data.length;
创建一个ImageData对像
- createImageData()
const myImageData = ctx.createImageData(width, height);
创建一个制定尺寸的ImageData对像,所有的像素都是透明黑色的。 你可以传入另一个ImageData对像实例创建一个相同尺寸的ImageData对像,一个新的ImageData实例。
const myImageData = ctx.createImageData(anotherImageData);
从canva画布上获取像素数据(ImageData)
- getImageData() 获取一份关于canvas像素数据的对象
const myImageData = ctx.getImageData(left, top, width, height);
任何在画布以外的元素都会被返回成一个透明黑的 ImageData 对象。
颜色选择器
根据鼠标位置抓取对应位置在canvas上的颜色像素 示例
var img = new Image();
img.crossOrigin = "anonymous";
img.src = "./assets/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 hoveredColor = document.getElementById("hovered-color");
var selectedColor = document.getElementById("selected-color");
function pick(event, destination) {
var x = event.layerX;
var y = event.layerY;
var pixel = ctx.getImageData(x, y, 1, 1);
var data = pixel.data;
const rgba = `rgba(${data[0]}, ${data[1]}, ${data[2]}, ${data[3] / 255})`;
destination.style.background = rgba;
destination.textContent = rgba;
return rgba;
}
canvas.addEventListener("mousemove", function (event) {
pick(event, hoveredColor);
});
canvas.addEventListener("click", function (event) {
pick(event, selectedColor);
});
在canvas中写入像素数据
- putImageData()
ctx.putImageData(myImageData, dx, dy);
dx和dy参数表示在canvas绘制像素数据起始位置。
图片的灰色和反相颜色
我们将遍历图片所有的像素修改颜色值然后使用putImageData重新放回画布中。
- 反相颜色就是用255减去每个颜色通道值。
- 灰度的效果设置每个颜色通道的值为的红色、绿色和蓝色的平均值。
var img = new Image();
img.crossOrigin = "anonymous";
img.src = "./assets/rhino.jpg";
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
var original = function () {
ctx.drawImage(img, 0, 0);
};
var invert = function () {
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
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 () {
ctx.drawImage(img, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
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);
};
const inputs = document.querySelectorAll("[name=color]");
for (const input of inputs) {
input.addEventListener("change", function (evt) {
switch (evt.target.value) {
case "inverted":
return invert();
case "grayscale":
return grayscale();
default:
return original();
}
});
}
缩放和抗锯齿
- imageSmoothingEnabled 属性使得图像放大时显示平滑 示例,鼠标位置裁剪出距左上5像素,距离右下5像素的图片,然后复制到另一个画布调整我们想要的大小。
zoomctx.drawImage(
canvas,
Math.abs(x - 5),
Math.abs(y - 5),
10,
10,
0,
0,
200,
200,
);
缩放示例
imageSmoothingEnabled的反锯齿效果是默认开启的。
var img = new Image();
img.src = "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);
}
保存图片(HTMLCanvasElement)
- toDataURL()方法,用于将canvas上像素保存成图片。(图片分辨率是 96 dpi)
- canvas.toDataURL(‘image/png’) 默认创建一个PNG类型的图片
- canvas.toDataURL(‘image/jpeg’, quality) 可以修改成其他类型,同时设置图片质量。
- 生成的路径可以使用a标签保存本地或使用img标签访问展示。
- canvas.toBlob(callback, type, encoderOptions) —— 根据canvas像素创建一个表示图片的blob对像。
写在最后
未完待续…
希望大家好好生活,健康快乐。