Javascript 如何使线条的边缘像素保持半透明?

Javascript 如何使线条的边缘像素保持半透明?,javascript,html,canvas,transparency,Javascript,Html,Canvas,Transparency,我正在使用一个HTML画布,其像素宽度和高度放大了32倍。然而,当我在上面画线时,我注意到线的边缘像素是半透明的(完全是半透明的)。有没有办法阻止这一切 在中,红线是从一点到另一点的单线。我希望所有的积木都是黑色或#FF0000红色 注意:我已经在使用canvas.translate()正确对齐像素,并且正在使用中的解决方案在离散块中渲染扩展的像素。问题背景 Canvas使用抗锯齿使图形看起来更平滑,这就是为什么它会到处填充半透明像素的原因(请参见了解其工作原理) 平滑(也称为插值)可以关闭,但

我正在使用一个HTML画布,其像素宽度和高度放大了32倍。然而,当我在上面画线时,我注意到线的边缘像素是半透明的(完全是半透明的)。有没有办法阻止这一切

在中,红线是从一点到另一点的单线。我希望所有的积木都是黑色或#FF0000红色

注意:我已经在使用canvas.translate()正确对齐像素,并且正在使用中的解决方案在离散块中渲染扩展的像素。

问题背景 Canvas使用抗锯齿使图形看起来更平滑,这就是为什么它会到处填充半透明像素的原因(请参见了解其工作原理)

平滑(也称为插值)可以关闭,但仅适用于图像(
ctx.imageSmoothingEnabled=false,顾名思义)

解决 为此,需要实现“线渲染器”。然而,典型的线条算法只支持宽度为1像素的线条。这包括Bresenham和EFLA(极快直线算法),后者比Bresenham快

对于大于1像素的线,需要找到切线角度,然后沿主线渲染每个线段

我提供了以下两种实现,我在一定程度上对它们进行了优化。它们都不需要访问位图本身,只需提供上下文即可

唯一需要记住的是使用
fillStyle
(和
fill()
)而不是
strokeStyle
(和
stroke()
)来设置其颜色。可以在填充之前生成几行,这通常比填充每个线段快,前提是它们使用相同的颜色

(可选)您可以使用图像数据并直接在那里设置像素,但如果您使用图像,则速度较慢且需要CORS(如果首选,请使用带有Uint32视图的位图。还有一些特殊技巧可以加速此方法,但此处不讨论)

EFLA(极快直线算法) 此算法适用于要绘制连续多边形线的位置,即未设置最后一点。但是在下面的实现中,我们手动设置它,以便它可以用于单个线段

请访问上面的链接站点以获得更深入的解释(以及许可证)

只需确保输入值是整数值:

function lineEFLA(ctx, x1, y1, x2, y2) {

    var dlt, mul, yl = false, i,
        sl = y2 - y1,
        ll = x2 - x1,
        lls = ll >> 31,
        sls = sl >> 31;

    if ((sl ^ sls) - sls > (ll ^ lls) - lls) {
        sl ^= ll;
        ll ^= sl;
        sl ^= ll;
        yl = true;
    }

    dlt = ll < 0 ? -1 : 1;
    mul = (ll === 0) ? sl : sl / ll;

    if (yl) {
        x1 += 0.5;  // preset for rounding
        for (i = 0; i !== ll; i += dlt) setPixel((x1 + i * mul)|0, y1 + i);
    }
    else {
        y1 += 0.5;
        for (i = 0; i !== ll; i += dlt) setPixel(x1 + i, (y1 + i * mul)|0);
    }
    setPixel(x2, y2);   // sets last pixel

    function setPixel(x, y) {ctx.rect(x, y, 1, 1)}
}
功能线FLA(ctx、x1、y1、x2、y2){
var dlt,mul,yl=假,i,
sl=y2-y1,
ll=x2-x1,
lls=ll>>31,
sls=sl>>31;
如果((sl^sls)-sls>(ll^lls)-lls){
sl^=ll;
ll^=sl;
sl^=ll;
yl=真;
}
dlt=ll<0?-1:1;
mul=(ll==0)?sl:sl/ll;
if(yl){
x1+=0.5;//四舍五入预设
对于(i=0;i!==ll;i+=dlt)setPixel((x1+i*mul)| 0,y1+i);
}
否则{
y1+=0.5;
对于(i=0;i!==ll;i+=dlt)设置像素(x1+i,(y1+i*mul)|0);
}
setPixel(x2,y2);//设置最后一个像素
函数setPixel(x,y){ctx.rect(x,y,1,1)}
}
布雷森汉姆 这是一种经典的线条算法,在过去需要渲染简单线条的许多应用程序和计算机中使用

对算法进行了更详细的解释

功能线Bresenham(ctx、x1、y1、x2、y2){
如果(x1==x2){//特殊情况,垂直线
ctx.rect(x1,数学最小值(y1,y2),1,数学绝对值(y2-y1)+1);
回来
}
如果(y1==y2){//特殊情况,水平线
ctx.rect(数学最小值(x1,x2),y1,数学绝对值(x2-x1)+1,1);
回来
}
var dx=Math.abs(x2-x1),sx=x1dy?dx:-dy)*0.5;
而(!0){
ctx.rect(x1,y1,1,1);
如果(x1==x2&&y1==y2)中断;
var e2=错误;
如果(e2>-dx){err-=dy;x1+=sx;}
如果(e2
现场演示,包括缩放
var ctx=document.querySelector(“canvas”).getContext(“2d”);
ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height);//背景色
ctx.刻度(20,20);//规模
ctx.fillStyle=“#f00”//本例中线条的颜色
linefla(ctx,0,0,17,20);//算法1
lineBresenham(ctx,3,0,20,20);//算法2
ctx.fill();//填充矩形,下一步使用beginPath()
功能线FLA(ctx、x1、y1、x2、y2){
/*x1 |=0;//确保值为整数值
x2 |=0;
y1 |=0;
y2 |=0*/
var dlt,
穆尔,
sl=y2-y1,
ll=x2-x1,
yl=假,
lls=ll>>31,
sls=sl>>31,
我
如果((sl^sls)-sls>(ll^lls)-lls){
sl^=ll;
ll^=sl;
sl^=ll;
yl=真;
}
dlt=ll<0?-1:1;
mul=(ll==0)?sl:sl/ll;
if(yl){
x1+=0.5;
对于(i=0;i!==ll;i+=dlt)
设置像素((x1+i*mul)| 0,y1+i);
}否则{
y1+=0.5;
对于(i=0;i!==ll;i+=dlt)
设置像素(x1+i,(y1+i*mul)| 0);
}
setPixel(x2,y2);//设置最后一个像素
函数设置像素(x,y){
ctx.rect(x,y,1,1)
}
}
功能线Bresenham(ctx、x1、y1、x2、y2){
如果(x1==x2){//特殊情况,垂直线
ctx.rect(x1,数学最小值(y1,y2),1,数学绝对值(y2-y1)+1);
回来
}
如果(y1==y2){//特殊情况,水平线
ctx.rect(数学最小值(x1,x2),y1,数学绝对值(x2-x1)+1,1);
回来
}
var dx=数学绝对值(x2-x1),
sx=x1dy?dx:-dy)*0.5;
而(!0){
ctx.rect(x1,y1,1,1);
如果(x1==x2&&y1==y2)中断;
var e2=错误;
如果(e2>-dx){
err-=dy;
x1+=sx;
}
if(e2
问题背景 Canvas使用抗锯齿使图形显示为m
function lineBresenham(ctx, x1, y1, x2, y2) {

    if (x1 === x2) {  // special case, vertical line
        ctx.rect(x1, Math.min(y1, y2), 1, Math.abs(y2 - y1) + 1);
        return;
    }

    if (y1 === y2) {  // special case, horizontal line
        ctx.rect(Math.min(x1, x2), y1, Math.abs(x2 - x1) + 1, 1);
        return;
    }

    var dx = Math.abs(x2 - x1), sx = x1 < x2 ? 1 : -1,
        dy = Math.abs(y2 - y1), sy = y1 < y2 ? 1 : -1,
        err = (dx > dy ? dx : -dy) * 0.5;

    while(!0) {
        ctx.rect(x1, y1, 1, 1);
        if (x1 === x2 && y1 === y2) break;
        var e2 = err;
        if (e2 > -dx) { err -= dy; x1 += sx; }
        if (e2 < dy)  { err += dx; y1 += sy; }
    }
}