C# 在透明像素上使用抽绳渲染错误的文本
在将文本渲染为位图时,我发现在具有非不透明alpha的区域顶部渲染时,文本看起来非常糟糕。随着底层像素变得更加透明,问题会越来越严重。如果我不得不猜测,我会说,当底层像素是透明的时,文本渲染器会将任何抗锯齿的“灰色”像素绘制为纯黑色 以下是一些屏幕截图: 在透明像素上绘制的文本: 在半透明像素上绘制的文本: 在不透明像素上绘制的文本: 以下是用于呈现文本的代码:C# 在透明像素上使用抽绳渲染错误的文本,c#,winforms,gdi+,system.drawing,drawstring,C#,Winforms,Gdi+,System.drawing,Drawstring,在将文本渲染为位图时,我发现在具有非不透明alpha的区域顶部渲染时,文本看起来非常糟糕。随着底层像素变得更加透明,问题会越来越严重。如果我不得不猜测,我会说,当底层像素是透明的时,文本渲染器会将任何抗锯齿的“灰色”像素绘制为纯黑色 以下是一些屏幕截图: 在透明像素上绘制的文本: 在半透明像素上绘制的文本: 在不透明像素上绘制的文本: 以下是用于呈现文本的代码: g.SmoothingMode = SmoothingMode.HighQuality; g.DrawString("Press
g.SmoothingMode = SmoothingMode.HighQuality;
g.DrawString("Press the spacebar", Font, Brushes.Black, textLeft, textTop);
第一个输出是在黑色背景(可能是Color.Transparent)上绘制黑色文本时得到的结果。第二张画在几乎是黑色的背景上。第三个是在显示的相同背景上绘制的 在透明背景上时,抗锯齿无法工作。当文本以不同背景显示时,用于抗锯齿像素的颜色不会将字母形状混合到背景中。这些像素现在将变得非常明显,并使文本看起来非常糟糕 请注意,SmoothingMode不会影响文本输出。如果使用质量较低的TextRenderingHint,背景颜色为灰色,alpha值为零,看起来就不会那么糟糕了。只有TextRenderingHint.SingleBitPerPixelGridFit可以避免所有抗锯齿问题
很难找到一个完美的解决方案。Vista在窗口标题栏上的玻璃效果使用非常精细的着色,为文本提供定义良好的背景色。您需要SysInternals的ZoomIt工具才能真正看到它。具有非零iGlowSize的DrawThemeTextEx()函数。我用于解决此问题的选项是:
Graphics graphics = new Graphics();
graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
TextRenderingHint中还有其他一些有用的选项
希望它有帮助如果您正在寻找比GDI+在默认情况下更好地保留抗锯齿的功能,您可以调用
Graphics。使用色度键清除
,然后手动删除产生的色度瑕疵。(见和。)
以下是我最终解决类似问题的方式:
static Bitmap TextToBitmap(string text, Font font, Color foregroundColor)
{
SizeF textSize;
using ( var g = Graphics.FromHwndInternal(IntPtr.Zero) )
textSize = g.MeasureString(text, font);
var image = new Bitmap((int)Math.Ceiling(textSize.Width), (int)Math.Ceiling(textSize.Height));
var brush = new SolidBrush(foregroundColor);
using ( var g = Graphics.FromImage(image) )
{
g.Clear(Color.Magenta);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.DrawString(text, font, brush, 0, 0);
g.Flush();
}
image.MakeTransparent(Color.Magenta);
// The image now has a transparent background, but around each letter are antialiasing artifacts still keyed to magenta. We need to remove those.
RemoveChroma(image, foregroundColor, Color.Magenta);
return image;
}
static unsafe void RemoveChroma(Bitmap image, Color foregroundColor, Color chroma)
{
if (image == null) throw new ArgumentNullException("image");
BitmapData data = null;
try
{
data = image.LockBits(new Rectangle(Point.Empty, image.Size), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
for ( int y = data.Height - 1; y >= 0; --y )
{
int* row = (int*)(data.Scan0 + (y * data.Stride));
for ( int x = data.Width - 1; x >= 0; --x )
{
if ( row[x] == 0 ) continue;
Color pixel = Color.FromArgb(row[x]);
if ( (pixel != foregroundColor) &&
((pixel.B >= foregroundColor.B) && (pixel.B <= chroma.B)) &&
((pixel.G >= foregroundColor.G) && (pixel.G <= chroma.G)) &&
((pixel.R >= foregroundColor.R) && (pixel.R <= chroma.R)) )
{
row[x] = Color.FromArgb(
255 - ((int)
((Math.Abs(pixel.B - foregroundColor.B) +
Math.Abs(pixel.G - foregroundColor.G) +
Math.Abs(pixel.R - foregroundColor.R)) / 3)),
foregroundColor).ToArgb();
}
}
}
}
finally
{
if (data != null) image.UnlockBits(data);
}
}
静态位图文本到位图(字符串文本、字体字体、颜色foregroundColor)
{
SizeF textSize;
使用(var g=Graphics.fromHwnInternal(IntPtr.Zero))
textSize=g.MeasureString(文本,字体);
var image=新位图((int)数学天花板(textSize.Width),(int)数学天花板(textSize.Height));
var笔刷=新的SolidBrush(foregroundColor);
使用(var g=Graphics.FromImage(image))
{
g、 清晰(颜色为洋红色);
g、 SmoothingMode=SmoothingMode.AntiAlias;
g、 插值模式=插值模式。高质量双三次;
g、 PixelOffsetMode=PixelOffsetMode.HighQuality;
g、 抽绳(文本、字体、画笔、0、0);
g、 冲洗();
}
图像。使透明(颜色为洋红色);
//图像现在有一个透明的背景,但是每个字母周围都有抗锯齿伪影,仍然是洋红色。我们需要删除这些伪影。
去除色素(图像,前底色,颜色.品红色);
返回图像;
}
静态消除色度(位图图像、彩色背景色、彩色色度)
{
如果(image==null)抛出新的ArgumentNullException(“image”);
BitmapData数据=null;
尝试
{
数据=image.LockBits(新矩形(Point.Empty,image.Size),ImageLockMode.ReadWrite,PixelFormat.Format32bppArgb);
对于(int y=data.Height-1;y>=0;--y)
{
int*行=(int*)(data.Scan0+(y*data.Stride));
对于(int x=data.Width-1;x>=0;--x)
{
如果(行[x]==0)继续;
颜色像素=Color.FromArgb(行[x]);
if((像素!=foregroundColor)&&
((pixel.B>=foregroundColor.B)和&(pixel.B=foregroundColor.G)和&(pixel.G=foregroundColor.R)和&(pixel.R对此有一个非常简单的答案
g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
如果在呈现文本之前设置此选项,则文本将清晰显示。此外,此方法支持更多字体大小(默认值仅为56)
感谢您阅读本文。我相信结果也将取决于ClearType是否启用。看起来您不是在“清除”(或者更确切地说是失效)透明背景。有完整源代码的最终解决方案吗?你能上传包含到堆栈溢出的图像吗?它们不再从Dropbox中下载。呃。我想我可以在临时位图上将黑色文本绘制为白色,将白色转换为透明,将灰色转换为半透明黑色,然后将其绘制到最终的bitmap。我将尝试不同的文本渲染提示。否则,我认为部分背景透明度的效果还不错。不过有一件事——在每种情况下,背景都是相同的颜色(灰白色)使用不同的透明度,所以我不希望文本以“有效”的黑色背景色绘制。不确定你的意思。关键问题是GDI看不到透明度,它可以看到透明颜色的RGB值。颜色。透明是一个非常糟糕的选择,它的RGB值为零。黑色。我的意思是背景是p用灰白色绘制,带有alpha成分。不确定从何处获得颜色。透明来自。@mack-是的,花太多时间在计算机上的人通常会遇到这种情况。这在家庭中不起作用,很好。请求很简单,请删除答案标记。SingleBitPerPixelGridFit指针+1可以绕过这个问题-谢谢。虽然这是一个非常老的问题,我还没有测试过这个答案,但将答案换成了这个。user3470185的答案(g.TextRenderingHint=Drawing.Text.TextRenderingHint.AntiAliasGridFit)会产生更好的结果。这适用于我正在修改的控件(但我使用textrendinghint.ClearTypeGridFit
只是为了修复应用于该控件文本的默认错误提示)