克服鼠标事件的画布线上的抗锯齿

时间:2017-10-19 22:35:45

标签: javascript html html5 canvas

我面临一个明显已知的问题,HTML画布中的行不能禁用抗锯齿(例如this question提到这只能用于使用context.imageSmoothingEnabled= false的图像,而不能用于行。< / p>

我想知道是否有任何更新,如果有可能绘制一个清晰(即使“像素化”)线?所有我需要的是例如当使用普通的“铅笔”工具(参见下面的左侧笔划)时,MS Paint可以实现,而不是更平滑的“笔刷”类型(参见右侧笔划)。

crisp pixel line in paint

目前,我的HTML画布中的行看起来更像是“画笔”类型。 blurry canvas lines

这是一个问题,因为我正在尝试设置一个鼠标事件,它给出了线条的确切颜色,但是在实际颜色周围使用抗锯齿,它会在光标到达之前返回一些不需要的颜色。这条线的中心部分。

有人可以确认在画布上真的没有办法强迫“铅笔”般的笔画吗?如果是这样,可能有一个简单的解决方法,例如“切断”中风的边缘?

1 个答案:

答案 0 :(得分:2)

您可以使用SVG滤镜在画布上绘制这样的像素化形状,该滤镜可以移除形状边缘的Alpha值。 (但是SVG过滤器有点重。)

&#13;
&#13;
const ctx = canvas.getContext("2d");

//normal line(antialiased)
ctx.moveTo(20,20); ctx.lineTo(180,20);
ctx.stroke();

//set "crisp edge" filter
ctx.filter = "url(#crisp)";
//crisp line
ctx.beginPath();ctx.moveTo(20,40); ctx.lineTo(180,40);
ctx.moveTo(20, 50); ctx.lineTo(180, 70);
//crisp circle
ctx.moveTo(150, 130); ctx.arc(100, 130, 50, 0, Math.PI*2);
ctx.stroke();
&#13;
<canvas id="canvas" width="200" height="200"></canvas>
<svg style="visibility:hidden;width:0;height:0;">
  <defs>
    <!--SVG filter to remove alpha-->
    <filter id="crisp">
      <feComponentTransfer>
        <feFuncA type="discrete" tableValues="0,1"></feFuncA>
      </feComponentTransfer>
    </filter>
  </defs>
</svg>
&#13;
&#13;
&#13;

注意:但Chrome使用SVG过滤器会在输出图像上引发安全性错误。

如果您需要自己实现此类过滤器,ImageData对象将对您有所帮助。这没有安全错误风险。

但手工过滤器太重,无法应用于每个活动图纸。你应该仔细考虑申请时间。

&#13;
&#13;
const ctx = canvas.getContext("2d");

//temporary canvas to removeAlpha
const tmp = document.createElement("canvas");
[tmp.width, tmp.height] = [canvas.width, canvas.height];
const tctx = tmp.getContext("2d");

//normal line(antialiased)
ctx.moveTo(20,20); ctx.lineTo(180,20);
ctx.stroke();

//crisp line
tctx.beginPath(); tctx.moveTo(20,40); tctx.lineTo(180,40);
tctx.moveTo(20, 50); tctx.lineTo(180, 70);
removeAlpha();

//crisp circle
tctx.moveTo(150, 130); tctx.arc(100, 130, 50, 0, Math.PI*2);
tctx.stroke();
removeAlpha();

//remove alpha on tmp canvas and draw it to main canvas.
function removeAlpha(){
  const threshold = 128;//you can change the value
  const id = tctx.getImageData(0, 0, tmp.width, tmp.height);
  const data = id.data;//pixel data array
  //remove alpha values pixel by pixel.
  for(let i = 0, len = canvas.width * canvas.height; i<len; i++){
    const apos = i * 4 + 3;//alpha data position
    const a = data[apos];
    data[apos] = a > threshold ? 255 : 0;
  }
  tctx.putImageData(id, 0, 0);
  ctx.drawImage(tmp, 0, 0);
  tctx.clearRect(0, 0, tmp.width, tmp.height);
}
&#13;
<canvas id="canvas" width="200" height="200"></canvas>
&#13;
&#13;
&#13;