Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining exact glyph height in specified font

I have searched a lot and tried much but I can not find the proper solution.

I wonder is there any approach for determining exact glyph height in specified font?

I mean here when I want to determine the height of DOT glyph I should receive small height but not height with paddings or the font size.

I have found the solution for determining exact glyph width here (I have used the second approach) but it does not work for height.

UPDATE: I need solution for .NET 1.1

like image 242
Michael Z Avatar asked Mar 29 '12 11:03

Michael Z


People also ask

How do I know if a font has glyphs?

The easy way to know what is in a font's character set is by viewing the software's glyph panel. For any font, begin by selecting the Entire Font option. From there, view the submenus, investigating categories of glyphs you might be interested in. (These categories closely mirror those in the OpenType panel.)

What is a glyph in a font?

A glyph is a single representation of a character. Every font has a Unicode character map that links (abstract) character IDs with how to display that character, using the default glyphs.

How do I create a glyph font?

Hold Shift and press Return or double-click on the selection to create glyphs for all selected cells. Hold Shift and select the Font > Generate Glyphs menu command. See Generate Glyphs for details. Select the Font > Add Glyphs menu command to add several Unicode glyphs at once.

Is glyph a set of fonts?

A glyph is a specific form of a character. For example, in certain fonts, the capital letter A is available in several forms, such as swash and small cap. You can use the Glyphs panel to locate any glyph in a font. OpenType fonts such as Adobe Caslon™ Pro provide multiple glyphs for many standard characters.


2 Answers

It's not that hard to get the character metrics. GDI contains a function GetGlyphOutline that you can call with the GGO_METRICS constant to get the height and width of the smallest enclosing rectangle required to contain the glyph when rendered. I.e, a 10 point glyph for a dot in font Arial will give a rectangle of 1x1 pixels, and for the letter I 95x.14 if the font is 100 points in size.

These are the declaration for the P/Invoke calls:

// the declarations
public struct FIXED
{
    public short fract;
    public short value;
}

public struct MAT2
{
    [MarshalAs(UnmanagedType.Struct)] public FIXED eM11;
    [MarshalAs(UnmanagedType.Struct)] public FIXED eM12;
    [MarshalAs(UnmanagedType.Struct)] public FIXED eM21;
    [MarshalAs(UnmanagedType.Struct)] public FIXED eM22;
}

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int x;
    public int y;
}

[StructLayout(LayoutKind.Sequential)]
public struct POINTFX
{
    [MarshalAs(UnmanagedType.Struct)] public FIXED x;
    [MarshalAs(UnmanagedType.Struct)] public FIXED y;
}

[StructLayout(LayoutKind.Sequential)]
public struct GLYPHMETRICS
{

    public int gmBlackBoxX;
    public int gmBlackBoxY;
    [MarshalAs(UnmanagedType.Struct)] public POINT gmptGlyphOrigin;
    [MarshalAs(UnmanagedType.Struct)] public POINTFX gmptfxGlyphOrigin;
    public short gmCellIncX;
    public short gmCellIncY;

}

private const int GGO_METRICS = 0;
private const uint GDI_ERROR = 0xFFFFFFFF;

[DllImport("gdi32.dll")]
static extern uint GetGlyphOutline(IntPtr hdc, uint uChar, uint uFormat,
   out GLYPHMETRICS lpgm, uint cbBuffer, IntPtr lpvBuffer, ref MAT2 lpmat2);

[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);

The actual code, rather trivial, if you don't consider the P/Invoke redundancies. I tested the code, it works (you can adjust for getting the width as well from GLYPHMETRICS).

Note: this is ad-hoc code, in the real world, you should clean up the HDC's and objects with ReleaseHandle and DeleteObject. Thanks to a comment by user2173353 to point this out.

// if you want exact metrics, use a high font size and divide the result
// otherwise, the resulting rectangle is rounded to nearest int
private int GetGlyphHeight(char letter, string fontName, float fontPointSize)
{
    // init the font. Probably better to do this outside this function for performance
    Font font = new Font(new FontFamily(fontName), fontPointSize);
    GLYPHMETRICS metrics;

    // identity matrix, required
    MAT2 matrix = new MAT2
        {
            eM11 = {value = 1}, 
            eM12 = {value = 0}, 
            eM21 = {value = 0}, 
            eM22 = {value = 1}
        };

    // HDC needed, we use a bitmap
    using(Bitmap b = new Bitmap(1,1))
    using (Graphics g = Graphics.FromImage(b))
    {
        IntPtr hdc = g.GetHdc();
        IntPtr prev = SelectObject(hdc, font.ToHfont());
        uint retVal =  GetGlyphOutline(
             /* handle to DC   */ hdc, 
             /* the char/glyph */ letter, 
             /* format param   */ GGO_METRICS, 
             /* glyph-metrics  */ out metrics, 
             /* buffer, ignore */ 0, 
             /* buffer, ignore */ IntPtr.Zero, 
             /* trans-matrix   */ ref matrix);

        if(retVal == GDI_ERROR)
        {
            // something went wrong. Raise your own error here, 
            // or just silently ignore
            return 0;
        }


        // return the height of the smallest rectangle containing the glyph
        return metrics.gmBlackBoxY;
    }    
}
like image 73
Abel Avatar answered Oct 15 '22 02:10

Abel


Can you update the question to include what you have tried ?

By dot glyph I assume you mean the punctuation mark detailed here ?

Is this Glyph height displayed on screen or a printed page ?

I managed to modify the first method in the link you posted in order to count the matching vertical pixels, however identifying the largest height of the glyph is fiddly to do unless you are willing to draw character by character, so this wasn't really a general working solution like the article.

In order to have a general working solution would need identify the largest single pixel vertical region of the character / glyph, then count the number of pixels in that region.

I also managed to verify that Graphics.MeasureString, TextRenderer.MeasureText and Graphics.MeasureCharacterRanges all returned the bounding box which gave a number similar to the font height.

The alternative to this is to Glyph.ActualHeight property which gets the rendered height of the framework element. This part of WPF and the related GlyphTypeface and GlyphRun classes. I wasn't able to test them at this time having only Mono.

The steps for getting Glyph.ActualHeight are as follows

  1. Initialise the arguments for GlyphRun

  2. Initialise GlyphRun object

  3. Access relevant Glyph using glyphTypeface.CharacterToGlyphMap[text[n]] or more correctly glyphTypeface.GlyphIndices[n], where glyphTypeface is your GlyphTypeface, which is created from the Typeface object you make in Step 1.

Relevant resources on using them include

  • The Thing about Glyphs
  • GlyphRun and So Forth
  • Measuring Text
  • Glyphs Particularly the picture the bottom.

Futher references on GDI (What these classes use under the hood is GDI or GDI+) and Fonts in Windows include

  • GDI
  • Windows Font Mapping
like image 2
Appleman1234 Avatar answered Oct 15 '22 03:10

Appleman1234