System.Drawing.DrawString()长字符串的奇怪包装

更新:我想用帮助我解决问题的代码回答我自己的问题。 它是由布拉德利提交的,但调整为我工作,也可以帮助其他人。 但是在重新开放之前我无法回答。 链接的副本提供了一种方法,但没有代码。 基于代码的回答这个问题对社区有帮助

我在控制台应用程序内部的图像上绘制的文本格式有些轻微问题。 我试图绘制的文字是:

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

我的方法调用是:

RectangleF rectF = new RectangleF(0, 0, 320, 320); graphics.DrawString(fullTrav, defaultFont, Brushes.Black, rectF); 

那个输出是:

得到

此输出仅适用于Rectangle的默认StringFormat 。 它包装很好,但它似乎以不同的方式处理字符并在边框之前推送换行符,具体取决于即将发生的字符。 我试过StringFormatFlag.FitBlackBox无济于事,但没有经过每一个标志。

我想得到的是:

想

这个期望的输出看起来更像是方形/矩形并且具有较少的自动换行格式。

有没有办法格式化矩形,以便它不会给文字特殊处理和自动换行纯粹基于文本命中矩形边框的概念?

这个小例子(用LINQPad编写)演示了一种方法来包装打破任何字符的文本。 随意定制它,并改善它(它泄漏一些资源,并可能从右侧截断几个像素),以满足您的需求。

 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(); } 

它产生以下输出:

产量

由@BradleyUffner提供的答案。

解决此问题的唯一方法是测量字符串的每个字符,在行长度达到限制时切断行,然后单独打印每行。

代码如下:

 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; } } 

这段代码包含了我以前在特定字符上打破的可选区域。 为了解释一下,它可以防止它在两个不同的行之间拆分“N4”或“W17”,并且它阻止了一个开头的括号“(”来自一行中的最后一个字符。

成品看起来像:

解决了