Graphics.MeasureString doesn't include some parts of some chars
Asked Answered
S

0

1

I'm using this method to generate bitmaps from strings:

private Bitmap ConvertTextToImage(string text, FontFamily fontFamily, float fontSize,
    FontStyle fontStyle = FontStyle.Regular, StringFormat stringFormat = default,
    float MaxWidth = float.MaxValue, float MaxHeight = float.MaxValue, float xDpi = 72, float yDpi = 72,
    Color backgroundColor = default, Color foregroundColor = default)
{
    if (text == "") return null;
    Bitmap bitmap = new Bitmap(1, 1);
    Graphics graphics = Graphics.FromImage(bitmap);
    if (stringFormat == default) stringFormat = new StringFormat();
    if (backgroundColor == default) backgroundColor = Color.Transparent;
    if (foregroundColor == default) foregroundColor = Color.Black;

    Font font = new Font(fontFamily, fontSize, fontStyle);

    SizeF stringSize = graphics.MeasureString(text, font, int.MaxValue, stringFormat);
    while (stringSize.Width > MaxWidth || stringSize.Height > MaxHeight)
    {
        fontSize -= (float)0.1;
        font = new Font(fontFamily, fontSize, fontStyle);
        stringSize = graphics.MeasureString(text, font, int.MaxValue, stringFormat);
    }

    bitmap = new Bitmap((int)stringSize.Width, (int)stringSize.Height);
    graphics = Graphics.FromImage(bitmap);
    graphics.CompositingQuality = CompositingQuality.HighQuality;
    graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
    graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
    graphics.SmoothingMode = SmoothingMode.HighQuality;
    graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

    bitmap.SetResolution(xDpi,yDpi);
    graphics.Clear(backgroundColor);
    
    int x = 0;
    if (stringFormat.FormatFlags == StringFormatFlags.DirectionRightToLeft && stringFormat.Alignment == StringAlignment.Center)
        x = (int)stringSize.Width / 2;
    else if (stringFormat.FormatFlags == StringFormatFlags.DirectionRightToLeft) x = (int)stringSize.Width;
    else if (stringFormat.Alignment == StringAlignment.Center) x += (int)stringSize.Width / 2;

    graphics.DrawString(text, font, new SolidBrush(foregroundColor), x, 0, stringFormat);

    return bitmap;
}

It works well but sometimes it doesn't generate some parts of characters when using IranNastaliq font. For example, look at that persian character 'گ' which is at start of a string (highlighted part was in original picture and not created by GDI). The circled part should be much longer:
enter image description here
and this one. Circled dot is cropped (Also at start of a string):
enter image description here
I think Graphics.MeasureString doesn't measure those parts. I can add some space characters at start but it causes some other problems. How should I fix it?

Saffren answered 3/9, 2020 at 9:5 Comment(2)
It is a typographic feature called "glyph overhang", makes measuring the width of characters a perilous affair. Use StringFormatFlags.NoClip when you render to try to get ahead.Aquifer
@HansPassant It made things better but still some parts of گ is invisible.Saffren

© 2022 - 2024 — McMap. All rights reserved.