需求:
需要改变图片中某一物体的颜色,该物体是纯色;
鼠标点击哪个物体,哪个物体的颜色变为指定的颜色,利用canvas实现。
演示案例
代码Demo
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Color Replacement</title>
<style>
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<input type="color" id="newColor" name="newColor" />
<canvas id="myCanvas" width="375" height="397"></canvas>
<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });
const img = new Image();
img.src =
'data:image/png;base64,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';
img.onload = function () {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
// 替换颜色
function replaceColor(clickX, clickY, newColor) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// debugger;
// 点击的颜色值
const index = parseInt((clickY * canvas.width + clickX) * 4);
const oldColor = [data[index], data[index + 1], data[index + 2]];
// 将颜色转成rgb
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(newColor.slice(1));
const newRGB = result ? [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)] : null;
if (!newRGB) return;
floodFill(imageData, clickX, clickY, oldColor, newRGB);
ctx.putImageData(imageData, 0, 0);
}
// 填充颜色
function floodFill(imageData, x, y, oldColor, newColor) {
let stack = [[x, y]];
const data = imageData.data;
let includesPoints = [];
while (stack.length) {
let point = stack.pop();
let index = parseInt((point[1] * canvas.width + point[0]) * 4);
if (data[index] === oldColor[0] && data[index + 1] === oldColor[1] && data[index + 2] === oldColor[2]) {
data[index] = newColor[0];
data[index + 1] = newColor[1];
data[index + 2] = newColor[2];
data[index + 3] = 255;
[
[0, -1],
[1, 0],
[0, 1],
[-1, 0],
].forEach(([dx, dy]) => {
let newX = point[0] + dx;
let newY = point[1] + dy;
const pointToString = newX + ',' + newY;
if (newX >= 0 && newX < canvas.width && newY >= 0 && newY < canvas.height) {
stack.push([newX, newY]);
}
});
}
}
}
canvas.addEventListener('click', function (event) {
const rect = canvas.getBoundingClientRect();
const clickX = event.clientX - rect.left;
const clickY = event.clientY - rect.top;
// debugger;
let newColor = document.getElementById('newColor').value;
replaceColor(Math.round(clickX), Math.round(clickY), newColor);
});
</script>
</body>
</html>
后续
确定点击点四周相同颜色值的算法有待优化