使用canvas读取像素点和绘制简单形状两个功能点,几十行代码就可以简单实现乐高风格图片转化
思路一共两步
- 获取图片像素马赛克化
- 马赛克块填充为乐高块图形
马赛克化图片
1. 基础工作,canvas显示原始图片
const canvas = document.getElementById("mosaic");
const ctx = canvas.getContext("2d");
const image = new Image();
image.src = "./Test.png";
image.onload = function () {
if (!ctx) {
return null;
}
canvas.width = image.width;
canvas.height = image.height;
draw();
};
const draw = () => {
// 绘制原始图片
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
}
正常展示如下
2. 将原始图片马赛克化
思路很简单,首先设置马赛克块的size
,根据size
计算x和y轴马赛克块像素 参考canvas像素操作获取该块rgba信息,根据颜色信息填充该(size * size)
马赛克块
const size = 20;
const draw = () => {
// 绘制原始图片
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
// 获取原始图片信息
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// 生成 i * j 的马赛克块
for (let i = 0; i < Math.floor(canvas.width / size); i++) {
for (let j = 0; j < Math.floor(canvas.height / size); j++) {
// 从马赛克块中随机抽出一个像素点信息
let rgba = getPxInfo(
imageData,
i * size + Math.floor(Math.random() * size),
j * size + Math.floor(Math.random() * size)
);
// 填充马赛克块
fillMosaicRect(ctx, rgba, i * size, j * size, size, size);
}
}
};
// 获取该像素RGBA信息
const getPxInfo = (imgData, x, y) => {
const color = [];
const data = imgData.data;
const w = imgData.width;
color[0] = data[(y * w + x) * 4];
color[1] = data[(y * w + x) * 4 + 1];
color[2] = data[(y * w + x) * 4 + 2];
color[3] = data[(y * w + x) * 4 + 3];
return color;
};
// 填充该块颜色
const fillMosaicRect = (ctx, rgba, x, y, w, h) => {
ctx.fillStyle = `rgb(${rgba.join(",")})`;
ctx.fillRect(x, y, w, h);
};
此时效果就是正常的马赛克
填充乐高块图形
简单来说,只需要修改填充该块颜色函数,除了填充颜色外,需要绘制一个乐高风格的圆形按钮,为了让方块和圆按钮都具有一定质感,最简单的方法就是加上阴影效果
const fillMosaicRect = (ctx, rgba, x, y, w, h) => {
// 阴影效果
ctx.shadowBlur = w / 4;
ctx.shadowColor = `rgb(${rgba.map((color) => color * 0.6).join(",")})`;
// 背景色
ctx.fillStyle = `rgb(${rgba.join(",")})`;
ctx.fillRect(x, y, w, h);
// 乐高圆形按钮
const circle = new Path2D();
circle.arc(x + w / 2, y + h / 2, w / 3, 0, 2 * Math.PI);
ctx.fill(circle);
};
大功告成
更多细节
虽然已经完成了乐高块的渲染,但实际上来说,我们为了乐高的效果可以增加更多细节,比如说浮雕效果(或者还可以自己添加Lego水印/反光效果/阴影角度...)
添加浮雕效果
const fillMosaicRect = (ctx, rgba, x, y, w, h) => {
// 阴影效果
ctx.shadowBlur = w / 4;
ctx.shadowColor = `rgb(${rgba.map((color) => color * 0.6).join(",")})`;
// 背景色
ctx.fillStyle = `rgb(${rgba.join(",")})`;
ctx.fillRect(x, y, w, h);
// 浮雕背景色
const lineargradient = ctx.createLinearGradient(x, y, x, y + h);
lineargradient.addColorStop(0, `#ffffff`);
lineargradient.addColorStop(0.5, `rgb(${rgba.join(",")})`);
lineargradient.addColorStop(1, `#000000`);
ctx.fillStyle = lineargradient;
const circleFore = new Path2D();
circleFore.arc(x + w / 2, y + h / 2, w / 3, 0, 2 * Math.PI);
ctx.fill(circleFore);
// 浮雕前景色
ctx.fillStyle = `rgb(${rgba.join(",")})`;
ctx.shadowBlur = 0;
ctx.shadowColor = "";
const circleBack = new Path2D();
circleBack.arc(x + w / 2, y + h / 2, (w / 3) * 0.8, 0, 2 * Math.PI);
ctx.fill(circleBack);
}
最终实现
实际的功能演示中增加了一些配置项,体验起来趣味满多的