System.Drawing.DrawString() странное перенос длинной строки
Обновление: я хотел бы ответить на свой вопрос с кодом, который помог мне решить проблему. Он был представлен Брэдли, но настроен на работу для меня и может помочь другим. Но я не могу ответить, пока он не будет открыт. Связанный дубликат предоставляет метод, но не код. Кодовый ответ на этот вопрос будет полезен для сообщества
У меня возникли небольшие проблемы с форматированием текста, нарисованного на изображении внутри моего консольного приложения. Текст, который я пытаюсь нарисовать:
BAS2016 = ПТР =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);
Выход из этого:
Этот вывод только с тем, что является StringFormat по умолчанию для Rectangle. Он прекрасно переносится, но, похоже, обрабатывает символы по-разному и переносит символы новой строки до границы, в зависимости от того, какие символы появятся в будущем. Я пробовал StringFormatFlag.FitBlackBox безрезультатно, но не прошел каждый флаг.
Что я хочу получить это:
Этот желаемый результат выглядит более похожим на квадрат / прямоугольник и имеет меньшее форматирование переноса слов.
Есть ли способ отформатировать прямоугольник так, чтобы он не придавал символам особой обработки и переноса слов исключительно по концепции, когда текст достигает границы прямоугольника?
2 ответа
Этот небольшой пример (написанный на 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" между двумя разными строками, а также предотвращает использование скобок в начале "(" последний символ в строке ".
Готовый продукт выглядит примерно так: