如何在Canvas中绘制无抗锯齿文本,适配自定义复古等宽字体?
如何在Canvas中渲染无抗锯齿的像素风格文本
问题背景
需要在Canvas上显示无抗锯齿的固定等宽像素字体,现有实现中DOM元素可以渲染出清晰的像素边缘字体,但Canvas渲染的同字体文本存在抗锯齿模糊问题。
现有实现代码
<html> <head> <style type="text/css"> @font-face { font-family: "AST"; src: url(web_ast_premiumexec.woff) format('woff'); } div { font-family: "AST"; font-size: 16px; } canvas { font-smooth: never; -webkit-font-smoothing: none; /* image-rendering: pixelated; image-rendering: crisp-edges; */ } </style> </head> <body> <div>А</div> <canvas id="canvas" width="32" height="32"></canvas> <script type="text/javascript"> function setpixelated(context){ context.imageSmoothingEnabled = false; /* standard */ context.mozImageSmoothingEnabled = false; /* Firefox */ context.oImageSmoothingEnabled = false; /* Opera */ context.webkitImageSmoothingEnabled = false; /* Safari */ context.msImageSmoothingEnabled = false; /* IE */ context.imageSmoothingEnabled= false } var f = new FontFace('AST', 'url(web_ast_premiumexec.woff)'); f.load().then(function() { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); setpixelated(ctx) ctx.font = "16px AST" ctx.fillstyle='#00f'; ctx.filter = 'none'; ctx.fillText('А', 0, 16); }) </script> </body> </html>
实际渲染效果
顶部为DOM渲染的清晰效果,底部为Canvas渲染的模糊效果:
解决方案
按照以下步骤修改代码即可实现无抗锯齿的清晰像素文本:
- 修复代码笔误:将
ctx.fillstyle改为驼峰命名ctx.fillStyle,错误的属性名会导致样式不生效。 - 放开Canvas样式中注释的渲染规则,明确指定像素级渲染:
canvas { font-smooth: never; -webkit-font-smoothing: none; image-rendering: pixelated; image-rendering: crisp-edges; }
- 适配高分屏设备避免自动插值模糊:Canvas的实际画布尺寸需要乘以设备像素比,再通过CSS缩放到目标显示尺寸:
修改JS逻辑如下:
f.load().then(function() { const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); // 适配高DPI屏幕 const dpr = window.devicePixelRatio || 1; const displaySize = 32; canvas.width = displaySize * dpr; canvas.height = displaySize * dpr; canvas.style.width = `${displaySize}px`; canvas.style.height = `${displaySize}px`; ctx.scale(dpr, dpr); setpixelated(ctx); // 额外添加文本渲染优化规则 ctx.textRendering = "optimizeSpeed"; ctx.antialias = false; ctx.font = "16px AST"; ctx.fillStyle = '#00f'; ctx.filter = 'none'; ctx.fillText('А', 0, 16); })
- 如果部分浏览器依然存在抗锯齿,可以增加离屏Canvas二次绘制的逻辑:先把文本渲染到小尺寸离屏画布,再放大绘制到主画布,因为已经关闭了图像平滑,放大后会保留像素边缘不会模糊:
// 离屏渲染逻辑 const offscreen = document.createElement('canvas'); offscreen.width = 32; offscreen.height = 32; const offCtx = offscreen.getContext('2d'); setpixelated(offCtx); offCtx.font = "16px AST"; offCtx.fillStyle = '#00f'; offCtx.fillText('А', 0, 16); // 绘制到主画布 ctx.drawImage(offscreen, 0, 0, canvas.width, canvas.height);
内容的提问来源于stack exchange,提问作者kostr22
相关产品推荐
相关产品推荐

