几周前看到这个像素猫的效果,这个版本的实现原理是 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
),例如:CSSImageValue
,HTMLImageElement
,SVGImageElement
,HTMLVideoElement
,HTMLCanvasElement
,ImageBitmap
或者OffscreenCanvas
。
如果不加上禁止平滑处理的话,出来的效果就会是这样,emm 谁把我的眼镜摘了:
在 CanvasRenderingContext2D.imageSmoothingEnabled 的文档里也说得很明白,如果开发者需要像素化的视觉效果,就需要禁用这个特性:
以缩放画布为例,这个属性对像素为主的游戏很有用。默认的改变大小的算法会造成图片模糊并且破坏图片原有的像素。 如果那样的话,设置属性值为false。 参见 CSS
image-rendering
属性。
顺着这个属性,我爬到了 image-rendering 的文档页 — 哦!原来 image 也可以拿来这么处理啊。