html5画布中单个像素上的clearRect()实际上并未将alpha设置为0

时间:2015-10-22 01:32:32

标签: canvas html5-canvas

我在html5画布中手动绘制单个像素。我只使用纯黑色和纯白色。只是简化一下:

var canvas = document.querySelector(".main-canvas");
var ctx = canvas.getContext('2d');
ctx.imageSmoothingEnabled = false;

var isNonNegativeInteger = function(val) {
  return Number.isFinite(val) && val % 1 === 0 && val >= 0;
};

var paintPixel = function(x, y) {
    if (!isNonNegativeInteger(x) ||
        !isNonNegativeInteger(y) ) {
        debugger;       
    }
    ctx.fillRect( x, y, 1, 1 );
};

var clearPixel = function( x, y ) {
    if (!isNonNegativeInteger(x) ||
        !isNonNegativeInteger(y) ) {
        debugger;       
    }
    ctx.clearRect( x, y, 1, 1 );
};

我只在x和y坐标中传递整数。是的,我绝对肯定,我已经进行了测试。

我不是在操纵RGB。所有像素都保持黑色。我只是在操纵alpha。我所发现的是,经过大量的绘画和清理,经过大量的来回,有一个微弱的视觉“重影”,其中被fillRect()设置为完全不透明的黑色像素是<{1}}被调用时实际上没有将alpha重置为零。

我知道这一点,因为当我在受影响的像素邻域中调用clearRect()时,我看到像素数据alpha值中出现了低但非零的alpha值(3,5或12等)。这是......疯狂的制作。有趣的是,我也看到了黑色像素的一些非255 alpha值,这些值也存在问题,但对“脏”白人的视觉攻击性较小。

这些是大像素网格,每帧有数千个绘制调用。所以我不愿意使用ctx.getImageData()getImageData()来手动设置alpha,因为它们很慢。问题在于putImageData()没有按照它所说的那样做。

非常感谢任何建议。

1 个答案:

答案 0 :(得分:0)

这真的很奇怪,我能想到的唯一原因是你的x和y坐标不是int。 在浮点位置绘制确实会在clearRect上创建一个抗锯齿工件:

var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
ctx.textBaseline = "middle"
var paintPixel = function(x, y) {
  ctx.fillRect(x, y, 1, 1);
};
var clearPixel = function(x, y) {
  ctx.clearRect(x, y, 1, 1);
};
var i = 0;
for (i = 0; i < 25; i += .1) {
  paintPixel(i, 10);
  clearPixel(i, 10);
}
ctx.fillText('float', 30, 10)

for (i = 0; i < 25; i++) {
  paintPixel(i, 30);
  clearPixel(i, 30);
}
ctx.fillText('int', 30, 30)
// an other solution could have been to use globalCompositeOperation
var gCOClear = function(x, y) {
  ctx.globalCompositeOperation = 'destination-out';
  ctx.fillRect(x, y, 1, 1);
  ctx.globalCompositeOperation = 'source-over';
}
for (i = 0; i < 25; i += .1) {
  paintPixel(i, 50);
  gCOClear(i, 50);
}
ctx.fillText('gCO float', 30, 50)
for (i = 0; i < 25; i++) {
  paintPixel(i, 70);
  gCOClear(i, 70);
}
ctx.fillText('gCO int', 30, 70)

所以解决方案是:要么在绘制前围绕坐标,要么比你绘制的要小一些。

但正如您指定的那样,您绝对肯定“只能将整数作为x和y坐标传递”,这可能不是您的问题......

另外,请注意,ctx.imageSmoothingEnabled对绘制方法没有影响,例如fillRect()clearRect()