System.Drawing.DrawString() weird wrapping of long string

放肆的年华 提交于 2019-12-06 15:30:54

This small example (written in LINQPad) demonstrates a way to wrap text that breaks on any character. Feel free to customize it, and improve it (it leaks some resources, and may truncate a few pixels from the right side) for your needs.

void Main()
{
    var bmp = new Bitmap(320, 320, PixelFormat.Format32bppArgb);
    using (var g = Graphics.FromImage(bmp))
    {
        g.Clear(Color.Gray);

        var str = @"BAS2016=PTR=E30BAS2010=(S20)$W30$PTO2016=N5W20N5(W20N10)(S10W20)S5W5S5E10N10(E15N5)(S5E15)S10E25$W25N10(W15N5)(S5W15)S10W10S15BAS2020=S15PTO2013=S5E20S5(E20S10)(N10E20)N5E5N5W10S10(W15S5)(N5W15)N10W25$E25S10(E15S5)(N5E15)N10E10N15W65$E65N15$.";
        var font = new Font(FontFamily.GenericSansSerif, 10, FontStyle.Regular, GraphicsUnit.Point);           
        int lineIndex=0;
        double lineHeight = font.Height;

        while (str.Length > 0)
        {
            float lineLength = 0;
            int currentChar = 1;

            while (lineLength < bmp.Width - 5 && currentChar <= str.Length)
            {
                string line= str.Substring(0, currentChar);
                lineLength = g.MeasureString(line, font).Width;
                currentChar++;
            }
            g.DrawString(str.Substring(0,currentChar-1),font,Brushes.Black,0,(float)Math.Ceiling(lineIndex*lineHeight),StringFormat.GenericDefault);

            str = str.Substring(currentChar-1);
            lineIndex++;
            currentChar=1;               
        }
    }
    bmp.Dump();
}

It produces the following output:

Answer facilitated by @BradleyUffner.

The only solution to this problem was to measure each character of the string, cutting off the line when the line length hit the limit, and then printing each line individually.

The code is as follows:

using (var graphics = Graphics.FromImage(bmp))
{
    PointF ptF = new PointF(last.textPoints.subCode.X, last.textPoints.subCode.Y + 40);

    int lineIndex = 0;
    double lineHeight = defaultFont.Height;

    while (fullTrav.Length > 0)
    {
        float lineLength = 0;
        int currentChar = 1;
        while (lineLength < 320 && currentChar <= fullTrav.Length)
        {
            string line = fullTrav.Substring(0, currentChar);
            lineLength = graphics.MeasureString(line, defaultFont).Width;
            currentChar++;
        }

        //
        // Optional Code Start
        //
        while (fullTrav[currentChar - 2].ToString().IndexOfAny("(NSEW".ToCharArray()) != -1)
        {
            currentChar--;
        }

        if (currentChar - 1 < fullTrav.Length)
        {
            while (fullTrav[currentChar - 1].ToString().IndexOfAny("1234567890".ToCharArray()) != -1)
            {
                currentChar--;
            }
        }
        //
        // Optional Code End
        //

        graphics.DrawString(fullTrav.Substring(0, currentChar - 1), defaultFont, Brushes.Black, ptF.X, ptF.Y + lineIndex * 20, StringFormat.GenericDefault);

        fullTrav = fullTrav.Substring(currentChar - 1);
        lineIndex++;
        currentChar = 1;

    }
}

This code includes and optional area that I used to break on specific characters only. To explain a little, it prevents it from splitting up "N4" or "W17" between two different lines and it prevents a beginning parenthesis "(" from being the last character in a line.

The finished product looks something like:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!