繁体   English   中英

在HTML5Canvas中绘制和填充非抗锯齿圆的最快方法

[英]Fastest way to draw and fill a NOT anti-aliasing circle in HTML5Canvas

我需要为HTML5Canvas中的基本绘图应用程序绘制并填充一个非抗锯齿的圆,因为填充桶工具算法无法很好地填充抗锯齿形状的边框。

我采用了此页面的JavaScript算法https://en.wikipedia.org/wiki/Midpoint_circle_algorithm并实现了它来绘制实心圆,但是它很慢。

canvas = document.getElementById("canvas");
const CHANNELS_PER_PIXEL = 4; //rgba

function drawCircle (x0, y0, radius, canvas) {
var x = radius-1;
var y = 0;
var dx = 1;
var dy = 1;
var decisionOver2 = dx - (radius << 1);   // Decision criterion divided by 2 evaluated at x=r, y=0
var imageWidth = canvas.width;
var imageHeight = canvas.height;
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, imageWidth, imageHeight);
var pixelData = imageData.data;
var makePixelIndexer = function (width) {
    return function (i, j) {
        var index = CHANNELS_PER_PIXEL * (j * width + i);
        //index points to the Red channel of pixel 
        //at column i and row j calculated from top left
        return index;
    };
};
var pixelIndexer = makePixelIndexer(imageWidth);
var drawPixel = function (x, y) {
    var idx = pixelIndexer(x,y);
    pixelData[idx] = 152;   //red
    pixelData[idx + 1] = 152; //green
    pixelData[idx + 2] = 152;//blue
    pixelData[idx + 3] = 255;//alpha
};

while (x >= y) {

    if(x0 + x>=0){drawPixel(x0 + x, y0 + y);}
    if(x0 + y>=0){drawPixel(x0 + y, y0 + x);}
    if(x0 - x>=0){drawPixel(x0 - x, y0 + y);} 
    if(x0 - y>=0){drawPixel(x0 - y, y0 + x);} 
    if(x0 - x>=0){drawPixel(x0 - x, y0 - y);}
    if(x0 - y>=0){drawPixel(x0 - y, y0 - x);}
    if(x0 + x>=0){drawPixel(x0 + x, y0 - y);}
    if(x0 + y>=0){drawPixel(x0 + y, y0 - x);}

    //fill circle code
    var x1=x0-x;
    var x2=x0+x;
    var xx=x2-x1;

        for(i=x2-x1;i>0; i--){
            if((x1+(xx-i))>=0){
            drawPixel(x1+(xx-i),y0+y);
            }
        }

    var x1=x0-y;
    var x2=x0+y;
    var xx=x2-x1;

        for(i=x2-x1;i>0; i--){
            if((x1+(xx-i))>=0){
            drawPixel(x1+(xx-i),y0+x);
            }
        }

    var x1=x0-x;
    var x2=x0+x;
    var xx=x2-x1;

        for(i=x2-x1;i>0; i--){
            if((x1+(xx-i))>=0){
            drawPixel(x1+(xx-i),y0-y);
            }
        }

    var x1=x0-y;
    var x2=x0+y;
    var xx=x2-x1;

        for(i=x2-x1;i>0; i--){
            if((x1+(xx-i))>=0){
            drawPixel(x1+(xx-i),y0-x);
            }
        }
    //fill end

    if (decisionOver2 <= 0) 
    {
        y++;
        decisionOver2 += dy; // Change in decision criterion for y -> y+1
        dy += 2;
    } 
    if (decisionOver2 > 0)
    {
        x--;
        dx += 2;
        decisionOver2 += (-radius << 1) + dx; // Change for y -> y+1, x -> x-1
    }
}

context.putImageData(imageData, 0, 0);
}

也,

context.translate(0.5, 0.5);

context.imageSmoothingEnabled = !1;

不要工作一圈。

您是否拥有更好的功能,或者您知道如何压缩和连接此圆形算法?

谢谢

我制作了Breseham圆圈算法的此修改版本,以便为“复古”项目回填“混淆”圆圈。

修改是从8个切片中获取值并将其转换为4行。 我们可以使用rect()创建一条线,但必须将绝对(x2,y2)坐标转换为宽度和高度。

该方法只需将rect添加到相当快的路径中,您就不必通过慢速的getImageData() / putImageData() (并且不会受到CORS问题的影响)。 最后,将调用一个填充操作。 这意味着您也可以直接在画布上使用它,而不必担心大多数情况下的现有内容。

重要的是,平移值和给定值是数值,并且半径> 0。

要强制整数值,只需将值移动0:

xc = xc|0;  // you can add these to the function below
yc = yc|0;
r  = r|0;

(如果要制作轮廓(“描边的”)版本,则必须使用所有8个切片的位置,并将rect()宽度更改为1。)

演示版

快照4倍

 var ctx = c.getContext("2d"); ctx.fillStyle = "#09f"; aliasedCircle(ctx, 200, 200, 180); ctx.fill(); function aliasedCircle(ctx, xc, yc, r) { // NOTE: for fill only! var x = r, y = 0, cd = 0; // middle line ctx.rect(xc - x, yc, r<<1, 1); while (x > y) { cd -= (--x) - (++y); if (cd < 0) cd += x++; ctx.rect(xc - y, yc - x, y<<1, 1); // upper 1/4 ctx.rect(xc - x, yc - y, x<<1, 1); // upper 2/4 ctx.rect(xc - x, yc + y, x<<1, 1); // lower 3/4 ctx.rect(xc - y, yc + x, y<<1, 1); // lower 4/4 } } 
 <canvas id=c width=400 height=400></canvas> 

放大演示:

 var ctx = c.getContext("2d"); ctx.scale(4,4); ctx.fillStyle = "#09f"; aliasedCircle(ctx, 50, 50, 45); ctx.fill(); ctx.font = "6px sans-serif"; ctx.fillText("4x", 2, 8); function aliasedCircle(ctx, xc, yc, r) { var x = r, y = 0, cd = 0; // middle line ctx.rect(xc - x, yc, r<<1, 1); while (x > y) { cd -= (--x) - (++y); if (cd < 0) cd += x++; ctx.rect(xc - y, yc - x, y<<1, 1); // upper 1/4 ctx.rect(xc - x, yc - y, x<<1, 1); // upper 2/4 ctx.rect(xc - x, yc + y, x<<1, 1); // lower 3/4 ctx.rect(xc - y, yc + x, y<<1, 1); // lower 4/4 } } 
 <canvas id=c width=400 height=400></canvas> 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM