如何在没有抗锯齿的情况下在画布上绘制像素字体

Posted

技术标签:

【中文标题】如何在没有抗锯齿的情况下在画布上绘制像素字体【英文标题】:How to draw a pixel font on the canvas without anti-aliasing 【发布时间】:2021-12-14 01:23:54 【问题描述】:

我有一个像素艺术字体(在一个 ttf 文件中),我发现它的原始分辨率是 8 像素 (CTX.font = '8px mainfont';)

当我做 fillText 时,字体在 firefox 中完美显示,但在 chrome 中模糊:

火狐

我尝试将 X 坐标偏移不同的量,例如 0.5,但它变得更加模糊。通常它总是一个整数。

我试过CTX.translate(0.5, 0);CTX.imageSmoothingEnabled = true;

我试过 css font-smooth: none; font-smooth: never; -webkit-font-smoothing : none;

过去,我必须将字体转换为特殊格式并使用库在画布上绘制它们。只是希望 5 年后他们添加了一种官方方法来解决这个问题吗?

【问题讨论】:

【参考方案1】:

是否只是希望 5 年后他们添加了解决此问题的官方方法?

嗯……不超过几个月前,more text modifiers一直是added to the canvas API,其中ctx.textRendering,基本相当于SVG's text-rendering

因此,没有任何选项会真正强制关闭抗锯齿,但使用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 ></canvas>

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

【讨论】:

以上是关于如何在没有抗锯齿的情况下在画布上绘制像素字体的主要内容,如果未能解决你的问题,请参考以下文章

防止 TrueType 字体的抗锯齿(或子像素渲染)

在 iOS 中,如何在没有抗锯齿/插值的情况下绘制位图?

画布中的抗锯齿大文本

关于字体的抗锯齿属性

透明位图上的抗锯齿文本

如何在没有抗锯齿的情况下拉伸图像