代码之家  ›  专栏  ›  技术社区  ›  Codo

如何正确地将文本与抽绳左对齐?

  •  0
  • Codo  · 技术社区  · 7 年前

    我正在将文本绘制为屏幕外位图。不幸的是,文本没有正确地左对齐(见下图)。文本应该接触左边距(蓝线),但会偏离几个像素。距离随着文本大小的增加而增加。

    Left alignment

    我怎样才能摆脱这种距离?

    我使用的是.NETFramework4.6.1。但这似乎更像是一个我不理解的一般GDI+问题。

    using System.Drawing;
    using System.Drawing.Imaging;
    
    namespace LeftAlignment
    {
        class Program
        {
            static void Main(string[] args)
            {
                const int LeftMargin = 10;
    
                // create off-screen bitmap
                using (Bitmap bitmap = new Bitmap(300, 100))
                {
                    // create graphics context
                    using (Graphics graphics = Graphics.FromImage(bitmap))
                    {
                        // clear bitmap
                        graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
    
                        // draw border and left margin
                        graphics.DrawRectangle(Pens.Gray, new Rectangle(0, 0, bitmap.Width - 1, bitmap.Height - 1));
                        graphics.DrawLine(Pens.Blue, LeftMargin, 8, LeftMargin, 92);
    
                        // draw string at 24 pt
                        Font font = new Font("Arial", 24);
                        graphics.DrawString("Cool water", font, Brushes.Black, LeftMargin, 8);
    
                        // draw string at 36 pt
                        font = new Font("Arial", 36);
                        graphics.DrawString("Cool water", font, Brushes.Black, LeftMargin, 44);
                    }
    
                    // save result as PNG
                    bitmap.Save("alignment.png", ImageFormat.Png);
                }
            }
        }
    }
    
    2 回复  |  直到 7 年前
        1
  •  5
  •   Ringo Store    7 年前

    据说,微软在GDI+中添加了填充,以便于实现控件。老GDI没有这个问题。

    当微软意识到这是一个错误时,他们添加了 TextRenderer class 这绕过了GDI+并使用了更好的GDI实现。

    据推测,填充物左侧为1/6 em,右侧为1/4 em。

    您有两个选择:

    1. 使用 TextRenderer.DrawText . 然而,它是 Windows窗体 . 所以它在.NET标准和.NET核心中都不可用。

    2. 使用 Graphics.DrawString 带着神奇的选择 StringFormat.GenericTypographic . 它神奇地去除了填充物。

        2
  •  1
  •   Codo    7 年前

    MeasureCharacterRanges 测量由添加的填充 DrawString . 结果看起来很糟糕:

    Improved left alignment

    正如你所见,它并不完美。蓝线和字母“C”之间仍然有一些空白,因为测量的矩形包括所谓的 左侧轴承 ,即在两个字符之间添加的空白的左侧。

    所以我仍然在寻找更好的解决方案。除了测量的衬垫外,还可以计算轴承并减去轴承的一半。希望它在.NET标准2.0中是可行的。。。

    填充=0.002312554字体大小分辨率

    (填充以像素为单位,字体大小以磅为单位,分辨率以像素/英寸为单位)

    例如:对于24pt字体和96dpi的图形分辨率,填充为5.33像素。

    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Drawing.Imaging;
    using System.Drawing.Text;
    
    namespace LeftAlignment
    {
        class Program
        {
            static void ImprovedDrawString(Graphics graphics, string text, Font font, float x, float y)
            {
                // measure left padding
                StringFormat sf = new StringFormat(StringFormatFlags.NoClip);
                sf.SetMeasurableCharacterRanges(new CharacterRange[] { new CharacterRange(0, 1) });
                Region[] r = graphics.MeasureCharacterRanges(text, font, new RectangleF(0, 0, 1000, 100), sf);
                float leftPadding = r[0].GetBounds(graphics).Left;
    
                // draw string
                sf = new StringFormat(StringFormatFlags.NoClip);
                graphics.DrawString(text, font, Brushes.Black, x - leftPadding, y, sf);
            }
    
            static void Main(string[] args)
            {
                const int LeftMargin = 10;
                const string Text = "Cool water";
    
                // create off-screen bitmap
                using (Bitmap bitmap = new Bitmap(300, 100))
                {
                    // create graphics context
                    using (Graphics graphics = Graphics.FromImage(bitmap))
                    {
                        // enable high-quality output
                        graphics.SmoothingMode = SmoothingMode.AntiAlias;
                        graphics.TextRenderingHint = TextRenderingHint.AntiAlias;
    
                        // clear bitmap
                        graphics.FillRectangle(Brushes.White, 0, 0, bitmap.Width, bitmap.Height);
    
                        // draw border and left margin
                        graphics.DrawRectangle(Pens.Gray, new Rectangle(0, 0, bitmap.Width - 1, bitmap.Height - 1));
                        graphics.DrawLine(Pens.Blue, LeftMargin, 8, LeftMargin, 92);
    
                        // draw string at 24 pt
                        Font font = new Font("Arial", 24);
                        ImprovedDrawString(graphics, Text, font, LeftMargin, 8);
    
                        // draw string at 36 pt
                        font = new Font("Arial", 36);
                        ImprovedDrawString(graphics, Text, font, LeftMargin, 44);
                    }
    
                    // save result as PNG
                    bitmap.Save("alignment.png", ImageFormat.Png);
                }
            }
        }
    }