有没有办法以编程方式确定字体文件是否具有特定的 Unicode 字形? [英] Is there a way to programmatically determine if a font file has a specific Unicode Glyph?
问题描述
我正在开展一个项目,该项目可生成包含相当复杂的数学和科学公式的 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屋!