[pixlate] 用 canvas 转像素画

2019-08-04 20:47:11 浏览数 (1)

几周前看到这个像素猫的效果,这个版本的实现原理是 box-shadow,我想到用 grid 也可以实现一遍。接着发散到了“如何将任意图片像素化”上。

一开始的思路是如果还是用 grid 或者 box-shadow 的方式,需要遍历图片上的每个像素,拿到坐标和像素值,这样就需要用到 canvas。既然已经用到了 canvas… 其实就不用这么麻烦了,参考了 8-bit 的实现方法,可以用 drawImage 方法,将缩小的图片放大,通过 ctx.imageSmoothing = false 禁用掉浏览器器对图片平滑处理。

核心代码非常短:

代码语言:javascript复制
var eightBit = function (canvas, image, scale) {
    scale *= 0.01;

    canvas.width = image.width;
    canvas.height = image.height;

		// 将图片缩小
    var scaledW = canvas.width * scale;
    var scaledH = canvas.height * scale;

    var ctx = canvas.getContext('2d');
  
		// 禁止浏览器的平滑处理
    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;

    ctx.drawImage(image, 0, 0, scaledW, scaledH);
		// 但依然要画到和原图尺寸一样的画布上
    ctx.drawImage(canvas, 0, 0, scaledW, scaledH, 0, 0, canvas.width, canvas.height);
  };

背后的原理是将小尺寸的图片放到大尺寸的画布上,自然会“糊”,就像我们把 1x 的图片放在 Retina 屏幕上看一样。两者尺寸差别越大,模糊会越厉害,最极端的情况能到类似提取主题色那样的效果。因为要先缩小再真正画到画布上,所以先 draw image,再 draw canvas。从前我用 drawImage 基本画的都是媒体对象,这次画的是个 canvas 对象,对这个用法还蛮新奇的。根据 MDN,这个函数的第一个参数可以是任何的 canvas 图像源:

绘制到上下文的元素。允许任何的 canvas 图像源(CanvasImageSource),例如:CSSImageValueHTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementImageBitmap 或者OffscreenCanvas

如果不加上禁止平滑处理的话,出来的效果就会是这样,emm 谁把我的眼镜摘了:

在 CanvasRenderingContext2D.imageSmoothingEnabled 的文档里也说得很明白,如果开发者需要像素化的视觉效果,就需要禁用这个特性:

以缩放画布为例,这个属性对像素为主的游戏很有用。默认的改变大小的算法会造成图片模糊并且破坏图片原有的像素。 如果那样的话,设置属性值为false。 参见 CSS image-rendering 属性。

顺着这个属性,我爬到了 image-rendering 的文档页 — 哦!原来 image 也可以拿来这么处理啊。

0 人点赞