有没有办法以编程方式确定字体文件是否具有特定的 Unicode 字形? [英] Is there a way to programmatically determine if a font file has a specific Unicode Glyph?

查看:17
本文介绍了有没有办法以编程方式确定字体文件是否具有特定的 Unicode 字形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开展一个项目,该项目可生成包含相当复杂的数学和科学公式的 PDF.文本以 Times New Roman 格式呈现,Unicode 覆盖率相当不错,但并不完整.我们有一个系统可以为在 TNR 中没有字形的代码点(如大多数陌生人"数学符号)交换更完整的 Unicode 字体,但我似乎找不到查询的方法*.ttf 文件以查看是否存在给定的字形.到目前为止,我只是对存在哪些代码点的查找表进行了硬编码,但我更喜欢自动解决方案.

I'm working on a project that generates PDFs that can contain fairly complex math and science formulas. The text is rendered in Times New Roman, which has pretty good Unicode coverage, but not complete. We have a system in place to swap in a more Unicode complete font for code points that don't have a glyph in TNR (like most of the "stranger" math symbols,) but I can't seem to find a way to query the *.ttf file to see if a given glyph is present. So far, I've just hard-coded a lookup table of which code points are present, but I'd much prefer an automatic solution.

我在 ASP.net 下的 Web 系统中使用 VB.Net,但将不胜感激任何编程语言/环境中的解决方案.

I'm using VB.Net in a web system under ASP.net, but solutions in any programming language/environment would be appreciated.

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

The win32 solution looks excellent, but the specific case I'm trying to solve is in an ASP.Net web system. Is there a way to do this without including the windows API DLLs into my web site?

推荐答案

这是使用 c# 和 windows API 的一个过程.

Here's a pass at it using c# and the 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;
}

然后,给定一个要检查的字符 toCheck 和一个用于测试它的字体 theFont...

Then, given a char toCheck that you want to check and a Font theFont to test it against...

if (!CheckIfCharInFont(toCheck, theFont) {
    // not present
}

同样的代码使用 VB.Net

Same code using 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  

这篇关于有没有办法以编程方式确定字体文件是否具有特定的 Unicode 字形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆