I'm filtering fonts using the Panose.FontFamily Type, which I get using:
[System.Runtime.InteropServices.DllImport("gdi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Ansi)]
private static extern int GetOutlineTextMetricsA(IntPtr hdc, int cbData, IntPtr lpOtm);
However, I'm starting with a System.Windows.Media.FontFamily. Coming from the list: System.Windows.Media.Fonts.SystemFontFamilies
I haven't found a way to get the hDC for a Media.FontFamily. Therefore, I need to match it to System.Drawing.FontFamily. Coming from the list: System.Drawing.FontFamily.Families
The only way I've found to map a Media.FontFamily to a Drawing.FontFamily is by comparing Media.FontFamily.Source to Drawing.FontFamily.Name. Which is not perfect since their respective names often don't exactly match. I figure I'm getting a match for at least 90% of the fonts.
Using a Drawing.FontFamily does have a way to get the hDC of a font.
A decent solution will be a better way (other than by name) to map a Media.FontFamily to Drawing.FontFamily. An ideal solution would to get an hDC directly from a Media.FontFamily. Another ideal solution would be to get the OUTLINETEXTMETRICS struct without needing to import the base method. A perfect solution would be getting the panose family type from a Media.FontFamily with involving a Drawing.FontFamily or importing a method.
First, I get the list of Media.FontFamily like this:
foreach (Media.FontFamily font in Media.Fonts.SystemFontFamilies.OrderBy(_ => _.Source))
Then I get the list of Drawing.FontFamily like this:
System.Collections.IEnumerator fontIter = Draw.FontFamily.Families.OrderBy(_ => _.Name).GetEnumerator();
Then I compare the Media.FontFamily.Source to the Drawing.FontFamily.Name. I've found that Drawing.FontFamily.Name contains Media.FontFamily.Source quite often. After getting the Drawing.FontFamily, it's an easy step to convert it to a Drawing.Font:
Draw.Font drawFont = new Draw.Font(drawFamily, 9.0F);
And from that I get the Panose Family Type:
enum PanoseFontFamilyTypes
{
PAN_ANY = 0, PAN_NO_FIT = 1, PAN_FAMILY_TEXT_DISPLAY = 2, PAN_FAMILY_SCRIPT = 3,
PAN_FAMILY_DECORATIVE = 4, PAN_FAMILY_PICTORIAL = 5
}
public PanoseFontFamilyTypes PanoseFontFamilyType(Draw.Font font)
{
byte bFamilyType = 0;
IntPtr hdc = (IntPtr)0;
IntPtr hFontOld;
try
{
hdc = GraphTool.GetHdc();
hFontOld = SelectObject(hdc, font.ToHfont());
int bufSize = GetOutlineTextMetricsA(hdc, 0, (IntPtr)0);
IntPtr lpOtm = System.Runtime.InteropServices.Marshal.AllocCoTaskMem(bufSize);
System.Runtime.InteropServices.Marshal.WriteInt32(lpOtm, bufSize);
int success = GetOutlineTextMetricsA(hdc, bufSize, lpOtm);
if (success != 0)
{
int offset = 61;
bFamilyType = System.Runtime.InteropServices.Marshal.ReadByte(lpOtm, offset);
}
System.Runtime.InteropServices.Marshal.FreeCoTaskMem(lpOtm);
SelectObject(hdc, hFontOld);
}
catch (Exception ex)
{
MessageBox.Show($"Message: {ex.Message}\r\nStackTrace:\r\n{ex.StackTrace}", "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
finally
{
GraphTool.ReleaseHdc(hdc);
}
return (PanoseFontFamilyTypes)bFamilyType;
}
Looking for a less convoluted solution.
CodePudding user response:
I never did find a way to map a Media.FontFamily to a Drawing.FontFamily that did not involve a string comparison. However, I did find a more reliable way to do the mapping. The problem is that Media.FontFamily.Source (the font name) often does not exactly correspond to a Drawing.FontFamily.Name.
Media.FontFamily font=<your font>;
Typeface face = new Typeface(font, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
if (face.TryGetGlyphTypeface(out GlyphTypeface typeFace))
{
Drawing.FontFamily drawFont = Drawing.FontFamily.Families.FirstOrDefault(_o => typeFace.Win32FamilyNames.Any(_i => _i.Value.Equals(_o.Name, StringComparison.OrdinalIgnoreCase)));
return new Tuple<FontUtility.OutlineTextMetric, bool>(GetOutlineTextMetric(drawFont, fontData), typeFace.Symbol);
}
The GetOutlineTextMetric method Gets the OUTLINETEXTMETRIC using the code found here: http://pinvoke.net/default.aspx/gdi32/GetOutlineTextMetrics.html
The name in Win32FamilyNames does map exactly to a Drawing.FontFamily.Name. I was able to get rid of the contains string algorithm I was using.
This also has the added benefit of getting the Symbol boolean, which at least for every font I have installed is 100% accurate to identify a symbol font. (e.g. wingdings)