Bitmap与OnPaintBackground中的TextRenderer.DrawText

时间:2009-05-11 18:58:59

标签: c# textrenderer

如果我使用OnPaintBackground中提供的Graphics对象使用TextRenderer.DrawText(),我的文本看起来很完美。如果我创建自己的Bitmap并使用从我的Bitmap获得的Graphics对象,我的文本看起来很糟糕。看起来它使用黑色对文本进行抗锯齿处理,而不是位图的背景颜色。如果我使用Graphics.DrawString(),我可以避免这个问题,但这种方法有可怕的字距调整问题。我该怎么办?如何使用Bitmap的内容正确地将TextRenderer.DrawText()转换为反别名?

看起来很可怕:

Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(g, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}

看起来不错,但我想将其渲染到位图上,而不是渲染到控件的表面上:

protected override void OnPaintBackground(PaintEventArgs e)
{
e.Graphics.Clear(Color.Red);
TextFormatFlags tf = TextFormatFlags.Left;
TextRenderer.DrawText(e.Graphics, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
}

有什么区别?

6 个答案:

答案 0 :(得分:9)

答案是不使用TextRenderer。 TextRenderer是文本呈现的GDI(非GDI +)实现的包装器,它具有许多功能,但是与您发现的内存DC不能很好地互操作。

使用Graphics.DrawString& Graphics.MeasureString,但请记住将其传递给StringFormat.GenericTypographic以获得准确的大小和位置。

最初引入TextRenderer的原因是GDI +不支持GDI的Uniscribe引擎所做的所有复杂脚本。然而,随着时间的推移,GDI +对复杂脚本的支持已经扩展,现在没有任何好的理由可以使用TextRenderer(它甚至不再是两者中更快的,事实上它恰好相反)。

但是,除非您遇到严重的,可测量的性能问题,否则只需使用Graphics.DrawString

答案 1 :(得分:3)

我认为问题是如果背景是透明的,则清晰类型的文本渲染不起作用。一些可能的解决方案。

选项1.使用颜色填充位图的背景。

如果你这样做(正如Tim Robinson在他的代码示例中通过使用g.Clear(Color.Red)所做的那样),clear type将做正确的事情。但是你的位图不会完全透明,这可能是不可接受的。如果您使用Graphics.MeasureText,您可以根据需要填充文本周围的矩形。

选项2.设置TextRenderingHint = TextRenderingHintAntiAliasGridFit

这似乎关闭了清除类型。文本将在背景上以低于透明类型的质量呈现,但是比没有背景的乱画类型更好。

选项3.用白色填充文本矩形,绘制文本,然后找到所有非文本像素并将它们放回透明。

using (Bitmap bmp = new Bitmap(someWidth, someHeight))
{
    using (Graphics g = Graphics.FromImage(bmp))
    {
        // figure out where our text will go
        Point textPoint = new Point(someX, someY);
        Size textSize = g.MeasureString(someText, someFont).ToSize();
        Rectangle textRect = new Rectangle(textPoint, textSize);

        // fill that rect with white
        g.FillRectangle(Brushes.White, textRect);

        // draw the text
        g.DrawString(someText, someFont, Brushes.Black, textPoint);

        // set any pure white pixels back to transparent
        for (int x = textRect.Left; x <= textRect.Left + textRect.Width; x++)
        {
            for (int y = textRect.Top; y <= textRect.Top + textRect.Height; y++)
            {
                Color c = bmp.GetPixel(x, y);
                if (c.A == 255 && c.R == 255 && c.G == 255 && c.B == 255)
                {
                    bmp.SetPixel(x, y, Color.Transparent);
                }
            }
        }
    }
}

我知道,这是一个可怕的黑客,但似乎有效。

答案 2 :(得分:2)

答案是使用BuffersGraphicsContext这是在控件上设置ControlStyles.OptimizedDoubleBuffer样式时.NET内部使用的系统。

有关.NET中双缓冲的更多信息,请参阅http://msdn.microsoft.com/en-us/library/b367a457.aspx

答案 3 :(得分:0)

另一种可能的解决方案:将整个事物绘制到屏幕上,在顶部显示文本的位图,然后将一些代码写入“屏幕截图”屏幕的那一部分。在所有情况下都不实用,但你是对的,DrawString创建了奇怪的文本,而DrawText在位图上看起来很糟糕。

答案 4 :(得分:-1)

如果您的位图与显示区域的大小不同,则可能只是一个调整大小的问题,.NET会将位图缩放到显示大小,并且您会看到有趣的文本。

您可以使用与显示区域大小相同的位图进行测试吗?

答案 5 :(得分:-1)

你能发布遭受这个问题的最小程序吗?我无法像这样重现它 - 抗锯齿看起来很好:

    using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

public class Program
{
    public static void Main()
    {
        Bitmap bmp = new Bitmap(100, 100, PixelFormat.Format32bppArgb);
        using (Font font = new Font("Arial", 10, GraphicsUnit.Point))
        using (Graphics g = Graphics.FromImage(bmp))
        {
            Rectangle clip = Rectangle.FromLTRB(0, 0, 100, 100);
            g.Clear(Color.Red);
            TextFormatFlags tf = TextFormatFlags.Left;
            TextRenderer.DrawText(g, @"C:\Development\Testing\blag", font, clip, Color.White, Color.Transparent, tf);
        }

        Form form = new Form();
        form.BackgroundImage = bmp;
        Application.Run(form);
    }
}