使用.NET创建TrueType字体文件的子集

3

我正在尝试实现以下目标:

  1. 创建仅针对特定字符的原始字体文件子集
  2. 通过浏览 Google,我找到了以下可用的API:
    • WPFGlyphTypeface类的ComputeSubset方法
    • FontSub.dll中的CreateFontPackage
  3. 虽然我能够创建字体文件的一个子集,但是我不确定它是否针对我指定的字符,因为当我打开该文件(双击文件)时,我看到所有字符都在那里。如何确切地验证这一点? 我将其安装在c:\windows\fonts中,并且我能够输入该字体的所有字符,而我期望它只显示我选择的字符。
  4. 是否有适用于TrueType字体(TTF)文件的程序员参考资料,帮助我们从编程角度了解TTF文件?
2个回答

3
如果您有兴趣学习TTF规范,可以参考Microsoft TrueType规范v1.66。请访问http://www.microsoft.com/typography/SpecificationsOverview.mspx
您可能会感兴趣的字体表是CMAP表,它指定了字符代码到字形索引的映射。
但是,如果您只想验证子集化的TTF字体是否包含正确的字符,我认为参考规范有些过头了。
我建议使用工具将字体内容转储为可读格式。有一个名为TTX的工具,可以输出给定字体的字体表的XML表示形式。请访问http://www.letterror.com/code/ttx/index.html
一旦您运行了TTX,就可以运行命令“ttx.exe -tcmap MyFont.ttf”,然后它应该会输出一个名为“MyFont.ttx”的文件。在文本编辑器中打开它,它应该会显示您在字体中找到的所有字符代码。
针对Ujjwal的问题更新:
1. 我没有使用.NET处理字体的经验;很抱歉无法帮助您解决.NET的问题。
2. Otaku提供的Apple链接比Microsoft规范更易于阅读;只需注意,在某些方面,TTF格式的Apple和Microsoft规范略有不同。
3. 通常,我会说字体的大小取决于保留字符字形的复杂程度以及是否保留了hinting数据。从我看到的字体来看,这些数据占据了TTF字体的大部分空间。(实际上,嵌入式位图占用更多空间,但根据您提到的字体大小,我敢打赌它不包含嵌入式位图)
4. 不确定这是否有用,但如果您无法使用.NET更改字体名称,则可能会对查找名为FontForge的工具http://fontforge.sourceforge.net/感兴趣。我自己没有真正使用过它,但我相信它应该可以让您更改字体名称。

是的,FontForge 是一个很棒的工具。它有修改字体名称和字体族的功能。事实上,我正在尝试构建一个简单的工具(使用 C#.net),类似于 FontForge,但只针对非常有限的功能。 - Ujjwal

3

我使用过你提到的两种方法,第一种更容易。这是我使用的代码:

Imports System.Text.Encoding
Imports System.Collections
Imports System.Windows.Media
Public Class FontManager
    Sub New()
        CreateSubSet("my baloney has a first name", New Uri("C:\Windows\Fonts\impact.ttf"))
    End Sub
    Public Sub CreateSubSet(sourceText As String, fontURI As Uri)
        Dim glyphTypeface As GlyphTypeface = New GlyphTypeface(fontURI)
        Dim Index As Generic.ICollection(Of UShort)
        Index = New Generic.List(Of UShort)
        Dim sourceTextBytes As Byte() = Unicode.GetBytes(sourceText)
        Dim sourceTextChars As Char() = Unicode.GetChars(sourceTextBytes)
        Dim sourceTextCharVal As Integer
        Dim glyphIndex As Integer
        For sourceTextCharPos = 0 To UBound(sourceTextChars)
            sourceTextCharVal = AscW(sourceTextChars(sourceTextCharPos))
            glyphIndex = glyphTypeface.CharacterToGlyphMap(sourceTextCharVal)
            Index.Add(glyphIndex)
        Next
        Dim filebytes() As Byte = glyphTypeface.ComputeSubset(Index)
        Using fileStream As New System.IO.FileStream("C:\Users\Me\Documents\impact-subset.ttf", System.IO.FileMode.Create)
            fileStream.Write(filebytes, 0, filebytes.Length)
        End Using
    End Sub
End Class

当然,对于sourceText,如果您愿意,可以只发送唯一的字符。

Gilamesh提到的链接是学习TTF字体的好地方。我发现另一个非常有价值的参考资料是http://developer.apple.com/fonts/TTRefMan/RM06/Chap6.html


感谢@otaku和@gilamesh。还有几个问题:
  1. 如果我选择子集字体(输入到CreateSubSet的“1234”,输出文件:subset.ttf),我希望除了1、2、3和4之外的字符不会显示(例如在MS Word中)。这是正确的期望吗?
  2. 使用GlyphTypeface类的ComputeSubset函数是否足够?还是我需要做一些额外的事情,比如删除不必要的查找表?是否有可用的API?
  3. 字体文件的大小缩小与我们传递的字符成比例吗?
  4. 我可以修改字体名称和字体系列吗?
- Ujjwal
只是为了让自己更清楚,如何验证使用此函数创建的字体子集?我想确保字体子集仅支持我在子集化原始字体时选择的字符。 - Ujjwal
@Ujjwal:以下是我对你问题的回答。1) 并不是它们不会被显示,而是因为它们在你的子集字体中不存在,所以无法显示, 2) 这已经足够了,我一直在使用, 3) 不总是成比例的,但明显要小得多, 4) 不是用这种方法。为此,您必须进行P/Invoke调用-请参见此页面以获取示例。 - Todd Main
1
.otf字体文件会导致文件复制。我做错了什么吗? - Yarl
我不确定,Hugo,我已经好几年没看过这个了。 - Todd Main

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