Chrome Canvas 中的亚像素渲染

10

我想知道是否有可能在Chrome(和/或Safari)的HTML5画布中启用亚像素渲染。

Chrome对HTML进行亚像素渲染,而Firefox则对HTML和Canvas都进行渲染。下面是特定问题的截图:

屏幕截图


2
我在谷歌上搜索“subpixel chrome canvas”,你两分钟前发布的帖子排名第一,而第二个结果是你的答案(一个较早的stackoverflow问题)。 - sod
1
@sod - 谢谢。这些解决方案需要手动文本渲染,这绝对不是我想要的方法。 - user578895
5个回答

8

简短回答:不可能。

这是许多Canvas用户感到沮丧的两个话题之一。

任何类型的子像素渲染/抗锯齿都取决于浏览器。这意味着不同的浏览器很容易以不同的方式呈现事物。

许多人要求抗锯齿成为可以在特定上下文中打开或关闭的选项。目前还没有这样的运气。

尤其需要注意Chrome,因为他们处理子像素渲染的方式在过去的4个月里发生了巨大变化。如果您开始使用Chrome开发者频道,您将预览到他们一直在尝试的东西。他们在这个领域做了很多测试,甚至推出了一些我抱怨过的激进倒退变化。

这里的要点是:

  1. 关于子像素渲染,Chrome绝对“还没有完成”。很遗憾,但目前您最好的选择是等一段时间。
  2. 规范在这个领域需要更具体,以便浏览器之间有些一致性,因为现在任何子像素渲染/抗锯齿都非常依赖于浏览器。在2008年曾经讨论过它,但仍未解决。我不知道有任何进展。

1
这仍然是真的吗? - Crashalot

1

目前我不认为这是可能的。

这是一个难题,因为画布提供了如此多底层控制权给用户。如果画布开始做这样一些智能的事情,它可能会破坏用户预期的一些其他功能。

考虑其他图形元素的亚像素渲染 - 根据应用程序,程序员可能不希望这样做,并且你肯定不希望将亚像素渲染作为全局元素开关任意启用。试想获取特定像素的颜色 - 这里的正确答案是什么?画布是否应该说谎并返回预期的颜色,还是返回实际的颜色(这样我们就必须回答整天的问题:“为什么我制作的黑色像素被测量为暗红色?”)。

有人会认为Firefox在这里做错了。


0

这里有一种对于任何画布内容(文本、图像、矢量等)进行亚像素渲染的方法。http://johnvalentine.co.uk/subpixel-html5-canvas.htm

方法概述

它绘制到画布上,然后绘制到屏幕上以利用RGB条纹亚像素。它也适用于alpha通道。请注意,如果您使用的是纵向显示器、非条纹像素或者您的浏览器将画布显示在低于您的显示器分辨率的情况下,则可能无法正常工作。

虽然还有优化的空间,但这是一种简单方法的重大收益。我已经测试过所有浏览器都可以使用,但只适用于画布到屏幕像素比为1:1的情况(但我相信已经提供了解决方案)。


有趣的方法,对于一次性图形生成来说是个不错的想法。但是对于任何类型的动画来说,它会非常慢且完全无法使用 :( - user578895
@zyklus,这取决于您如何呈现它。与其重新渲染整个图像,不如只重新渲染从动画的第一帧到第二帧不同的部分。 - Pacerier

0

这取决于平台,但是有可能实现。以下是具体步骤:

  1. 创建一个不透明的画布上下文,使用 canvas.getContext('2d', {alpha: false})
  2. -webkit-font-smoothing 属性设置为所需值:autoantialias(模糊)、subpixel-antialias(带彩色边缘的“LCD”文本)或 none

这将应用于画布中的所有文本。

以下是在 Mac 上 Chrome 81 中的屏幕截图;绿色矩形中的文本是画布的 fillText

Screenshot of canvas text with different antialiasing options

这是该文件的源代码:


<!DOCTYPE html>
<style>
canvas {
  border: 1px solid green;
}
div {
  position: float;
  float: left;
}
#a {
  -webkit-font-smoothing: auto;
}
#b {
  -webkit-font-smoothing: antialiased;
}
#c {
  -webkit-font-smoothing: subpixel-antialiased;
}
#d {
  -webkit-font-smoothing: none;
}
</style>
<div id="a">
(auto)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="b">
(antialiased)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="c">
(subpixel)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<div id="d">
(none)<br>
??????????<br>
||||||||||<br>
IIIIIIIIII<br>
llllllllll<br>
//////////<br>
</div>
<script>
'use strict';
function add(container) {
  let canvas = document.createElement('canvas');
  const width = container.clientWidth;
  canvas.style.width = `${width}px`;
  const height = 40;
  canvas.style.height = `${height}px`;
  canvas.width = Math.floor(width * window.devicePixelRatio);
  canvas.height = Math.floor(height * window.devicePixelRatio);
  container.append(canvas);
  let ctx = canvas.getContext('2d', {alpha: false});
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.fillStyle = 'black';
  ctx.font = '12pt Arial';
  ctx.fillText('\/!|hello world', 0, height / 2);
}

add(a);
add(b);
add(c);
add(d);
</script>

你正在回答一个9年前的问题... 当时这是不可能的。 - user578895
6
没错...但这个问题仍然有意义,所以我想回答它,为了下一个搜索到这个问题的人。 - Dominic Cooney

0
在2023年,这是可能的。当获取Canvas上下文时,您只需要指定alpha: false
ctx = canvas.getContext("2d", {alpha: false});

结果:

with subpixel rendering


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接