什么原因导致Calibri在9到14磅之间失去ClearType效果?

17

GDI+在使用默认的Microsoft Office字体Calibri时,具有ClearTypeGridFit指定的大小在9pt和14pt之间时切换到二进制抗锯齿。这是什么原因呢?

这有些令人不安。还有多少其他字体也受到此背后的影响,并且在哪些大小下受到影响?是否有解决方法?(排除GDI,它没有相同的文本布局功能)

以下是我用来生成图像的代码:

private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

    var height = 0;
    for (var i = 1; i <= 17; i++)
    {
        using (var font = new Font("Calibri", i))
        {
            var text = "ClearTypeGridFit " + i + "pt";
            e.Graphics.DrawString(text, font, SystemBrushes.ControlText, 0, height);
            height += (int)e.Graphics.MeasureString(text, font).Height;
        }
    }
}

1
Graphics.DrawString()只在高DPI设备上产生不错的输出效果。打印机,而不是显示器。请使用TextRenderer.DrawText(e.Graphics, text, font, new Point(0, height), SystemColors.ControlText);代替。 - Hans Passant
@HansPassant 已经明白了。这个问题对我来说仍然很有趣和重要。这是我正在处理的内容。 - jnm2
显然,你得等到DevEx开始行动起来才行。同时,使用一个表现更好的字体,XP字体没有这个问题。Segoe UI也可以。 - Hans Passant
可能会。与此同时,我真的希望有人足够了解这个谜团。由于我无法控制字体,谁知道在其他字体中还会出现什么问题? - jnm2
@HansPassant 如果您将其作为答案编写,即使它不是问题的确切答案,人们也会遇到此问题并从您的评论中获得更多帮助。请考虑将其作为答案发布。 - Mike 'Pomax' Kamermans
1个回答

15
Calibri配有EBLC表和EBDT表,这些表格告诉文本引擎,在某些点大小下,它们不应尝试“自己的缩放算法”,而只需直接使用存储在字体中的位图。
每个字体大小都可以有其自己的“必须在此大小上以位图形式显示以下字形”的列表,称为“打印头”,因此一个字形可以有多个大小的位图(但可能存在间隙,此时需要缩放位图,否则会出现灾难性错误)。
例如,Calibri具有12、13、15、16、17和19号字体大小的打印头,其中A的示例位图如下:
<ebdt_bitmap_format_1 name="A">
  <SmallGlyphMetrics>
    <height value="8"/>
    <width value="7"/>
    <BearingX value="0"/>
    <BearingY value="8"/>
    <Advance value="7"/>
  </SmallGlyphMetrics>
  <rawimagedata>
    10102828 447c8282  
  </rawimagedata>
</ebdt_bitmap_format_1>

这个位图是由字体大小为12的打印机引用的,编码为7x8像素位图。由于12是最低值,当我们使用小于12的字体大小时就会遇到问题:我们必须缩放位图。这可能会出现严重的问题。
如果您查看类似WordPad的东西,您可以看到Microsoft的Uniscribe引擎(与GDI+一起使用;现代等效物是具有DirectWrite作为文本引擎的Direct2D)可以相当好地缩小这些位图(显示大小为5至20),但甚至连Microsoft自己的技术也有明显的限制。我们看到在字体大小为5、6和7px时,位图非常糟糕,甚至8、10和11看起来有些奇怪。

A at sizes 5 through 20

扩大:

A at sizes 5 through 20, scaled up 3x

事情变得更有趣了,因为并非每个字形都在每次打印中表示,所以虽然"A"在12号点大小上有一个位图,但对于某些字形,最低点大小的显式位图可能是13、15、16、17甚至19。

这意味着您有三个问题:

  1. 字体可能“要求”文本引擎使用其位图,而不是尝试根据文本引擎的算法光栅化矢量轮廓,
  2. 没有神奇的字体大小,可以在此大小以上将所有字符呈现“漂亮”,在此大小以下将所有字符呈现“差”。字体可以具有任意数量的“打印”,包含字体编码字形的任何子集,有效地意味着每个字符都可以有自己的规则,关于文本引擎何时应从栅格化矢量切换到嵌入式位图,和
  3. 文本引擎完全可以完全忽略字体的“要求”,并且无论如何都可以做自己的事情,找出哪个引擎做什么是几乎不可能的,尽管我们可以使用互联网。这是那些似乎没有人记录的事情之一。

找出哪些字体会强制引擎在非常小(有时非常大)的字体大小时使用位图的最简单方法是检查字体是否具有EBDT表-如果有,这种字体将强制引擎使用位图。如果您想了解具体信息,可以通过TTX运行字体,然后找到<EBDT>表开始,以查看实际情况。

但要准备被压倒的感觉。例如,Calibri单独就为超过一千个字形指定了位图。


这些打印不符合9pt-14pt,但你的解释在其他方面是有道理的。我认为所有现代文本渲染引擎都使用矢量渲染(显然是缓存的)-您是否会说大多数字体都使用嵌入式光栅呈现? - jnm2
2
对于专业的TTF-OpenType字体,如Calibri,嵌入式位图将比矢量光栅化器产生的效果要好得多(http://www.rastertragedy.com详细解释了为什么)。因此,良好的文本引擎将利用它们-但并非所有文本引擎都会这样做。而且,仅仅因为你在Windows上运行,并不意味着你总是使用相同的引擎:我认为GDI+使用Uniscribe,但现代版本的Windows将使用Direct2D和DirectWrite。话虽如此,自从Windows 95以来,我就没有为Windows编程了,所以需要验证。 - Mike 'Pomax' Kamermans

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