我写了一个脚本,它采用像这样的图像(通常黑色是alpha):

...并添加您喜欢的任何颜色的边框:

然而,它不是很快.创建边框图层需要大约130毫秒作为这种小字体的画布.更大的字体需要更长的时间!
逻辑很简单:
/* This is more or less psuedo-code. */
// Blank image data where I will put the border.
var newData = newContext.getImageData(0, 0, canvas.width, canvas.height);
// The image I will be analyzing.
var oldData = oldContext.getImageData(0, 0, this.data.width, this.data.height);
// Loop through every pixel in oldData and remember where non-alpha pixels are.
var fontPixels = this._getNonAlphaPixels(oldData);
// Loop through relevant pixels, remember neighboring pixels, and add border.
for (var px in fontPixels) {
for (var py in fontPixels[px]) {
var borderPixels = this._getBorderPixels(px, py);
for (var bx in borderPixels) {
for (var by in borderPixels[bx]) {
if (typeof fontPixels[bx] !== 'undefined' &&
typeof fontPixels[bx][by] !== 'undefined')
{
continue; // Do not draw borders inside of font.
}
newData.data[((newData.width * by) + bx) * 4] = color.red;
newData.data[((newData.width * by) + bx) * 4 + 1] = color.green;
newData.data[((newData.width * by) + bx) * 4 + 2] = color.blue;
newData.data[((newData.width * by) + bx) * 4 + 3] = 255; //alpha
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上我想知道:有人知道一种不需要逐像素操作的替代方法吗?或者是否可以对上述逻辑进行重大优化?
我应该提到,_getNonAlphaPixels这个时间可以忽略不计.并且_getBorderPixels执行时间仅占总时间的17%.
编辑
以下选择的答案非常有用.我的解决方案与下面的解决方案之间唯一的显着区别是,无论何时绘制文本,我都会绘制图像(字体).
谢谢肯.
小智 5
你可以用几种方式做到这一点.
一种是使用内置strokeText函数绘制文本轮廓.设置lineWidth将决定边框的厚度.但是,结果并不总是令人满意:
ctx.strokeStyle = color;
ctx.font = font;
ctx.lineWidth = 2;
ctx.strokeText(txt, x, y);
Run Code Online (Sandbox Code Playgroud)
结果是:

文本和画布目前在子像素级别上不那么准确,这与使用字体提示(或者更确切地说不使用),抗锯齿和其他方面有关.
无论如何,通过在"圆圈"中手动绘制文本来创建边框,您可以获得更好的结果:
var thick = 2;
ctx.fillStyle = color;
ctx.font = font;
ctx.fillText(txt, x - thick, y - thick);
ctx.fillText(txt, x, y - thick);
ctx.fillText(txt, x + thick, y - thick);
ctx.fillText(txt, x + thick, y);
ctx.fillText(txt, x + thick, y + thick);
ctx.fillText(txt, x, y + thick);
ctx.fillText(txt, x - thick, y + thick);
ctx.fillText(txt, x - thick, y);
ctx.fillStyle = '#fff';
ctx.fillText(txt, x, y);
Run Code Online (Sandbox Code Playgroud)
结果好多了,如下所示:

最后一种技术的缺点是我们要求画布在理论上将文本渲染9次 - 这是浪费时间......(见结果).
为了改善这一点,我们至少可以通过作为一次图像缓存边框文本,我们绘制文本的时间减为两个,并用它来绘制边框,然后画在上面的最后文本.
这里octx代表一个离屏画布上下文(c它自己的离屏画布),我们绘制我们将用于边框的文本.然后,我们更换圆形fillText带drawImage.请注意,我们将基线设置为top以更容易控制文本最终的位置.
octx.textBaseline = ctx.textBaseline = 'top';
octx.fillStyle = color;
octx.font = ctx.font = font;
octx.fillText(txt, 0, 0);
ctx.drawImage(c, x - thick, y - thick);
ctx.drawImage(c, x, y - thick);
ctx.drawImage(c, x + thick, y - thick);
ctx.drawImage(c, x + thick, y);
ctx.drawImage(c, x + thick, y + thick);
ctx.drawImage(c, x, y + thick);
ctx.drawImage(c, x - thick, y + thick);
ctx.drawImage(c, x - thick, y);
ctx.fillStyle = '#fff';
ctx.fillText(txt, x, y);
Run Code Online (Sandbox Code Playgroud)
图像结果与上一个相同:

请注意,如果你想要更厚的边框,你可能会想要考虑实际进行圆形绘制 - 字面意思 - 使用cos/sin等.原因是因为在更高的偏移处,边界将开始分离:

您可以改为使用Cos/Sin计算在文字圆圈中绘制文本,而不是添加一组绘制:
function drawBorderText(txt, x, y, font, color) {
var thick = 7,
segments = 4, /// number of segments to divide the circle in
angle = 0, /// start angle
part, /// degrees per segment, see below
i = 0, d2r = Math.PI / 180;
/// determine how many parts are needed. I just
/// started with some numbers in this demo.. adjust as needed
if (thick > 1) segments = 6;
if (thick > 2) segments = 8;
if (thick > 4) segments = 12;
part = 360 / segments;
ctx.fillStyle = color;
ctx.font = font;
/// draw the text in a circle
for(;i < segments; i++) {
ctx.fillText(txt, x + thick * Math.cos(angle * d2r),
y + thick * Math.sin(angle * d2r));
angle += part;
}
ctx.fillStyle = '#fff';
ctx.fillText(txt, x, y);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,您可能需要绘制两个圆形,因为它们不具有实心的小点(例如,参见i上的点).

这个演示中有点粗糙,但是举个例子.你可以通过为段设置不同的阈值来微调,也可以添加一个"内圆",其中文本包含这里的小细节(i).
请注意,结果取决于各种因素:
例如,如果没有硬件加速的Atom单核的计算机上,我得到两个演示2和3的Firefox(极光)为16ms(有时双的纯文字版).
在同一台计算机上的Chrome(Canary)中,基于文本的一个使用1-3毫秒,而缓存使用大约5毫秒.
在慢速计算机上,sin/cos方法大约需要8到11毫秒(几次达到5毫秒 - JSFiddle不是测试性能的最佳位置).
我目前无法访问其他硬件进行测试(这里的边距非常小,而且我不确定JavaScript能否接受它,我相信特别是Firefox的情况)但是与使用手动像素操作相比,在任何情况下,你都会有很大的增长.
| 归档时间: |
|
| 查看次数: |
98 次 |
| 最近记录: |