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

回眸只為那壹抹淺笑 提交于 2020-01-03 03:06:08

问题


Update: I would like to answer my own question with code that helped me solve the issue. It was submitted by Bradley but tweaked to work for me and may help others as well. But I can't answer until it is reopened. The linked duplicate provides a method, but no code. A code based answer to this question would be helpful to the community

I'm having some slight issues with the formatting of the text drawn on an image inside of my console application. The text I'm trying to draw is:

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$.

My method call is:

RectangleF rectF = new RectangleF(0, 0, 320, 320);

graphics.DrawString(fullTrav, defaultFont, Brushes.Black, rectF);

The output from that is:

This output is only with whatever is the default StringFormat for the Rectangle. It wraps fine but it seems to treat characters differently and pushes newlines before the border, depending on what characters are upcoming. I've tried StringFormatFlag.FitBlackBox to no avail but haven't gone through each and every flag.

What I want to get is:

This desired output is one that looks more like a square/rectangle and has less word wrap formatting.

Is there a way to format the Rectangle so that it will not give characters special treatment and word wrap purely on the concept of when text hits the Rectangle border?


回答1:


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:




回答2:


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:



来源:https://stackoverflow.com/questions/45337074/system-drawing-drawstring-weird-wrapping-of-long-string

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