canvas的drawImage, getImageData 和 putImageData扫盲

4,244 阅读6分钟

前言

最近自己想做一个UI自动化测试工具,因为自己的页面第一页面少,第二适配多,根据这个场景,那么使用两张图片对比的测试就非常适合我这个场景,但是自己一直对canvas的不是太了解,自学过很多次,但是因为用的不多所以经常忘记,那么这次我们不学全部的,用到哪个api,就学哪个api

drawImage

drawImage的参数

drawImage() 方法用于在 Canvas 上绘制图像。它可以接受不同的参数组合,以实现不同的绘制效果。以下是 drawImage() 方法的常见参数组合:

  1. drawImage(image, dx, dy) :

    • image: 要绘制的图像对象,可以是 ImageCanvasVideo 对象。
    • dx: 目标画布上绘制的图像左上角的 x 坐标。
    • dy: 目标画布上绘制的图像左上角的 y 坐标。
  2. drawImage(image, dx, dy, dWidth, dHeight) :

    • image: 要绘制的图像对象,可以是 ImageCanvasVideo 对象。
    • dx: 目标画布上绘制的图像左上角的 x 坐标。
    • dy: 目标画布上绘制的图像左上角的 y 坐标。
    • dWidth: 目标画布上绘制的图像的宽度。
    • dHeight: 目标画布上绘制的图像的高度。
  3. drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) :

    • image: 要绘制的图像对象,可以是 ImageCanvasVideo 对象。
    • sx: 源图像的左上角在源图像中的 x 坐标。
    • sy: 源图像的左上角在源图像中的 y 坐标。
    • sWidth: 源图像中要绘制的部分的宽度。
    • sHeight: 源图像中要绘制的部分的高度。
    • dx: 目标画布上绘制的图像左上角的 x 坐标。
    • dy: 目标画布上绘制的图像左上角的 y 坐标。
    • dWidth: 目标画布上绘制的图像的宽度。
    • dHeight: 目标画布上绘制的图像的高度。

drawImage的应用场景都有哪些呢?

  1. 绘制图像: 最常见的用途是将图像绘制到 Canvas 上,例如显示用户上传的图片、绘制图标、展示游戏素材等。
  2. 图像裁剪: 可以使用 drawImage() 方法中的源图像参数来指定要裁剪的图像区域,从而实现对图像的裁剪效果。
  3. 图像缩放: 通过调整目标绘制区域的宽度和高度,可以实现对图像的缩放效果,无论是按比例缩放还是非等比例缩放。
  4. 图像平铺: 可以使用 drawImage() 方法来平铺图像,即将一个小的图像重复绘制到整个 Canvas 上,创建背景纹理或平铺效果。
  5. 图像合成: drawImage() 方法支持多个图像的叠加绘制,可以通过多次调用该方法来实现图像的合成效果,例如图层叠加、蒙版效果等。
  6. 图像滤镜: 在绘制图像之前,可以通过 Canvas 提供的绘图操作和像素处理技术来实现图像滤镜效果,例如亮度调节、对比度调整、颜色变换等。
  7. 视频处理: 除了图像,drawImage() 方法也可以用于在 Canvas 上绘制视频帧,实现视频的播放和处理。

应用示例

const image1 = './img/1.jpeg';
const canvas = document.querySelector('#canvas');
// 如果想使用canvas的api,那么必须获取context对象,相当于一个接口
const ctx = canvas.getContext("2d");
// 等价于document.createElement("img").
const imageObj = new Image();
// 图片加载好以后开始进行操作
imageObj.onload = function(){
  ctx.drawImage(imageObj, 0, 0);
}
imageObj.src = image1;

image.png

咱们的美女图立马显示在电脑上

有人可能感叹了,怎么绘制一个图片这么麻烦,又要new Image(),又要src,又要onload的,这怎么记得住呢?

首先说一下为什么要new Image(), 因为drawImage的第一个参数必须是以下几种

image.png

所以这个没有办法

getImageData

getImageData参数

  1. x: 指定矩形区域左上角的 x 坐标,即矩形区域的左边界的水平位置。
  2. y: 指定矩形区域左上角的 y 坐标,即矩形区域的上边界的垂直位置。
  3. width: 指定矩形区域的宽度。
  4. height: 指定矩形区域的高度。(此处注意是区域的y轴,而是区域的高度)

getImageData是干什么的呢? 从字面上理解就是获取指定宽高的ImageData信息的,那么什么是imageData呢?

我们先来看一下imageData都返回哪些信息

image.png

  • width:图像区域的宽度。
  • height:图像区域的高度。
  • data:一个 Uint8ClampedArray 类型的数组,包含了每个像素的颜色信息。该数组按照从左到右、从上到下的顺序存储每个像素的 RGBA(红、绿、蓝、透明度)值。

这个data包含了每个像素的颜色信息,像不像颜色选择器的返回值呢,因为每个像素其实就是由这几个值构成的

image.png

显示器上的1像素是什么样子的呢

image.png

这不就是我们常写的rgb(255,255,255), 如果都不发光那么就是黑色rgb(0,0,0)

putImageData

putImageData是干什么用的呢?

从字面理解就是把imageData重新渲染到canvas上。也就是我们在通过getImageData获取到imageData以后,然后进行处理,再通过putImageData绘制到canvas上,接下来我们就以一个取反色的例子来演示一下效果

const dealImageData = (imageData) => {
  let data = imageData.data;
  for(let i=0;i<data.length;i+=4){
    // R 红色通道去反色
    data[i] = data[i]^255;
    // G 绿色通道去反色
    data[i+1] = data[i+1]^255;
    // B 绿色通道去反色
    data[i+2] = data[i+2]^255;
    // A 透明通道一般不取反色,因为你的图片有可能都是255,也就是不透明的,你取了反色,就成了全透明,什么都看不到了
    // data[i+3] = data[i+3]^255;
  }
  return imageData;
}

const image1 = './img/1.jpeg';
const canvas = document.querySelector('#canvas');
// 如果想使用canvas的api,那么必须获取context对象,相当于一个接口
const ctx = canvas.getContext("2d");
// 等价于document.createElement("img").
const imageObj = new Image();
// 图片加载好以后开始进行操作
imageObj.onload = function(){
  ctx.drawImage(imageObj, 0, 0);
  const imageData = ctx.getImageData(0, 0, imageObj.width, imageObj.height);
  const newImageData = dealImageData(imageData);
  ctx.clearRect(0, 0, imageObj.width, imageObj.height);
  ctx.putImageData(newImageData, 0, 0);
}
imageObj.src = image1;

上面的代码一定要注意,不是什么都可以取反色的,比如透明度就最好不要取反色,因为你的图片有可能都是255,也就是不透明的,你取了反色,就成了全透明,什么都看不到了

image.png

现在再看一下我们图片的效果,哦,好诡异,所以技术不能乱用哦,小心吓到自己

参考