Правильно рисовать текст с использованием графического контура - PullRequest
0 голосов
/ 30 октября 2018

Как вы можете видеть на изображении ниже, текст на картинке отличается от текста на картинке. Это работает нормально, если я использую Graphics.DrawString(), но когда я использую Графический путь, он усекается и не показывает весь текст. Что вы думаете не так в моем коде?

enter image description here

Вот мой код:

public LayerClass DrawString(LayerClass.Type _text, string text, RectangleF rect, Font _fontStyle, PaintEventArgs e)
{
    using (StringFormat string_format = new StringFormat())
    {
        rect.Size = e.Graphics.MeasureString(text, _fontStyle);
        rect.Location = new PointF(Shape.center.X - (rect.Width / 2), Shape.center.Y - (rect.Height / 2));
        if(isOutlinedOrSolid)
        {
            using (GraphicsPath path = new GraphicsPath())
            {
                path.AddString(text, _fontStyle.FontFamily, (int)_fontStyle.Style, rect.Size.Height, rect, string_format);
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
                e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
                e.Graphics.CompositingMode = CompositingMode.SourceOver;
                e.Graphics.DrawPath(new Pen(Color.Red, 1), path);
            }
        }
        else
        {
            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
            e.Graphics.CompositingMode = CompositingMode.SourceOver;
            e.Graphics.DrawString(text,_fontStyle,Brushes.Red, rect.Location);
        }
    }

    this._Text = text;
    this._TextRect = rect;
    return new LayerClass(_text, this, text, rect);
}

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Класс GraphicsPath вычисляет размер объекта Text другим способом (как уже отмечалось в комментариях). Размер текста рассчитывается с использованием размера ограничивающего прямоугольника Ems.
Em - это типографская мера, которая не зависит от контекста устройства назначения.
Это относится к прямоугольнику, занимаемому самой широкой буквой шрифта, обычно буквой «М» (произносится em ).

Размер назначения Em может быть рассчитан двумя различными способами: один включает Font descent, другой не включает его. Последнее чаще встречается (так как «М» не имеет descent частей).

float EMSize = (Font.Height * [FontFamly].GetCellAscent([FontStyle]) 
                            / [FontFamily].GetEmHeight([FontStyle]

или

float EMSize = (Font.Height * ([FontFamly].GetCellAscent([FontStyle] + 
                               [FontFamily.GetCellDescent([FontStyle])) 
                             / [FontFamily].GetEmHeight([FontStyle]

См. Документы о:
FontFamily.GetEmHeight , FontFamily.GetCellAscent и FontFamily.GetCellDescent

Я вставляю сюда рисунок, который вы можете найти в Документах.

Font Ascent-Descent

См. Общую информацию, содержащуюся здесь:
Использование шрифта и текста (MSDN)

В этом документе рассказывается о том, как переводить баллы, пиксели и символы:
Как: получить метрику шрифта (MSDN)


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

Этот класс выполняет некоторые вычисления на основе размера шрифта, выбранного пользователем.
Размер шрифта обычно указывается в Points. Затем эта мера преобразуется в Pixels с использованием текущего разрешения экрана DPI (или преобразуется в Points из измерения Pixel). Каждая мера также конвертируется в Ems, что очень удобно, если вам нужно использовать GraphicsPath для рисования текста.

Размер Ems рассчитывается с учетом Ascent и Descent шрифта. GraphicsPath лучше работает с этой мерой, поскольку смешанный текст может иметь обе части, а если нет, то эта часть равна = 0.

Чтобы рассчитать контейнер контейнера для текста, нарисованного с определенным размером шрифта и шрифта, используйте метод GraphicsPath.GetBounds () :
([Canvas] - это элемент управления, который предоставляет e.Graphics объект Paint)

using (GraphicsPath path = new GraphicsPath())
using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
{
    format.Alignment = [StringAlignment.Center/Near/Far]; //As selected
    format.LineAlignment = [StringAlignment.Center/Near/Far]; //As selected
    //Add the Text to the GraphicsPath
    path.AddString(fontObject.Text, fontObject.FontFamily, 
                   (int)fontObject.FontStyle, fontObject.SizeInEms, 
                   [Canvas].ClientRectangle, format);
    //Ems size (bounding rectangle)
    RectangleF TextBounds = path.GetBounds(null, fontObject.Outline);
    //Location of the Text
    fontObject.Location = TextBounds.Location;
}

Нарисуйте текст на устройстве [Canvas] Контекст:

private void Canvas_Paint(object sender, PaintEventArgs e)
{
    using (GraphicsPath path = new GraphicsPath())
    using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
    {
        format.Alignment = [StringAlignment.Center/Near/Far]; //As selected
        format.LineAlignment = [StringAlignment.Center/Near/Far]; //As selected

        path.AddString(fontObject.Text, fontObject.FontFamily, (int)fontObject.FontStyle, fontObject.SizeInEms, Canvas.ClientRectangle, format);

        e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
        e.Graphics.CompositingMode = CompositingMode.SourceOver;
        e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;

        if (fontObject.Outlined) { 
            e.Graphics.DrawPath(fontObject.Outline, path);
        }
        using(SolidBrush brush = new SolidBrush(fontObject.FillColor)) {
            e.Graphics.FillPath(brush, path);
        }
    }
}

Визуальный эффект с использованием этого класса и методов realted:

Font Outline Example

Объект класса, для использования в качестве ссылки:

public class FontObject
{
    private float CurrentScreenDPI = 0.0F;
    private float m_SizeInPoints = 0.0F;
    private float m_SizeInPixels = 0.0F;
    public FontObject() 
        : this(string.Empty, FontFamily.GenericSansSerif, FontStyle.Regular, 18F) { }
    public FontObject(string Text, Font font) 
        : this(Text, font.FontFamily, font.Style, font.SizeInPoints) { }
    public FontObject(string Text, FontFamily fontFamily, FontStyle fontStyle, float FontSize)
    {
        if (FontSize < 3) FontSize = 3;
        using (Graphics g = Graphics.FromHwndInternal(IntPtr.Zero)) {
            this.CurrentScreenDPI = g.DpiY; 
        }
        this.Text = Text;
        this.FontFamily = fontFamily;
        this.SizeInPoints = FontSize;
        this.FillColor = Color.Black;
        this.Outline = new Pen(Color.Black, 1);
        this.Outlined = false;
    }

    public string Text { get; set; }
    public FontStyle FontStyle { get; set; }
    public FontFamily FontFamily { get; set; }
    public Color FillColor { get; set; }
    public Pen Outline { get; set; }
    public bool Outlined { get; set; }
    public float SizeInPoints {
        get => this.m_SizeInPoints;
        set {  this.m_SizeInPoints = value;
               this.m_SizeInPixels = (value * 72F) / this.CurrentScreenDPI;
               this.SizeInEms = GetEmSize();
        }
    }
    public float SizeInPixels {
        get => this.m_SizeInPixels;
        set {  this.m_SizeInPixels = value;
               this.m_SizeInPoints = (value * this.CurrentScreenDPI) / 72F;
               this.SizeInEms = GetEmSize();
        }
    }

    public float SizeInEms { get; private set; }
    public PointF Location { get; set; }
    public RectangleF DrawingBox { get; set; }

    private float GetEmSize()
    {
        return (this.m_SizeInPoints * 
               (this.FontFamily.GetCellAscent(this.FontStyle) +
                this.FontFamily.GetCellDescent(this.FontStyle))) /
                this.FontFamily.GetEmHeight(this.FontStyle);
    }
}

Редактировать

ComboBox с семействами шрифтов.

Настройка OwnerDraw ComboBox:

string[] FontList = FontFamily.Families.Where(f => f.IsStyleAvailable(FontStyle.Regular)).Select(f => f.Name).ToArray();

cboFontFamily.DrawMode = DrawMode.OwnerDrawVariable;
cboFontFamily.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
cboFontFamily.AutoCompleteSource = AutoCompleteSource.CustomSource;
cboFontFamily.AutoCompleteCustomSource.AddRange(FontList);
cboFontFamily.DisplayMember = "Name";
cboFontFamily.Items.AddRange(FontList);
cboFontFamily.Text = "Arial";

Обработчики событий:

private void cboFontFamily_DrawItem(object sender, DrawItemEventArgs e)
{
    TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
    using (FontFamily family = new FontFamily(cboFontFamily.GetItemText(cboFontFamily.Items[e.Index])))
    using (Font font = new Font(family, 10F, FontStyle.Regular, GraphicsUnit.Point)) {
        TextRenderer.DrawText(e.Graphics, family.Name, font, e.Bounds, cboFontFamily.ForeColor, flags);
    }
    e.DrawFocusRectangle();
}

private void cboFontFamily_MeasureItem(object sender, MeasureItemEventArgs e)
{
    e.ItemHeight = (int)this.Font.Height + 4;
}

private void cboFontFamily_SelectionChangeCommitted(object sender, EventArgs e)
{
    fontObject.FontFamily = new FontFamily(cboFontFamily.GetItemText(cboFontFamily.SelectedItem));
    Canvas.Invalidate();
}
0 голосов
/ 30 октября 2018

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

using (GraphicsPath path = new GraphicsPath())
{
    path.AddString(
        text,                         
        _fontStyle.FontFamily,      
        (int)_fontStyle.Style,      
        e.Graphics.DpiY * fontSize / 72f,       // em size
        new Point(0, 0),                       // location where to draw text
        string_format);          

    e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
    e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
    e.Graphics.CompositingMode = CompositingMode.SourceOver;
    e.Graphics.DrawPath(new Pen(Color.Red), path);
}
...