2015-05-19 6 views
4

У меня проблема с функциями C# GDI + draw string - я не могу получить точный размер моей нарисованной строки - без внутреннего ведущего и внешнего, только em em height. API-интерфейсы для шрифтов/строк, предоставленные Microsoft, по-видимому, всегда выводят ограничивающий прямоугольник, который на несколько пикселей больше, чем текст, даже после того, как я удалил внутреннюю строку.GDI +, Удалить пустое пространство из Graphics DrawString()

private void pictureBox1_Paint(object sender, PaintEventArgs e) 
    { 
     Graphics g = e.Graphics; 
     g.Clear(Color.Black); 
     String text = "The quick brown fox jumps over the lazy dog"; 
     Font font = new System.Drawing.Font(FontFamily.GenericSerif, 24); 
     float internalLeading = font.Size * (font.FontFamily.GetCellAscent(font.Style) + font.FontFamily.GetCellDescent(font.Style) - font.FontFamily.GetEmHeight(font.Style))/font.FontFamily.GetEmHeight(font.Style); 
     StringFormat format = StringFormat.GenericTypographic; 
     format.Trimming = StringTrimming.None; 
     format.FormatFlags = StringFormatFlags.NoWrap; 
     System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, pictureBox1.Width,pictureBox1.Height); 
     System.Drawing.CharacterRange[] ranges = { new System.Drawing.CharacterRange(0, text.Length) }; 
     System.Drawing.Region[] boundings = new System.Drawing.Region[1]; 
     format.SetMeasurableCharacterRanges(ranges); 
     boundings = g.MeasureCharacterRanges(text, font, rect, format); 
     rect = boundings[0].GetBounds(g); 
     g.DrawString(text, font, new SolidBrush(Color.Red), new RectangleF(0,0,rect.Width,rect.Height), format); 
     g.DrawRectangle(Pens.Yellow, rect.X, rect.Y + internalLeading, rect.Width, rect.Height - internalLeading); 
    } 

И выход показан ниже. Мы можем видеть, что между текстом и верхним краем ограничивающей рамки все еще имеется несколько пикселей.

enter image description here

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

+1

Как правило, я использую типографский параметр. Но чтобы получить пиксельный точный ограничивающий прямоугольник, я думаю, вам нужно использовать GraphicsPath и получить его границы. – TaW

+0

Ahh, GraphicsPath, спасибо! Я попробую! – ncite

ответ

4

GDI + обрабатывает больше, чем просто английский, а высота линии фиксированы (представьте себе ужас, если каждая линия была высота текста на этой линии).

Ограничительная коробка также учитывает различные диакритики, которые могут украшать эти персонажи, включая похожие вещи на английском языке, например, в COÖPERATE.

См:

Diaresis and diacritis

Обратите внимание, как диарез (¨) едва вписывается в ограничительной рамки, и ˇ вполне очевидно, снаружи - и все же, в нижней части, там достаточно места, чтобы соответствовать q. Что дает? Ну, MeasureString предназначен для форматирования текста, а не для получения минимально возможного прямоугольника, текст которого может быть визуализирован, что, конечно же, будет осложнено вещами, которые не должны изменять способ выравнивания текста, например, используя ClearType.

Функция построена на основе предположения, что вам очень нравится иметь линии одинаковой высоты - так обычно отображается весь текст.

Цитирую MSDN непосредственно:

Метод MeasureString предназначен для использования с отдельными строками и включает в себя небольшое количество дополнительного пространства до и после строки, чтобы позволить нависающих глифы. Кроме того, метод DrawString настраивает глифные точки для оптимизации качества отображения и может отображать строку, уже указанную MeasureString.

+0

Спасибо, по крайней мере теперь я могу понять, почему функции ничейной строки так сложно играть! – ncite

+1

@ ncite Да, это один из тех очень сложных предметов, которые кажутся действительно простыми на поверхности, такими как дата/время (что так сложно показывать дату и время ?!) или многопоточность: D – Luaan

-1

Тест этот путь:

var size = g.MeasureString(text, font); 
pictureBox1.Size = new Size((int)size.Width, (int)size.Height); 
Смежные вопросы