Измерение ширины чисел в растровых изображениях

#c# #.net #bitmap #character

#c# #.net #растровое изображение #символ

Вопрос:

Я создал текстуру (растровое изображение), которая используется для рисования произвольных чисел

Текстура содержит текст: 0123456789.-

Фактическое изображение

Теперь мне нужны координаты каждого символа.

TextRenderer.MeasureText(c.ToString(), m_font, new Size(1, 1), TextFormatFlags.NoPadding);

… возвращает значение 16×17

g.MeasureString(c.ToString(), m_font);

…возвращает значение 11.9×17.7

Фактический размер 8×11

Мой обходной путь на данный момент — это ручное измерение каждого символа, которое дает следующую таблицу:
coords.Add('0', new RectangleF(1, 3, 8, 11));
coords.Add('1', new RectangleF(9, 3, 7, 11));
coords.Add('2', new RectangleF(15, 3, 8, 11));
coords.Add('3', new RectangleF(22, 3, 8, 11));
coords.Add('4', new RectangleF(29, 3, 8, 11));
coords.Add('5', new RectangleF(36, 3, 8, 11));
coords.Add('6', new RectangleF(43, 3, 8, 11));
coords.Add('7', new RectangleF(50, 3, 8, 11));
coords.Add('8', new RectangleF(57, 3, 8, 11));
coords.Add('9', new RectangleF(64, 3, 8, 11));
coords.Add('.', new RectangleF(72, 3, 3, 11));
coords.Add('-', new RectangleF(75, 3, 6, 11));

Я хотел бы использовать динамический шрифт, поэтому требуется программный способ измерения размера.

Комментарии:

1. я думаю, вам придется искать больше перегрузок. представьте, что вы пытаетесь измерить i. откуда вы знаете, что точка является частью i, а не отдельным символом. Возможно, вы получаете неожиданные значения, потому что они также включают высоту строки при вызове функции.

Ответ №1:

Укажите методу MeasureString для работы с общим типографским строковым форматом.

 static void Main(string[] args)
        {
            var image = new Bitmap(1000, 500);

            var g = Graphics.FromImage(image);
            g.FillRectangle(System.Drawing.Brushes.White, 0, 0, 1000, 500);

            var stringFormat = new StringFormat(StringFormat.GenericTypographic) {
                 Alignment = StringAlignment.Near,
                 FormatFlags = System.Drawing.StringFormatFlags.LineLimit | System.Drawing.StringFormatFlags.NoClip | StringFormatFlags.DirectionRightToLeft
            };

            var font = new Font(new System.Drawing.FontFamily("Times New Roman"), 72.0f,FontStyle.Regular, GraphicsUnit.Point);
            var point = new PointF { X = 10, Y = 10 };

            SizeF[] outputs = new SizeF[7];
            SizeF[] total = new SizeF[7];
            outputs[0] = g.MeasureString("T", font, point, stringFormat);
            outputs[1] = g.MeasureString("e", font, point, stringFormat);
            outputs[2] = g.MeasureString("s", font, point, stringFormat);
            outputs[3] = g.MeasureString("t", font, point, stringFormat);
            outputs[4] = g.MeasureString("S", font, point, stringFormat);
            outputs[5] = g.MeasureString("t", font, point, stringFormat);
            outputs[6] = g.MeasureString("r", font, point, stringFormat);

            total[0] = g.MeasureString("T", font, point, stringFormat);
            total[1] = g.MeasureString("Te", font, point, stringFormat);
            total[2] = g.MeasureString("Tes", font, point, stringFormat);
            total[3] = g.MeasureString("Test", font, point, stringFormat);
            total[4] = g.MeasureString("TestS", font, point, stringFormat);
            total[5] = g.MeasureString("TestSt", font, point, stringFormat);
            total[6] = g.MeasureString("TestStr", font, point, stringFormat);

            stringFormat.FormatFlags = System.Drawing.StringFormatFlags.LineLimit | System.Drawing.StringFormatFlags.NoClip;

            g.DrawString("TestStr", font, System.Drawing.Brushes.Red, new PointF { X = 10, Y = 10 }, stringFormat);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 0), 10.0f, outputs[0].Width, outputs[0].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 1), 10.0f, outputs[1].Width, outputs[1].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 2), 10.0f, outputs[2].Width, outputs[2].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 3), 10.0f, outputs[3].Width, outputs[3].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 4), 10.0f, outputs[4].Width, outputs[4].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 5), 10.0f, outputs[5].Width, outputs[5].Height);
            g.DrawRectangle(new System.Drawing.Pen(System.Drawing.Brushes.Blue, 1.0f), GetOutputPositionX(total,outputs, 6), 10.0f, outputs[6].Width, outputs[6].Height);

            image.Save(@"c:Tempbla.png");

        }
        private static float GetOutputPositionX(SizeF[] total, SizeF[] outputs, int p)
        {
            return 10.0f   total[p].Width - outputs[p].Width;
        }
 

Чтобы получить точную позицию, из-за этих перекрывающихся символов вам нужно вычислить ширину буквы «e» и общую ширину буквы «Te».

Кроме того, очевидно, что в функции MeasureString есть ошибка. Если вы вызываете MeasureString без StringFormatFlags .DirectionRightToLeft перекрытие символов «Te» игнорируется.

введите описание изображения здесь

Комментарии:

1. Я не могу заставить это работать. Я взял точный код и поместил его в новое решение, но выравнивание зеленой сетки в моем случае неверно. Не могли бы вы проверить еще раз?

2. @testalino Не могли бы вы добавить свое выходное изображение.

3. @testalino Я уже тестировал в приложении WPF, и оно работало нормально. В консольном приложении GDI перекрывает символы «Te». Чего по какой-либо причине не происходит в приложении WPF. Я обновил свой код. Теперь должно сработать.

4. Хорошо, большое вам спасибо за работу, которую вы вложили в это. Я могу получить тот же результат, что и вы, при использовании вашего кода. Хотя в моей среде это все еще не работает, потому что, когда вы уменьшаете размер шрифта, рамка внезапно перестает соответствовать буквам, возможно, из-за округления до пикселей. Это особенно актуально при использовании моего фактического шрифта (Tahoma, 10): i.imgur.com/egBQLn6.png