How to test that a string can be represented by a font

  • Follow


My app creates a PDF file in a user-specified font.  If a particular string 
contains characters that cannot be represented in that font, the app needs 
to know.  What it then does is to throw the string into an RTF control and 
parses the TextRTF result to see what fonts are used.  It can then switch 
the fonts of the PDF output for the text, or text segments, in line with 
what the RTF control has specified.

However, to do this for every string is quite intensive

The question is how to know if the string can be displayed in its entirety 
by the currently user-specified font so that the RTF logic is only applied 
if it cannot.

This is relatively easy for systems with English codepages and standard 
fonts,  I have created a function "WillFontDisplayString (FontName, 
TextString)" which sets the font of a label to the required text, sets the 
caption equal to the text, and checks the caption against the text.  If they 
are now not equal (because "?" has been substituted for some characters), 
the app knows that it needs to apply the RTF parsing logic.  If the captions 
are equal, we conclude that the font was OK with that string.

The problem comes when Windows does automatic font substitution.  If I 
change the codepage to, say, "Chinese (simplified)" and reboot, then things 
break down.

In this situation, the label test fails because Windows will now place the 
Chinese characters in the label via font substitution (even though the Times 
New Roman font assigned to the label does not support Chinese), so now the 
caption matches the string and the app does not determine that Chinese does 
not fit Times New Roman.

So what I need is a fast and reliable method for the function 
"WillFontDisplayString (FontName, TextString)" which will work universally.

I have Googled for days, but I can find no way of determining that font 
substitution occurred, nor anyway of suppressing font substitution.  It 
seems that the label trick is doomed.   Therefore, I have also searched for 
code snippets that might be equivalent to "WillFontDisplayString", but so 
far no luck.

Does anyone have any ideas?

Thanks in advance,
Nigel 

0
Reply Nigel 9/10/2010 1:56:38 PM

Nigel Bufton <nigel@bufton.org> schrieb im Beitrag
<#GBFIAPULHA.564@TK2MSFTNGP04.phx.gbl>...
> This is relatively easy for systems with English codepages and standard 
> fonts,  I have created a function "WillFontDisplayString (FontName, 
> TextString)" which sets the font of a label to the required text, sets
the 
> caption equal to the text, and checks the caption against the text.  If
they 
> are now not equal (because "?" has been substituted for some characters),

> the app knows that it needs to apply the RTF parsing logic.  If the
captions 
> are equal, we conclude that the font was OK with that string.

The "?" doesn't mean that there is no glyph for the character in the font
used but only that there is no representation for the Unicode character in
the current character set/code page. If there is no glyph for a specific
Unicode character in a font the default glyph (usually a square box) is
displayed instead. This could be checked by some kind of OCR only.

> So what I need is a fast and reliable method for the function 
> "WillFontDisplayString (FontName, TextString)" which will work
universally.

Pass the string to GetGlyphIndices() (Win >= Win 2K only!) with the
GGI_MARK_NONEXISTING_GLYPHS flag set. In the glyph indices array filled by
this procedure any value 0xFFFF means that in the font used there is no
glyph available for the character.
This should be reliable. To make your code fast you should implement some
sort of caching (i.e. a list of characters which already have been checked,
or the like).

-- 
Thorsten Albers

albers (a) uni-freiburg.de

0
Reply Thorsten 9/10/2010 2:44:18 PM


See GetFontUnicodeRanges(Win2000+), or GetTextCharsetInfo(Win95+).

GetFontUnicodeRanges Function:
http://msdn.microsoft.com/en-us/library/dd144887%28VS.85%29.aspx

GetTextCharsetInfo Function:
http://msdn.microsoft.com/en-us/library/dd318126%28VS.85%29.aspx


0
Reply Nobody 9/10/2010 5:58:20 PM

Nobody <nobody@nobody.com> schrieb im Beitrag
<i6drjs$6g5$1@speranza.aioe.org>...
> See GetFontUnicodeRanges(Win2000+), or GetTextCharsetInfo(Win95+).
> 
> GetFontUnicodeRanges Function:
> http://msdn.microsoft.com/en-us/library/dd144887%28VS.85%29.aspx
> 
> GetTextCharsetInfo Function:
> http://msdn.microsoft.com/en-us/library/dd318126%28VS.85%29.aspx

It is very important to remark that even if a certain Unicode range is
supported by a font this does in no case mean that the font provides a
glyph for any (assigned) character of that range.

-- 
Thorsten Albers

albers (a) uni-freiburg.de

0
Reply Thorsten 9/10/2010 10:01:32 PM

"Thorsten Albers" <albersSKIP@THISuni-freiburg.de> wrote in message
news:01cb50f6$9fecbc20$8901a8c0@thalk8s8x...
> Nigel Bufton <nigel@bufton.org> schrieb im Beitrag
>> So what I need is a fast and reliable method for the function
>> "WillFontDisplayString (FontName, TextString)" which will work
> universally.
>
> Pass the string to GetGlyphIndices() (Win >= Win 2K only!) with the
> GGI_MARK_NONEXISTING_GLYPHS flag set. In the glyph indices array filled by
> this procedure any value 0xFFFF means that in the font used there is no
> glyph available for the character.
> This should be reliable. To make your code fast you should implement some
> sort of caching (i.e. a list of characters which already have been
> checked,
> or the like).
>
> -- 
> Thorsten Albers
>
> albers (a) uni-freiburg.de
>

Could you provide example code for declaring and calling GetGlyphIndices
please.  It is not in my API guide.

Thanks,
Nigel 

0
Reply Nigel 9/11/2010 11:54:10 AM

Nigel Bufton <nigel@bufton.org> schrieb im Beitrag
<OHBPNgaULHA.5944@TK2MSFTNGP06.phx.gbl>...
> Could you provide example code for declaring and calling GetGlyphIndices
> please.  It is not in my API guide.

Private Declare Function GetGlyphIndices _
  Lib "gdi32" _
  Alias "GetGlyphIndicesW" _
  ( _
    ByVal hDC As Long, _
    ByVal sChars As Long, _
    ByVal lCharCount As Long, _
    ByRef paGlyphIndices As Any, _
    ByVal lFlags As Long, _
  ) As Long

Private Const GGI_MARK_NONEXISTING_GLYPHS As Long = &H1
Private Const GDI_ERROR As Long = &HFFFFFFFF
Private Const INVALIDGLYPHINDEX As Integer = &HFFFF


Dim sMyString As String
Dim aiGlyphIndex() As Integer
Dim lNumIndices As Long


sMyString$ = "abc"
ReDim aiGlyphIndex(0 To (Len(sMyString$) - 1)) As Integer

Err.Clear
lNumIndices& = GetGlyphIndices(Me.hDC, _
  StrPtr(sMyString$), Len(sMyString$), _
  aiGlyphIndex(0), _
  GGI_MARK_NONEXISTING_GLYPHS)
If lNumIndices& = GDI_ERROR Then
  MsgBox "Last DLL error: " & Err.LastDLLError
ElseIf lNumIndices& < 1 Then
  MsgBox "Number of indices = " & lNumIndices& & "!"
Else

 ' Check aiGlyphIndex() entries on 
 ' INVALIDGLYPHINDEX

End If


This I have written 'on the fly', i.e. online and not in VB...

Be aware of the fact that Unicode codepoints of certain Unicode ranges -
the so-called surrogates - consist of 2 16 bit codes instead of 1 (= 2 VB
string characters instead of 1).

-- 
Thorsten Albers

albers (a) uni-freiburg.de

0
Reply Thorsten 9/11/2010 12:27:00 PM


"Thorsten Albers" <albersSKIP@THISuni-freiburg.de> wrote in message 
news:01cb51ac$98f2e0f0$8901a8c0@thalk8s8x...
> Nigel Bufton <nigel@bufton.org> schrieb im Beitrag
> <OHBPNgaULHA.5944@TK2MSFTNGP06.phx.gbl>...
>> Could you provide example code for declaring and calling GetGlyphIndices
>> please.  It is not in my API guide.
>
> Private Declare Function GetGlyphIndices _
>  Lib "gdi32" _
>  Alias "GetGlyphIndicesW" _
>  ( _
>    ByVal hDC As Long, _
>    ByVal sChars As Long, _
>    ByVal lCharCount As Long, _
>    ByRef paGlyphIndices As Any, _
>    ByVal lFlags As Long, _
>  ) As Long
>
> Private Const GGI_MARK_NONEXISTING_GLYPHS As Long = &H1
> Private Const GDI_ERROR As Long = &HFFFFFFFF
> Private Const INVALIDGLYPHINDEX As Integer = &HFFFF
>
>
> Dim sMyString As String
> Dim aiGlyphIndex() As Integer
> Dim lNumIndices As Long
>
>
> sMyString$ = "abc"
> ReDim aiGlyphIndex(0 To (Len(sMyString$) - 1)) As Integer
>
> Err.Clear
> lNumIndices& = GetGlyphIndices(Me.hDC, _
>  StrPtr(sMyString$), Len(sMyString$), _
>  aiGlyphIndex(0), _
>  GGI_MARK_NONEXISTING_GLYPHS)
> If lNumIndices& = GDI_ERROR Then
>  MsgBox "Last DLL error: " & Err.LastDLLError
> ElseIf lNumIndices& < 1 Then
>  MsgBox "Number of indices = " & lNumIndices& & "!"
> Else
>
> ' Check aiGlyphIndex() entries on
> ' INVALIDGLYPHINDEX
>
> End If
>
>
> This I have written 'on the fly', i.e. online and not in VB...
>
> Be aware of the fact that Unicode codepoints of certain Unicode ranges -
> the so-called surrogates - consist of 2 16 bit codes instead of 1 (= 2 VB
> string characters instead of 1).
>
> -- 
> Thorsten Albers
>
> albers (a) uni-freiburg.de

Thanks - it works great.

Nigel
> 
0
Reply Nigel 9/11/2010 2:08:22 PM

6 Replies
548 Views

(page loaded in 1.066 seconds)

Similiar Articles:
















7/31/2012 7:06:54 AM


Reply: