如何添加透明像素而不只添加白色像素?

问题描述 投票:0回答:1

我刚刚制作了一个小像素艺术应用程序,在尝试修复橡皮擦工具时遇到了问题。当我尝试用颜色“rgba(0, 0, 0, 0)”擦除时,它什么也没做,所以我被迫选择白色。你们知道我可能做错了什么吗? (我还有另一个问题,所以当这个问题得到解答时我会询问这个问题)这是项目下面是该项目的代码:

HTML:

<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">

CSS:

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;
}

JavaScript:

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]);
    }
}


我试图将彩色像素转换为完全透明的像素,但最终得到的是白色或什么都没有。

javascript html css graphics transparent
1个回答
0
投票

正如我在这里看到的,当你模拟橡皮擦效果时。您使用的是半透明颜色,即

rgba(255,255,255,.1)
。我认为这种半透明的颜色与画布的白色背景混合,因此会产生白色区域。

更好的是,您在此处使用

globalCompositeOperation
和值
destination-out
,因此新绘图仅在现有绘图透明的区域中绘制。

当橡皮擦工具处于活动状态时,在

mousedown
mousemove
中,将
globalCompositeOperation
属性设置为
destination-out

下面的代码中,每次绘制操作后将

globalCompositeOperation
设置为
source-over
,以便后续的绘图能够正常绘制;

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.globalCompositeOperation = "destination-out";
          ctx.fillStyle = "rgba(0,0,0,1)";
          ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
      } else {
          ctx.fillStyle = color;
          ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
      }
      ctx.globalCompositeOperation = "source-over";
  }
});

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.globalCompositeOperation = "destination-out";
          ctx.fillStyle = "rgba(0,0,0,1)";
          ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
      } else {
          ctx.fillStyle = color;
          ctx.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize);
      }
      ctx.globalCompositeOperation = "source-over";
  }
});

然后,当显示最终图像时,您需要使用

globalCompositeOperation
属性将原始画布绘制到其自身上,并将其设置为
destination-out
。这将从原始绘图中删除擦除的区域;

function displayFinalImage() {
  ctx.globalCompositeOperation = "destination-out";
  ctx.drawImage(canvas, 0, 0);
  ctx.globalCompositeOperation = "source-over";
}

© www.soinside.com 2019 - 2024. All rights reserved.