我刚刚做了一个小像素艺术应用程序,我遇到了一个问题,而我试图修复橡皮擦工具。当我试图用颜色'rgba擦除(0,0,0,0)'它什么也不做,所以我被迫用白色来解决。你们知道我可能做错了什么吗?(我也有另一个问题,所以我会问,当这一个回答)Here is the project下面是该项目的代码:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var pixelSize = 10;
var color = "#000000";
var eraser = false;
var fillStack = [];
var fillButton = document.getElementById("fill");
fillButton.addEventListener("click", function() {
processFillStack();
});
var downloadButton = document.getElementById("download");
downloadButton.addEventListener("click", function() {
var dataURL = canvas.toDataURL("image/png");
var link = document.createElement("a");
link.setAttribute("href", dataURL);
link.setAttribute("download", "pixel-art.png");
link.click();
});
var widthInput = document.getElementById("width");
var heightInput = document.getElementById("height");
var resizeButton = document.getElementById("resize");
resizeButton.addEventListener("click", function() {
canvas.width = widthInput.value;
canvas.height = heightInput.value;
var ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
document.getElementById("eraser").addEventListener("change", function() {
eraser = this.checked;
});
canvas.addEventListener("mousedown", function(e) {
if (!fillButton.pressed) {
var x = Math.floor(e.offsetX / pixelSize);
var y = Math.floor(e.offsetY / pixelSize);
if (eraser) {
ctx.fillStyle = "rgba(255,255,255,.1)";
} else {
ctx.fillStyle = color;
}
ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
}
});
canvas.addEventListener("mousemove", function(e) {
if (e.buttons == 1 && !fillButton.pressed) {
var x = Math.floor(e.offsetX / pixelSize);
var y = Math.floor(e.offsetY / pixelSize);
if (eraser) {
ctx.fillStyle = "rgba(255,255,255,.1)";
} else {
ctx.fillStyle = color;
}
ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
}
});
var imageInput = document.getElementById("image-input");
imageInput.addEventListener("change", function() {
var file = imageInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
};
img.src = e.target.result;
};
reader.readAsDataURL(file);
});
function floodFill(x, y, fillColor) {
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var pixelStack = [[x, y]];
var pixelPos, rowStart, rowEnd, up, down, i;
while (pixelStack.length) {
pixelPos = pixelStack.pop();
rowStart = pixelPos[1] * canvas.width * 4;
rowEnd = rowStart + canvas.width * 4;
up = false;
down = false;
for (i = rowStart; i < rowEnd; i += 4) {
if (matchColor(imageData.data, i, fillColor)) {
continue;
}
if (matchColor(imageData.data, i, getPixelColor(pixelPos[0], pixelPos[1]))) {
imageData.data[i] = fillColor[0];
imageData.data[i + 1] = fillColor[1];
imageData.data[i + 2] = fillColor[2];
imageData.data[i + 3] = fillColor[3];
if (pixelPos[1] > 0) {
if (matchColor(imageData.data, i - canvas.width * 4, getPixelColor(pixelPos[0], pixelPos[1] - 1))) {
if (!up) {
pixelStack.push([pixelPos[0], pixelPos[1] - 1]);
up = true;
}
} else if (up) {
up = false;
}
}
if (pixelPos[1] < canvas.height - 1) {
if (matchColor(imageData.data, i + canvas.width * 4, getPixelColor(pixelPos[0], pixelPos[1] + 1))) {
if (!down) {
pixelStack.push([pixelPos[0], pixelPos[1] + 1]);
down = true;
}
} else if (down) {
down = false;
}
}
if (pixelPos[0] > 0) {
if (matchColor(imageData.data, i - 4, getPixelColor(pixelPos[0] - 1, pixelPos[1]))) {
pixelStack.push([pixelPos[0] - 1, pixelPos[1]]);
}
}
if (pixelPos[0] < canvas.width - 1) {
if (matchColor(imageData.data, i + 4, getPixelColor(pixelPos[0] + 1, pixelPos[1]))) {
pixelStack.push([pixelPos[0] + 1, pixelPos[1]]);
}
}
}
}
}
ctx.putImageData(imageData, 0, 0);
}
function matchColor(data, i, color) {
return data[i] == color[0] && data[i + 1] == color[1] && data[i + 2] == color[2] && data[i + 3] == color[3];
}
function getPixelColor(x, y) {
var imageData = ctx.getImageData(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
var r = 0, g = 0, b = 0, a = 0;
for (var i = 0; i < imageData.data.length; i += 4) {
r += imageData.data[i];
g += imageData.data[i + 1];
b += imageData.data[i + 2];
a += imageData.data[i + 3];
}
var n = imageData.data.length / 4;
return [Math.round(r / n), Math.round(g / n), Math.round(b / n), Math.round(a / n)];
}
function processFillStack() {
var threads = 4; // number of threads to use
var stackSize = fillStack.length;
var chunkSize = Math.ceil(stackSize / threads);
var chunks = [];
for (var i = 0; i < threads; i++) {
chunks.push(fillStack.splice(0, chunkSize));
}
for (var i = 0; i < threads; i++) {
(function(chunk) {
setTimeout(function() {
for (var j = 0; j < chunk.length; j++) {
var x = chunk[j][0];
var y = chunk[j][1];
var color = chunk[j][2];
floodFill(x, y, color);
}
}, 0);
})(chunks[i]);
}
}
canvas {
background-color: white;
border: 1px solid black;
}
#color-picker {
width: 50px;
height: 50px;
/* position: absolute;
top: 10px;
left: 10px; */
}
#download {
display: block;
margin: 10px auto;
padding: 10px;
background-color: black;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
label, input, button {
display: block;
margin: 10px 0;
}
label {
font-weight: bold;
}
input[type="number"] {
width: 50px;
}
button {
padding: 10px;
background-color: black;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
#eraser {
display: none;
}
#eraser + label:before {
content: "";
display: inline-block;
width: 20px;
height: 20px;
background-color: white;
border: 1px solid black;
margin-right: 5px;
}
#eraser:checked + label:before {
background-color: black;
}
<canvas id="canvas"></canvas>
<input type="color" id="color-picker">
<input type="checkbox" id="eraser">
<label for="eraser">Eraser</label>
<button id="download">Download</button>
<label for="width">Width:</label>
<input type="number" id="width" value="20">
<label for="height">Height:</label>
<input type="number" id="height" value="20">
<button id="resize">Resize</button>
<button id="fill">Fill</button>
Import Image:
<input type="file" id="image-input">
我试图将彩色像素转换为完全透明的像素,但我最终得到的颜色是白色或什么都没有。
2条答案
按热度按时间cnwbcb6i1#
就像其他人说的那样,
fillRect
会在已经存在的东西上作画,而不是替换。这让你可以像在真实的画布上一样混合透明的颜色。您可以使用
clearRect
来删除。将
mousedown
和mousemove
中的事件侦听器更改为:字符串
关于mozilla docs:
Canvas 2D API的
CanvasRenderingContext2D.clearRect()
方法通过将矩形区域中的像素设置为透明黑色来擦除这些像素。演示:
yrdbyhpb2#
正如我在这里看到的,当你模拟橡皮擦效果时,你使用了一种半透明的颜色
rgba(255,255,255,.1)
。我认为这种半透明的颜色与画布的白色背景混合在一起,所以它会给你一个白色区域。更好的方法是,在这里使用
globalCompositeOperation
,值为destination-out
,这样新的绘图只会在现有绘图透明的区域中绘制。在
mousedown
和mousemove
中,当橡皮擦工具处于活动状态时,将globalCompositeOperation
属性设置为destination-out
。在下面的代码中,
globalCompositeOperation
在每次绘制操作后设置为source-over
,以便正常绘制后续图形;字符串
然后,在显示最终图像时,您需要使用
globalCompositeOperation
属性将原始画布绘制到其自身上,并设置为destination-out
。这将从原始绘图中删除删除的区域;型
这应该允许您使用任何颜色擦除,包括
rgba(0, 0, 0, 0)
,并且仍然可以看到擦除的区域是透明的。