非常感谢所有这些解释!
默认fillText()不支持在画布中以简洁的方式显示“简单字符串”,这是非常不可思议的,我们必须做这样的技巧才能有一个正确的显示,也就是说一个显示是一点也不模糊或模糊。这有点像画布中的“1px 画线问题”(为此使坐标 +0.5 有助于但不能完全解决问题)...
我修改了您上面提供的代码,使其支持彩色文本(不仅是黑白文本)。希望能帮到你。
在函数subPixelBitmap() 中,有一个平均红/绿/蓝颜色的小算法。它稍微改进了画布中的字符串显示(在 Chrome 上),特别是对于小字体。也许还有其他更好的算法:如果你找到了,我会很感兴趣。
下图显示效果:改进了canvas中的字符串显示
这是一个可以在线运行的工作示例:working example on jsfiddle.net
相关代码是这个(查看上面的工作示例以了解最新版本):
canvas = document.getElementById("my_canvas");
ctx = canvas.getContext("2d");
...
// Display a string:
// - nice way:
ctx.font = "12px Arial";
ctx.fillStyle = "red";
subPixelText(ctx,"Hello World",50,50,25);
ctx.font = "bold 14px Arial";
ctx.fillStyle = "red";
subPixelText(ctx,"Hello World",50,75,25);
// - blurry default way:
ctx.font = "12px Arial";
ctx.fillStyle = "red";
ctx.fillText("Hello World", 50, 100);
ctx.font = "bold 14px Arial";
ctx.fillStyle = "red";
ctx.fillText("Hello World", 50, 125);
var subPixelBitmap = function(imgData){
var spR,spG,spB; // sub pixels
var id,id1; // pixel indexes
var w = imgData.width;
var h = imgData.height;
var d = imgData.data;
var x,y;
var ww = w*4;
for(y = 0; y < h; y+=1){ // (go through all y pixels)
for(x = 0; x < w-2; x+=3){ // (go through all groups of 3 x pixels)
var id = y*ww+x*4; // (4 consecutive values: id->red, id+1->green, id+2->blue, id+3->alpha)
var output_id = y*ww+Math.floor(x/3)*4;
spR = Math.round((d[id + 0] + d[id + 4] + d[id + 8])/3);
spG = Math.round((d[id + 1] + d[id + 5] + d[id + 9])/3);
spB = Math.round((d[id + 2] + d[id + 6] + d[id + 10])/3);
// console.log(d[id+0], d[id+1], d[id+2] + '|' + d[id+5], d[id+6], d[id+7] + '|' + d[id+9], d[id+10], d[id+11]);
d[output_id] = spR;
d[output_id+1] = spG;
d[output_id+2] = spB;
d[output_id+3] = 255; // alpha is always set to 255
}
}
return imgData;
}
var subPixelText = function(ctx,text,x,y,fontHeight){
var width = ctx.measureText(text).width + 12; // add some extra pixels
var hOffset = Math.floor(fontHeight);
var c = document.createElement("canvas");
c.width = width * 3; // scaling by 3
c.height = fontHeight;
c.ctx = c.getContext("2d");
c.ctx.font = ctx.font;
c.ctx.globalAlpha = ctx.globalAlpha;
c.ctx.fillStyle = ctx.fillStyle;
c.ctx.fontAlign = "left";
c.ctx.setTransform(3,0,0,1,0,0); // scaling by 3
c.ctx.imageSmoothingEnabled = false;
c.ctx.mozImageSmoothingEnabled = false; // (obsolete)
c.ctx.webkitImageSmoothingEnabled = false;
c.ctx.msImageSmoothingEnabled = false;
c.ctx.oImageSmoothingEnabled = false;
// copy existing pixels to new canvas
c.ctx.drawImage(ctx.canvas,x,y-hOffset,width,fontHeight,0,0,width,fontHeight);
c.ctx.fillText(text,0,hOffset-3 /* (harcoded to -3 for letters like 'p', 'g', ..., could be improved) */); // draw the text 3 time the width
// convert to sub pixels
c.ctx.putImageData(subPixelBitmap(c.ctx.getImageData(0,0,width*3,fontHeight)), 0, 0);
ctx.drawImage(c,0,0,width-1,fontHeight,x,y-hOffset,width-1,fontHeight);
}