How to compute the correct width of a digit in pixels?

Small adjustments are required to make this work as intended:

  1. TextRenderingHint.ClearTypeGridFit gives a better result when rendering the Text.
    It’s more precise and works well with the grid-fitting nature of Graphics.DrawString.
    See the notes you can find in the answer linked below for more informations on this matter.
  2. StringFormat alignment in both horizontal and vertical dimensions.
  3. A modified method that allows to draw strings of any length.
    If the string is larger than the container, it will be wrapped, with the current settings.
  4. Irrelevant: Brush and Pen are declared outside the Paint event, to allow their re-definition when required.

Different implementations of MeasureCharacterRanges here:
How to highlight wrapped text in a control

About Graphics.DrawString and TextRenderingHint.ClearTypeGridFit:
Drawing a Long String on to a Bitmap results in Drawing Issues


Font 48em:
MeasureCharacterRanges 1

Font 16em:
MeasureCharacterRanges 2

Font 9em:
MeasureCharacterRanges 3

Pen pen = new Pen(Color.LightGreen, 1);
Brush brush = new SolidBrush(Color.White);
string sourceDigits = "010011001";

private void panel1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

    CharacterRange[] charRanges = new CharacterRange[sourceDigits.Length];
    for (int chx = 0; chx < sourceDigits.Length; ++chx) {
        charRanges[chx] = new CharacterRange(chx, 1);
    }

    using (StringFormat sf = new StringFormat())
    {
        sf.Alignment = StringAlignment.Center;
        sf.LineAlignment = StringAlignment.Center;
        sf.SetMeasurableCharacterRanges(charRanges);

        Region[] regions = e.Graphics.MeasureCharacterRanges(sourceDigits, Font, e.ClipRectangle, sf);
        for (int i = 0; i < regions.Length; i++) {
            RectangleF rect = regions[i].GetBounds(e.Graphics);
            e.Graphics.DrawRectangle(pen, rect.X, rect.Y, rect.Width, rect.Height);
            e.Graphics.DrawString(char.ToString(sourceDigits[i]), Font, brush, rect, sf);
        }
    }
}

Leave a Comment