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" между двумя разными строками, а также предотвращает использование скобок в начале "(" последний символ в строке ".

Готовый продукт выглядит примерно так:

решена

Другие вопросы по тегам