如果我使用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);
}
有什么区别?
答案 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);
}
}