如何在没有抗锯齿的情况下在 canvas 上绘制像素字体
How to draw a pixel font on the canvas without anti-aliasing
我有一个像素艺术字体(在 ttf 文件中),我发现它的原始分辨率为 8 像素 (CTX.font = '8px mainfont';
)
当我填充文本时,字体在 firefox 中完美显示,但在 chrome 中模糊不清:
火狐
chrome
我尝试将 X 坐标偏移不同的量(例如 0.5),但它变得更加模糊。通常它总是一个整数。
我尝试了 CTX.translate(0.5, 0);
和 CTX.imageSmoothingEnabled = true;
我试过了cssfont-smooth: none;
font-smooth: never;
-webkit-font-smoothing : none;
过去我不得不将我的字体转换为特殊格式并使用库在 canvas 上绘制它们。只是希望 5 年后他们添加一个官方方法来解决这个问题?
Was just hoping 5 years later they added an official way to fix this problem?
嗯...不超过几个月前,more text modifiers have been added to the canvas API, among which ctx.textRendering
, which is basically the equivalent of SVG's text-rendering
。
所以,none 的选项确实会强制关闭抗锯齿,但使用 textRendering = "geometricPrecision"
.
肯定会有更好的效果
此外,目前只有基于 Chromium 的浏览器才支持此功能……并且只有在 chrome://flags/#enable-experimental-web-platform-features
开启的情况下才支持。
const label = document.querySelector( "label" );
const canvas = document.querySelector( "canvas" );
const ctx = canvas.getContext( "2d" );
if( !ctx.textRendering ) {
console.warn( `Your browser doesn't support the textRendering property on Canvas
If you are on Chrome be sure to enable chrome://flags/#enable-experimental-web-platform-features` );
}
let state = 0;
const states = [
() => {
label.textContent = "optimizeLegibility";
ctx.textRendering = "optimizeLegibility";
drawText();
},
() => {
label.textContent = "geometricPrecision";
ctx.textRendering = "geometricPrecision";
drawText();
},
() => {
label.textContent = "difference";
ctx.textRendering = "optimizeLegibility";
drawText();
ctx.globalCompositeOperation = "xor";
ctx.textRendering = "geometricPrecision";
drawText();
ctx.globalCompositeOperation = "source-over";
}
];
document.fonts.load( "120px pixel" ).then( begin );
function begin() {
ctx.clearRect( 0, 0, canvas.width, canvas.height );
ctx.font = "120px pixel";
states[ state ]();
state = (state + 1) % states.length;
setTimeout( begin, 1000 );
}
function drawText() {
ctx.textBaseline = "top";
ctx.fillText( "TESTING", 0, 0 );
}
@font-face {
font-family: pixel;
src: url("https://dl.dropboxusercontent.com/s/hsdwvz761xqphhb/pixel.ttf");
}
<label></label><br>
<canvas width="500"></canvas>
目前,最好的办法可能是将您的文本预渲染为位图。
我有一个像素艺术字体(在 ttf 文件中),我发现它的原始分辨率为 8 像素 (CTX.font = '8px mainfont';
)
当我填充文本时,字体在 firefox 中完美显示,但在 chrome 中模糊不清:
我尝试将 X 坐标偏移不同的量(例如 0.5),但它变得更加模糊。通常它总是一个整数。
我尝试了 CTX.translate(0.5, 0);
和 CTX.imageSmoothingEnabled = true;
我试过了cssfont-smooth: none;
font-smooth: never;
-webkit-font-smoothing : none;
过去我不得不将我的字体转换为特殊格式并使用库在 canvas 上绘制它们。只是希望 5 年后他们添加一个官方方法来解决这个问题?
Was just hoping 5 years later they added an official way to fix this problem?
嗯...不超过几个月前,more text modifiers have been added to the canvas API, among which ctx.textRendering
, which is basically the equivalent of SVG's text-rendering
。
所以,none 的选项确实会强制关闭抗锯齿,但使用 textRendering = "geometricPrecision"
.
此外,目前只有基于 Chromium 的浏览器才支持此功能……并且只有在 chrome://flags/#enable-experimental-web-platform-features
开启的情况下才支持。
const label = document.querySelector( "label" );
const canvas = document.querySelector( "canvas" );
const ctx = canvas.getContext( "2d" );
if( !ctx.textRendering ) {
console.warn( `Your browser doesn't support the textRendering property on Canvas
If you are on Chrome be sure to enable chrome://flags/#enable-experimental-web-platform-features` );
}
let state = 0;
const states = [
() => {
label.textContent = "optimizeLegibility";
ctx.textRendering = "optimizeLegibility";
drawText();
},
() => {
label.textContent = "geometricPrecision";
ctx.textRendering = "geometricPrecision";
drawText();
},
() => {
label.textContent = "difference";
ctx.textRendering = "optimizeLegibility";
drawText();
ctx.globalCompositeOperation = "xor";
ctx.textRendering = "geometricPrecision";
drawText();
ctx.globalCompositeOperation = "source-over";
}
];
document.fonts.load( "120px pixel" ).then( begin );
function begin() {
ctx.clearRect( 0, 0, canvas.width, canvas.height );
ctx.font = "120px pixel";
states[ state ]();
state = (state + 1) % states.length;
setTimeout( begin, 1000 );
}
function drawText() {
ctx.textBaseline = "top";
ctx.fillText( "TESTING", 0, 0 );
}
@font-face {
font-family: pixel;
src: url("https://dl.dropboxusercontent.com/s/hsdwvz761xqphhb/pixel.ttf");
}
<label></label><br>
<canvas width="500"></canvas>
目前,最好的办法可能是将您的文本预渲染为位图。