我目前想用可变大小的圆圈填充给定的文本(实际上......它是任何图像)。
到目前为止,我将文本写入 <canvas>
,然后我通过以下方式获取图像数据:ctx.getImageData(0, 0, w, h)
,然后我开始循环遍历数组,从 imageData 中查找像素。
我面临这个问题,但我不明白为什么:(
- 它太慢了(对于大文本),我该如何提高它的性能?
- 是否有任何我可以使用的现有算法以便我可以研究它?
- 如果我使用更大的 Canvas
getImageData()
从,性能太差,没有完成。
这是我到目前为止的代码:http://codepen.io/Goodwine/pen/xDvLk
function circleCanvas(ctx, minR, maxR, padding) {
var c = $('<canvas>')[0].getContext('2d');
var img = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
var h = c.canvas.height = img.height;
var w = c.canvas.width = img.width;
var ban = [];
for (var i = 0; i < img.data.length; i += 4) {
if (img.data[i] != 100 || isBanned(ban, i, w))
continue;
var r = parseInt((Math.random() * 10000) % (maxR - minR) + minR);
var x = Math.floor(i % (w * 4) / 4) + r;
var y = Math.floor(i / (w * 4)) + r;
drawCircle(c, x, y, r);
ban.push({xi: x - r - padding, yi: y - r - padding, xf: x + r + padding, yf: y + r + padding});
}
return c;
}
.
// this function is used because I didn't find how else to improve performance
// it checks if there is a point in a "banned" range, and it ignores it in
// case it does.
function isBanned(ban, p, w) {
var x = Math.floor(p % (w * 4) / 4);
var y = Math.floor(p / (w * 4));
for (var i in ban) {
if (x >= ban[i].xi && x <= ban[i].xf && y >= ban[i].yi && y <= ban[i].yf)
return true;
}
return false;
}
最佳答案
作为开始,您可以通过以下几种方法来优化代码:
- 向路径添加弧线并在末端填充而不是填充,每次都设置颜色。
- 使用
Uint32Arrays
迭代和检测像素 - 将 ban() 区域替换为计数器的增量
例如,您可以通过以下方式添加圈子:
function addCircle(ctx, x, y, r) {
ctx.moveTo(x + r, y);
ctx.arc(x, y, r, 0, 2*Math.PI);
}
然后使用 Uint32Array
迭代循环:
function circleCanvas(ctx, minR, maxR, padding) {
var h = ctx.canvas.height;
var w = ctx.canvas.width;
var img = ctx.getImageData(0, 0, w, h);
/// use an Uint32 buffer instead
var buffer = new Uint32Array(img.data.buffer);
/// create new path here
ctx.beginPath();
var ban = []; /// I'm ignoring this in this example
var skipLines;
for (var i = 0; i < buffer.length; i++) {
if (buffer[i] === 0)
continue;
var r = (Math.random() * (maxR - minR) + minR)|0;
var x = i % w;
var y = Math.floor(i / w);
addCircle(ctx, x, y, r);
i += r * 2;
if (x === 0) {
skipLines = (r * 2 * Math.random() + r)|0;
i += skipLines * w;
}
}
/// fill at end
ctx.fillStyle = '#000';
ctx.fill();
}
<强> See update here
关于javascript - 如何以最佳性能用可变大小的圆圈填充 Canvas 文本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21343818/