how to measure width of a string precisely?

后端 未结 4 1291
伪装坚强ぢ
伪装坚强ぢ 2020-12-16 05:56

First of all, question How to measure width of character precisely? which is answered, doesn\'t really help for this case, so this isn\'t a duplicate of that.

相关标签:
4条回答
  • 2020-12-16 06:27

    Try to use this methods:

    GDI+ (graphics.MeasureString and graphics.DrawString) >> System.Drawing.Graphics
    GDI (TextRenderer.MeasureText and TextRenderer.DrawText)
    

    It also may help you:

    Write a custom measure method:

    • Split entry string on special characters
    • Use above .net methods
    • Calculate width of special characters and sum ...

    Read Ian Boyd answer

    0 讨论(0)
  • 2020-12-16 06:27

    A method using Graphics.MeasureCharacterRanges to return all the rectangles enclosing each individual letter in a string and their positions is given here: Measure character positions when drawing long strings in C#

    I have used the MeasureCharactersInWord and MeasureCharacters methods from that post, then in order to find the exact width without the spaces added to each side of the string, I use this code:

    var w = 0F;
    var rects = MeasureCharacters(Graphics.FromHwnd(IntPtr.Zero), font, text);
    if (rects.Count>0)
    {
        if (rects.Count == 1)
        {
            w = rects.First().Width;
        }
        else
        {
            var r0 = rects.First();
            var rN = rects.Last();
            w = rN.X - r0.X + rN.Width;
        }
    }
    

    Note that the height of the rectangle is the height of the font and not of the character itself. If you need the height check this post: Determining exact glyph height in specified font

    A final note: the reason why I used MeasureCharacterRanges is because all the other methods I tried were failing at giving me a bounding box without space to the left and right of the text. This post The wonders of text rendering and GDI gives a method to get the string width and remove this space using TextRenderer so the whole thing can be done in about two lines of code. I haven't checked the result though.

    0 讨论(0)
  • 2020-12-16 06:30

    You just need to eliminate extra width. You can do this by using string format:

    GdipStringFormatGetGenericTypographic()
    

    You could also use:

    float doubleWidth = g.MeasureString(text+text,...).Width;
    float singleWidth = g.MeasureString(text).Width;
    float textWidth = doubleWidth-singleWidth;
    

    This will allow you to work with other languages such as Japanese.

    On codeproject, Pierre Anaud's solution was to use MeasureCharacterRanges, which returns a region matching exactly the bounding box of the specified string:

    static public int MeasureDisplayStringWidth(Graphics graphics, string text, Font font)
    {
        System.Drawing.StringFormat format  = new System.Drawing.StringFormat ();
        System.Drawing.RectangleF   rect    = new System.Drawing.RectangleF(0, 0, 1000, 1000);
        var ranges  = new System.Drawing.CharacterRange(0, text.Length);
        System.Drawing.Region[] regions = new System.Drawing.Region[1];
    
        format.SetMeasurableCharacterRanges (ranges);
    
        regions = graphics.MeasureCharacterRanges (text, font, rect, format);
        rect    = regions[0].GetBounds (graphics);
    
        return (int)(rect.Right + 1.0f);
    }
    
    0 讨论(0)
  • 2020-12-16 06:30

    I'm a little late to the party here, but I was trying to do something similar and stumbled on this question. You've probably already seen the following remark from the documentation for the Graphics.MeasureString method on MSDN:

    The MeasureString method is designed for use with individual strings and includes a small amount of extra space before and after the string to allow for overhanging glyphs. Also, the DrawString method adjusts glyph points to optimize display quality and might display a string narrower than reported by MeasureString. To obtain metrics suitable for adjacent strings in layout (for example, when implementing formatted text), use the MeasureCharacterRanges method or one of the MeasureString methods that takes a StringFormat, and pass GenericTypographic. Also, ensure the TextRenderingHint for the Graphics is AntiAlias.

    It seems that you were trying to follow this advice because you're using StringFormat.GenericTypographic as a starting point for your custom StringFormat object. However, the line

    format.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
    

    effectively negates the fact that you started with StringFormat.GenericTypographic because it clears any previously set flags. What you probably meant to do is set the StringFormatFlags.MeasureTrailingSpaces flag while preserving the other flags, like so:

    format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
    
    0 讨论(0)
提交回复
热议问题