8

如果我使用我的文本中提供TextRenderer.DrawText()Graphics对象OnPaintBackground看起来很完美。如果我创建自己的Bitmap并使用Graphics从我Bitmap的文本中获得的对象看起来很糟糕。看起来它是使用黑色而不是位图的背景颜色对文本进行抗锯齿处理。如果我使用 ,我可以避免这个问题Graphics.DrawString(),但是这种方法有可怕的字距调整问题。我该怎么办?如何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);
}

有什么不同?

4

6 回答 6

9

答案是不使用TextRenderer。TextRenderer 是文本渲染的 GDI(不是 GDI+)实现的包装器,它具有许多功能,但与您发现的内存中 DC 的互操作性不佳。

使用Graphics.DrawString& Graphics.MeasureString,但记得传递 StringFormat.GenericTypographic 以获得准确的大小和定位。

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

但实际上,除非您遇到严重的、可衡量的性能问题,否则只需使用Graphics.DrawString.

于 2009-10-16T13:31:51.540 回答
3

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

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

如果你这样做(正如蒂姆罗宾逊在上面的代码示例中使用 g.Clear(Color.Red) 所做的那样),清除类型将做正确的事情。但是您的位图不会完全透明,这可能是不可接受的。如果您使用 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);
                }
            }
        }
    }
}

我知道,这是一个可怕的黑客,但它似乎工作。

于 2010-07-15T20:29:36.723 回答
2

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

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

于 2011-10-28T12:04:43.380 回答
0

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

于 2010-04-08T20:55:54.977 回答
-1

如果您的位图与显示区域的大小不同,则可能只是大小调整问题,其中 .NET 将位图缩放到显示大小,您会得到看起来很有趣的文本。

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

于 2009-05-11T19:05:07.407 回答
-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);
    }
}
于 2009-05-11T21:39:37.687 回答