C# TextRenderer.DrawText在位图与OnPaintBackground中的比较

C# TextRenderer.DrawText在位图与OnPaintBackground中的比较,c#,textrenderer,C#,Textrenderer,如果使用OnPaintBackground中提供的Graphics对象使用TextRenderer.DrawText(),我的文本看起来非常完美。如果我创建自己的位图并使用从我的位图获得的图形对象,我的文本看起来很糟糕。它看起来像是使用黑色而不是位图的背景色对文本进行抗锯齿处理。如果我使用Graphics.DrawString(),我可以避免这个问题,但是这个方法有可怕的紧排问题。我该怎么办?如何使用位图的内容使TextRenderer.DrawText()正确地反别名 看起来很糟糕: Bitm

如果使用
OnPaintBackground
中提供的
Graphics
对象使用
TextRenderer.DrawText()
,我的文本看起来非常完美。如果我创建自己的
位图
并使用从我的
位图
获得的
图形
对象,我的文本看起来很糟糕。它看起来像是使用黑色而不是位图的背景色对文本进行抗锯齿处理。如果我使用
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);
}
看起来不错,但我想将其渲染到位图上,而不是控件的表面:

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);
}

区别是什么?

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


能否使用与显示区域大小相同的位图进行测试?

能否发布出现此问题的最小程序?我不能像这样复制它--抗锯齿看起来很好:

    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);
    }
}

答案是不要使用
textrender
。TextRenderer是文本呈现的GDI(而不是GDI+)实现的包装器,它有很多特性,但正如您所发现的,它与内存中的DC不能很好地互操作

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

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


实际上,除非您遇到严重的、可测量的性能问题,否则只需使用
图形。DrawString

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

我认为问题在于,如果背景是透明的,则clear type文本渲染不起作用。一些可能的解决办法

备选案文1。用颜色填充位图的背景

如果您这样做(正如Tim Robinson在上面的代码示例中使用g.Clear(Color.Red))Clear类型将做正确的事情。但是你的位图不是完全透明的,这可能是不可接受的。如果使用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);
                }
            }
        }
    }
}
使用(位图bmp=新位图(someWidth,someHeight))
{
使用(Graphics g=Graphics.FromImage(bmp))
{
//弄清楚我们的文本将去哪里
点文本点=新点(someX,someY);
Size text Size=g.MeasureString(someText,someFont).ToSize();
矩形textRect=新矩形(textPoint,textSize);
//用白色填充那个矩形
g、 FillRectangle(笔刷.White,textRect);
//画课文
g、 抽绳(一些文字、一些字体、画笔、黑色、textPoint);
//将任何纯白色像素设置回透明

对于(int x=textRect.Left;x答案是使用。这与.NET在设置控件上的
控件样式时在内部使用的系统相同。OptimizedDoubleBuffer
样式


有关.NET中双缓冲区的更多信息,请参阅。

它们的大小和DPI都相同。我猜,由于位图没有内置透明度,您可能会尝试使用不同的图像类作为内存画布。在这种情况下,Color.Transparent可能会被解释为Color.Black。值得一试吗?我已经尝试过了正在对图像或位图进行反锯齿处理,并使用各种不同的像素格式。真正的问题是TextRenderer不是使用位图中的内容对文本进行反锯齿处理,而是使用黑色(出于某些原因)。尝试添加以下行:g.TextRenderingHint=System.Drawing.text.TextRenderingHint.ClearTypeGridFit;如果使用“color.LightBlue”作为背景,问题更加明显。是文本抗锯齿造成了混乱。此外,如果“Application.SetCompatibleTextRenderingDefault(false);”则无关紧要设置为true或false。
TextRenderer更快
?你确定吗?这篇文章说它比GDI+慢:@qakmak,但我想它可能已经改变了。你链接到的文章中的代码显示
DrawString
在我的机器上也快得多。