.net - 使用GDI +,最简单的方法是沿着同一基准对齐文本(以几种不同的字体绘制)?

标签 .net fonts gdi+ alignment baseline

我的问题:

我目前正在使用一个自定义用户控件,该控件在一行上显示文本片段(每个文本可能使用不同的字体)。我想将所有这些文本位精确地沿着一个共同的基线对齐。例如:

  Hello,    I am    George.  
------------------------------   <- all text aligns to a common baseline
    ^         ^        ^
    |         |        |
 Courier    Arial    Times       <- font used for a particular bit of text
  20pt      40pt     30pt

因为我没有找到直接执行此操作的任何GDI +功能,所以我想出了自己的方法(下面概述)。然而:

我想知道是否真的没有更简单的方法来完成此任务?

我目前的做法:

1)收集将用于绘制文本的所有System.Drawing.Font的列表。

2)对于每个Font,使用以下代码找到基线的垂直位置(以像素为单位):
// variables used in code sample (already set)
Graphics G;
Font font;
...

// compute ratio in order to convert from font design units to pixels:
var designUnitsPerPixel = font.GetHeight(G) / 
                          font.FontFamily.GetLineSpacing(font.Style);

// get the cell ascent (baseline) position in design units:
var cellAscentInDesignUnits = font.FontFamily.GetCellAscent(font.Style);

// finally, convert the baseline position to pixels:
var baseLineInPixels = cellAscentInDesignUnits * designUnitsPerPixel;

3)对于所有使用的Font,确定如上计算的最大baseLineInPixels值,并将该值存储到maxBaseLineInPixels

4)通过以下方式绘制文本的每一位:
// variables used in code sample (already set):
Graphics G;
Font font;
string text;
...

// find out how much space is needed for drawing the text
var measureF = G.MeasureString(text, font);

// determine location where text will be drawn:
var layoutRectF = new RectangleF(new PointF(0f, 0f), measureF);
layoutRectF.Y += maxBaseLineInPixels - baseLineInPixels;
// ^ the latter value 'baseLineInPixels' is specific to the font used

// draw text at specified location
G.DrawString(text, font, Brushed.Black, layoutRectF);

我是否缺少某些东西,或者真的没有更简单的方法吗?

最佳答案

我认为这种方式是行之有效的,请您尝试。

List<RectangleF> rects = new List<RectangleF>();

private void Form1_Paint(object sender, PaintEventArgs e)
{
    ////////////////////Not Set baseLine
    //baseline
    e.Graphics.DrawLine(Pens.Red , new Point(100,200),new Point(800,200));

    //words
    Point point = new Point(100,100);
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, point);
    RectangleF rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30)));
    e.Graphics.DrawRectangle(Pens.Green,rectangleF.X ,rectangleF.Y , rectangleF.Width , rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(400, 100);
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, point);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40)));
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(800, 100);
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, point);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20)));
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    ///////////////////SetBaseLine/////////////////////////////
    var maxHeight = GetMaxHeight();
    ///////////////////

    //baseLine
    e.Graphics.DrawLine(Pens.Pink, new Point(100, (int) (400 + maxHeight / 2)), new Point(800, (int) (400 + maxHeight / 2)));

    StringFormat stringFormat = new StringFormat();
    stringFormat.LineAlignment = StringAlignment.Center;

    //words
    point = new Point(100, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Times", 30)));
    e.Graphics.DrawString("hello world", new Font("Times", 30), Brushes.Black, new RectangleF(rectangleF.X ,rectangleF.Y , rectangleF.Width , maxHeight) , stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(400, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Arial", 40)));
    e.Graphics.DrawString("hello world", new Font("Arial", 40), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

    point = new Point(800, 400);
    rectangleF = new RectangleF(point, e.Graphics.MeasureString("hello world", new Font("Courier", 20)));
    e.Graphics.DrawString("hello world", new Font("Courier", 20), Brushes.Black, new RectangleF(rectangleF.X, rectangleF.Y, rectangleF.Width, maxHeight), stringFormat);
    e.Graphics.DrawRectangle(Pens.Green, rectangleF.X, rectangleF.Y, rectangleF.Width, rectangleF.Height);
    rects.Add(rectangleF);

}

private float GetMaxHeight()
{
    float temp = 0;
    foreach (RectangleF rectangleF in rects)
        if (rectangleF.Height > temp)
            temp = rectangleF.Height;

    return temp;
}

关于.net - 使用GDI +,最简单的方法是沿着同一基准对齐文本(以几种不同的字体绘制)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2133411/

相关文章:

javascript - Google 图表自定义字体无法正确呈现 - Firefox

.net - 在多线程中使用 GDI+ 的问题 (VB.NET)

.NET、SqlConnection 对象和多线程

c# - 如何使用 { get; 访问私有(private)变量放; }

c# - 'System.ServiceModel.Diagnostics.TraceUtility' 的类型初始值设定项

使用 apache POI 导出 Excel 让我抓狂

.net - 无法通过命令行构建混合解决方案(.NET Framework 与 .NET Standard)

css - 在 CSS 中使用自定义字体

.net - 将 png 缩小到比原来大的大小

c++ - Gdiplus::Bitmap::FromHBITMAP 内存泄漏