是什么导致 Calibri 在 9 到 14 pt 之间丢失 ClearType?

What is causing Calibri to lose ClearType between 9 and 14 pt?

当使用 9pt 和 14pt 之间的默认 Microsoft Office 字体 Calibri 并指定 ClearTypeGridFit 时,到底是什么让 GDI+ 切换到二进制别名?

这有点令人不安。有多少其他字体也受到这背后的影响,大小是多少?有解决方法吗? (不包括 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;
        }
    }
}

Calibri 带有一个 EBLC table and EBDT table,它告诉文本引擎对于某些磅值,它们不应该尝试 "their own scaling algorithms",而应该使用直接存储在字体中的位图, 相反。

每个字体大小都可以有自己的 "the following glyphs must be bitmapped at this size" 列表,称为 "strike",因此一个字形可以有多个位图用于多个大小(但可能会有间隙,当这种情况发生时位图需要缩放,事情可以 catastrophically wrong).

例如,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 的字体大小时,我们 运行 会遇到问题:突然我们必须缩放位图。这只会出错。

如果你看一下写字板之类的东西,你会发现微软的 Uniscribe engine (used with GDI+; the modern equivalent is Direct2D with DirectWrite 作为文本引擎,而不是)可以很好地缩小这些位图(显示尺寸为 5 到 20),但即使是微软自己的技术有明显的局限性。我们看到字体大小为 5、6 和 7 像素时,位图非常糟糕,甚至 8、10 和 11 看起来也有点不稳定:

放大:

事情变得更有趣了,因为并非每个字形都在每次击打中都表示,所以虽然 "A" 有一个点大小为 12 的位图,但有些字形的最小点大小可能是 13 , 或 15, 或 16, 或 17, 甚至 19.

这意味着你遇到了三个问题:

  1. 字体可能 "demand" 文本引擎使用其位图,而不是尝试根据文本引擎的算法对矢量轮廓进行栅格化,并且
  2. 没有神奇的字体大小,超过它所有字符都呈现 "nicely" 和小于它所有字符呈现 "poorly"。一种字体可以有任意数量的 "strikes",包含字体编码字形的任何子集,这实际上意味着每个字符都可以有自己的规则,说明文本引擎何时应该从光栅化矢量切换到嵌入位图,并且
  3. 文本引擎完全可以自由地完全忽略字体的 "demands" 并做自己的事情,尽管我们可以使用互联网,但要找出哪个引擎做的是什么,这几乎是不可能的。这是似乎没有人记录的事情之一。

找出哪些字体会执行此操作的最简单方法是简单地检查字体是否有 EBDT table - 如果有,此字体将强制引擎使用位图来显示非常小的 (有时非常大)字体大小。如果你想要具体的,你可以通过TTX运行字体,然后找到<EBDT>table开始,看看到底是怎么回事。

准备好被淹没吧。例如,仅 Calibri 就有为超过一千个字形指定的位图。