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

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

问题描述

我正在研究一个能够包含相当复杂的数学和科学公式的PDF文件。该文本呈现在Times New Roman中,具有相当不错的Unicode覆盖范围,但并不完整。我们有一个系统来替换在TNR中没有字形的代码点更多的Unicode字体完整字体(像大多数陌生人的数学符号),但我似乎无法找到一种方法来查询* .ttf文件来查看给定的字形是否存在。到目前为止,我只是硬编码了一个查找表,其中的代码点是存在的,但我更喜欢自动解决方案。



我使用VB .net在ASP.net下的网络系统,但任何编程语言/环境的解决方案将不胜感激。编辑:win32解决方案看起来不错,但具体情况我试图解决的是在一个ASP.Net网络系统。有没有办法做到这一点,而不包括Windows API DLL到我的网站?

解决方案

这是通过使用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高;
}

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();
返回fontRanges;

$ b $ public bool CheckIfCharInFont(char character,Font font)
{
UInt16 intval = Convert.ToUInt16(character);
List< FontRange> ranges = GetUnicodeRangesForFont(font);
bool isCharacterPresent = false;
foreach(范围范围)
{
if(intval> = range.Low&& intval< = range.High)
{
isCharacterPresent = true;
break;
}
}
返回isCharacterPresent;





$ b然后,给一个char检查,你想检查一个字体theFont ($!

$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $




$ b

使用VB.Net的相同代码

 < DllImport(gdi32.dll)> _ 
公共共享函数GetFontUnicodeRanges(ByVal hds As IntPtr,ByVal lpgs As IntPtr)As UInteger
End Function

< DllImport(gdi32.dll)> _
作为IntPtr
结束功能公共共享功能SelectObject(ByVal hDc作为IntPtr,ByVal hObject作为IntPtr)

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 =新列表(字体范围)
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(范围)
下一个

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

返回fontRanges
结束函数

公共函数CheckIfCharInFont(ByVal字符为Char,ByVal字体为Font) b $ b Dim intval As UInt16 = Convert.ToUInt16(character)
Dim range As List(Of FontRange)= GetUnicodeRangesForFont(font)
Dim isCharacterPresent As Boolean = False

For Each range In范围
如果intval> = range.Low And intval< = range.High然后
isCharacterPresent = True
退出对于
结束如果
下一个范围
返回isCharacterPresent
结束函数


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.

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

Edit: 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?

解决方案

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;
}

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

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

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天全站免登陆