如何在没有抗锯齿的情况下在 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>

目前,最好的办法可能是将您的文本预渲染为位图。