C# 位图与 OnPaintBackground 中的 TextRenderer.DrawText
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/849531/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
TextRenderer.DrawText in Bitmap vs OnPaintBackground
提问by Jon Tackabury
If I use TextRenderer.DrawText()
using the Graphics
object provided in the OnPaintBackground
my text looks perfect. If I create my own Bitmap
and use the Graphics
object obtained from my Bitmap
my text looks terrible. It looks like it is anti-aliasing the text using black, not the bitmap's background color. I can avoid this problem if I use Graphics.DrawString()
, but this method has horrible kerning problems. What should I do? How can I get TextRenderer.DrawText()
to anti-alias properly using the Bitmap's contents?
如果我使用TextRenderer.DrawText()
使用我的文本中Graphics
提供的对象OnPaintBackground
看起来很完美。如果我创建自己Bitmap
的Graphics
对象并使用从Bitmap
我的文本中获得的对象看起来很糟糕。看起来它使用黑色来消除文本锯齿,而不是位图的背景色。如果我使用Graphics.DrawString()
,我可以避免这个问题,但是这种方法有可怕的字距调整问题。我该怎么办?如何TextRenderer.DrawText()
使用位图的内容正确进行抗锯齿?
Looks terrible:
看起来很可怕:
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);
}
Looks good, but I want to render this onto a bitmap, NOT onto the control's surface:
看起来不错,但我想把它渲染到位图上,而不是在控件的表面上:
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);
}
What is the difference?
有什么不同?
采纳答案by Roman Starkov
The answer is not to use TextRenderer
. TextRenderer is a wrapper for the GDI (not GDI+) implementation of text rendering, which has lots of features, but doesn't interoperate well with in-memory DCs as you have discovered.
答案是不要使用TextRenderer
. TextRenderer 是文本渲染的 GDI(不是 GDI+)实现的包装器,它具有许多功能,但与您发现的内存中 DC 不能很好地互操作。
Use Graphics.DrawString
& Graphics.MeasureString
, but remember to pass it StringFormat.GenericTypographic to get accurate size and positioning.
使用Graphics.DrawString
& Graphics.MeasureString
,但记住传递它 StringFormat.GenericTypographic 以获得准确的大小和定位。
The reason TextRenderer was introduced initially was that GDI+ didn't support all the complex scripts that GDI's Uniscribe engine did. Over time however GDI+ support for complex scripts has been expanded, and these days there aren't any good reasons left to use TextRenderer (it's not even the faster of the two anymore, in fact quite the opposite it appears).
最初引入 TextRenderer 的原因是 GDI+ 不支持 GDI 的 Uniscribe 引擎支持的所有复杂脚本。然而,随着时间的推移,GDI+ 对复杂脚本的支持得到了扩展,现在已经没有任何充分的理由来使用 TextRenderer(它甚至不再是两者中更快的一个,实际上看起来正好相反)。
Really, though, unless you are running into serious, measurable performance issues just use Graphics.DrawString
.
不过,真的,除非您遇到严重的、可衡量的性能问题,否则只需使用Graphics.DrawString
.
回答by Mike
If your bitmap is not the same size as your display area, it might just be a resizing issue, where .NET scales the bitmap to the display size and you get funny looking text.
如果您的位图与显示区域的大小不同,则可能只是调整大小的问题,其中 .NET 将位图缩放到显示大小,并且您会得到看起来很有趣的文本。
Can you test with a bitmap created at the same size as your display area?
您可以使用与显示区域大小相同的位图进行测试吗?
回答by Tim Robinson
Can you post the smallest program that suffers from this problem? I can't reproduce it like this -- the antialiasing looks fine:
您可以发布遇到此问题的最小程序吗?我不能像这样重现它——抗锯齿看起来不错:
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);
}
}
回答by Michael
Another possible solution: Draw the whole thing to the screen, bitmap with text on top, and then write some code to 'screen capture' that portion of the screen. Not practical in all cases but you're right, DrawString creates weird text and DrawText onto a bitmap looks horrible.
另一种可能的解决方案:将整个内容绘制到屏幕上,在顶部绘制带有文本的位图,然后编写一些代码来“截屏”屏幕的该部分。在所有情况下都不实用,但你是对的,DrawString 创建奇怪的文本,而 DrawText 到位图上看起来很糟糕。
回答by Matthew Hess
I believe the problem is that the clear type text rendering doesn't work if the background is transparent. A few possible solutions.
我相信问题是如果背景是透明的,则清晰类型的文本渲染不起作用。几种可能的解决方案。
Option 1. Fill the background of your bitmap with a color.
选项 1. 用颜色填充位图的背景。
If you do this (as Tim Robinson did above in his code example by using g.Clear(Color.Red)) clear type will do the right thing. But your bitmap won't be completely transparent which might not be acceptable. If you use Graphics.MeasureText, you can fill just the rectangle around your text, if you like.
如果你这样做(就像 Tim Robinson 在上面的代码示例中使用 g.Clear(Color.Red) 所做的那样),clear type 会做正确的事情。但是您的位图不会完全透明,这可能是不可接受的。如果您使用 Graphics.MeasureText,您可以根据需要仅填充文本周围的矩形。
Option 2. Set TextRenderingHint = TextRenderingHintAntiAliasGridFit
选项 2. 设置 TextRenderingHint = TextRenderingHintAntiAliasGridFit
This appears to turn off clear type. The text will be rendered at a lower quality than clear type on a background, but much better than the mess clear type on no background creates.
这似乎关闭了清除类型。文本的渲染质量将低于背景上的清晰字体,但比无背景的清晰字体要好得多。
Option 3. Fill the text rectangle with white, draw the text and then find all the non-text pixels and put them back to transparent.
选项 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);
}
}
}
}
}
I know, it's a horrible hack, but it appears to work.
我知道,这是一个可怕的黑客,但它似乎有效。
回答by Pieter van Ginkel
The answer is to use a BuffersGraphicsContext
.This is the same system that .NET uses internally when you set the ControlStyles.OptimizedDoubleBuffer
style on a control.
答案是使用一个BuffersGraphicsContext
. 当您ControlStyles.OptimizedDoubleBuffer
在控件上设置样式时,这与 .NET 在内部使用的系统相同。
See http://msdn.microsoft.com/en-us/library/b367a457.aspxfor more information about double buffering in .NET.
有关.NET 中双缓冲的更多信息,请参阅http://msdn.microsoft.com/en-us/library/b367a457.aspx。