有没有办法以编程方式确定字体文件是否具有特定的Unicode字形?

Ele*_*hoy 31 vb.net asp.net unicode fonts

我正在开发一个项目,可以生成包含相当复杂的数学和科学公式的PDF.文本以Times New Roman呈现,它具有非常好的Unicode覆盖范围,但不完整.我们有一个系统来交换一个更unicode完整的字体,用于TNR中没有字形的代码点(就像大多数"陌生人"的数学符号一样),但我似乎找不到查询的方法*.ttf文件以查看是否存在给定的字形.到目前为止,我只是硬编码了一个存在代码点的查找表,但我更喜欢自动解决方案.

我在ASP.net下的Web系统中使用VB.Net,但是可以理解任何编程语言/环境中的解决方案.

编辑:win32解决方案看起来很棒,但我试图解决的具体情况是在ASP.Net网络系统中.有没有办法在不将Windows API dll包含到我的网站中的情况下执行此操作?

Sco*_*ols 10

这是使用c#和windows api的传递.

[DllImport("gdi32.dll")]
public static extern uint GetFontUnicodeRanges(IntPtr hdc, IntPtr lpgs);

[DllImport("gdi32.dll")]
public extern static IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

public struct FontRange
{
    public UInt16 Low;
    public UInt16 High;
}

public List<FontRange> GetUnicodeRangesForFont(Font font)
{
    Graphics g = Graphics.FromHwnd(IntPtr.Zero);
    IntPtr hdc = g.GetHdc();
    IntPtr hFont = font.ToHfont();
    IntPtr old = SelectObject(hdc, hFont);
    uint size = GetFontUnicodeRanges(hdc, IntPtr.Zero);
    IntPtr glyphSet = Marshal.AllocHGlobal((int)size);
    GetFontUnicodeRanges(hdc, glyphSet);
    List<FontRange> fontRanges = new List<FontRange>();
    int count = Marshal.ReadInt32(glyphSet, 12);
    for (int i = 0; i < count; i++)
    {
        FontRange range = new FontRange();
        range.Low = (UInt16)Marshal.ReadInt16(glyphSet, 16 + i * 4);
        range.High = (UInt16)(range.Low + Marshal.ReadInt16(glyphSet, 18 + i * 4) - 1);
        fontRanges.Add(range);
    }
    SelectObject(hdc, old);
    Marshal.FreeHGlobal(glyphSet);
    g.ReleaseHdc(hdc);
    g.Dispose();
    return fontRanges;
}

public bool CheckIfCharInFont(char character, Font font)
{
    UInt16 intval = Convert.ToUInt16(character);
    List<FontRange> ranges = GetUnicodeRangesForFont(font);
    bool isCharacterPresent = false;
    foreach (FontRange range in ranges)
    {
        if (intval >= range.Low && intval <= range.High)
        {
            isCharacterPresent = true;
            break;
        }
    }
    return isCharacterPresent;
}
Run Code Online (Sandbox Code Playgroud)

然后,给出一个char toCheck你要检查和一个Font theFont来测试它...

if (!CheckIfCharInFont(toCheck, theFont) {
    // not present
}
Run Code Online (Sandbox Code Playgroud)

使用VB.Net的相同代码

<DllImport("gdi32.dll")> _
Public Shared Function GetFontUnicodeRanges(ByVal hds As IntPtr, ByVal lpgs As IntPtr) As UInteger
End Function  

<DllImport("gdi32.dll")> _
Public Shared Function SelectObject(ByVal hDc As IntPtr, ByVal hObject As IntPtr) As IntPtr
End Function  

Public Structure FontRange
    Public Low As UInt16
    Public High As UInt16
End Structure  

Public Function GetUnicodeRangesForFont(ByVal font As Font) As List(Of FontRange)
    Dim g As Graphics
    Dim hdc, hFont, old, glyphSet As IntPtr
    Dim size As UInteger
    Dim fontRanges As List(Of FontRange)
    Dim count As Integer

    g = Graphics.FromHwnd(IntPtr.Zero)
    hdc = g.GetHdc()
    hFont = font.ToHfont()
    old = SelectObject(hdc, hFont)
    size = GetFontUnicodeRanges(hdc, IntPtr.Zero)
    glyphSet = Marshal.AllocHGlobal(CInt(size))
    GetFontUnicodeRanges(hdc, glyphSet)
    fontRanges = New List(Of FontRange)
    count = Marshal.ReadInt32(glyphSet, 12)

    For i = 0 To count - 1
        Dim range As FontRange = New FontRange
        range.Low = Marshal.ReadInt16(glyphSet, 16 + (i * 4))
        range.High = range.Low + Marshal.ReadInt16(glyphSet, 18 + (i * 4)) - 1
        fontRanges.Add(range)
    Next

    SelectObject(hdc, old)
    Marshal.FreeHGlobal(glyphSet)
    g.ReleaseHdc(hdc)
    g.Dispose()

    Return fontRanges
End Function  

Public Function CheckIfCharInFont(ByVal character As Char, ByVal font As Font) As Boolean
    Dim intval As UInt16 = Convert.ToUInt16(character)
    Dim ranges As List(Of FontRange) = GetUnicodeRangesForFont(font)
    Dim isCharacterPresent As Boolean = False

    For Each range In ranges
        If intval >= range.Low And intval <= range.High Then
            isCharacterPresent = True
            Exit For
        End If
    Next range
    Return isCharacterPresent
End Function  
Run Code Online (Sandbox Code Playgroud)


Ste*_*ken 1

FreeType是一个可以读取 TrueType 字体文件(以及其他文件)并可用于查询字体的特定字形的库。但是,FreeType 是为渲染而设计的,因此使用它可能会导致您引入比该解决方案所需的更多代码。

不幸的是,即使在 OpenType / TrueType 字体领域,也没有真正明确的解决方案;字符到字形的映射有大约十几种不同的定义,具体取决于字体的类型及其最初设计的平台。您可能会尝试查看Microsoft 的OpenType 规范副本中的cmap 表定义,但这并不容易阅读。