作为这个问题的后续:(如何在位图(Winforms)上绘制清晰的文本?),通过计算文本下面的“平均”颜色,并为文本选择适当的对比颜色,我在位图上绘制可读但小的文本。
我从https://stackoverflow.com/a/6185448/3784949窃取了Till的代码,用于计算“平均”bmp颜色。现在我来看看http://www.w3.org/TR/AERT#color-contrast提出的“色差”算法。
这意味着我需要使我的颜色亮度至少增加125个“单位”,而我的色差至少要大500个单位,其中亮度和差值计算如下:
颜色亮度由以下公式决定:
((红色值X 299) +(绿色值X 587) +(蓝色值X 114)) / 1000
色差由下列公式决定:
(最大(红色值1,红色值2) -最小值(红色值1,红色值2)) +(最大值(绿色值1,绿色值2) -最小值(绿色值1,绿色值2)) +(最大值(蓝色值1,蓝色值2) -最小值(蓝色值1,蓝色值2))
我如何实现这一点?我可以用ARGB来设置我的颜色(我相信,这是一个标签的前景色);但是我如何计算出如何改变每个单独的值来达到这里所需的差异呢?我不熟悉将“差异”单元分解成它们的组成部分所需的数学。
例如,一个位图的“平均值”是: A=255、R=152、G=138、B=129。我如何“添加”到每个部分,以实现这两个差异?
编辑:具体来说,我的困惑在于:
我不知道如何称呼第一位,我也不确定我对第二位的看法是正确的。
编辑:建议的解决方案
我目前正在做这个实验:
private Color GetContrastingFontColor(Color AverageColorOfBitmap,
List<Color> FavoriteColors)
{
IEnumerable<Color> AcceptableColors =
(IEnumerable<Color>)FavoriteColors.Where(clr =>
(GetColorDifferenceAboveTarget(AverageColorOfBitmap, clr, (float)200) > 0)
&& (GetBrightnessAboveTarget(AverageColorOfBitmap, clr, (float).125) > 0))
.OrderBy(clr => GetColorDifferenceAboveTarget(
AverageColorOfBitmap, clr, (float)200));
return AcceptableColors.DefaultIfEmpty(Color.Aqua).First();
}
这是一个很好的框架,但我需要努力从列表中选择“最好”的候选人。现在,它只是返回“符合亮度标准的最大色差的合格颜色”。然而,这允许我修改浮点值(W3的"500色差要求“是完全的废话,零KnownColors限定)和实验。
支持代码:
private float GetBrightnessAboveTarget(Color AverageColorOfBitmap,
Color proposed, float desiredDifference)
{
float result = proposed.GetBrightness() - AverageColorOfBitmap.GetBrightness();
return result - desiredDifference;
}
private float GetColorDifferenceAboveTarget(Color avg, Color proposed,
float desiredDifference)
{
float r1 = Convert.ToSingle(MaxByte(Color.Red, avg, proposed));
float r2 = Convert.ToSingle(MinByte(Color.Red, avg, proposed));
float r3 = Convert.ToSingle(MaxByte(Color.Green, avg, proposed));
float r4 = Convert.ToSingle(MinByte(Color.Green, avg, proposed));
float r5 = Convert.ToSingle(MaxByte(Color.Blue, avg, proposed));
float r6 = Convert.ToSingle(MinByte(Color.Blue, avg, proposed));
float result = (r1 - r2) + (r3 - r4) + (r5 - r6);
return result - desiredDifference;
}
private byte MaxByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R >= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G >= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B >= y.B) ? x.B : y.B;
return byte.MinValue;
}
private byte MinByte(Color rgb, Color x, Color y)
{
if (rgb == Color.Red) return (x.R <= y.R) ? x.R : y.R;
if (rgb == Color.Green) return (x.G <= y.G) ? x.G : y.G;
if (rgb == Color.Blue) return (x.B <= y.B) ? x.B : y.B;
return byte.MinValue;
}
发布于 2014-07-31 15:07:14
这更多的是对原来问题的回答。我称它为主页大纲。
使用透明度加上你可以得到的最大和最小亮度(白色和黑色),它创造了良好的对比度,至少在我的屏幕上看起来不错。
这是一种阴影和透明度的混合。我从红色的成分中减去一点点,得到你想要的水.
它首先通过打印左上1像素和右1像素的文本创建一个更暗的背景版本。最后,它在上面打印一个明亮的版本。请注意,它不是真正使用黑白,因为它的半透明像素,色调,它真正的每个背景像素。
对于一个实际的打印输出,您将不得不试验,特别是字体,但也与两个透明!
此外,你也许应该在黑色阴影上的白色和白色高亮点上的黑色之间切换,这取决于你打印的地点的亮度。但有了这个归家的轮廓,它真的将工作在黑暗和明亮的背景,它将只是看起来不那么优雅在一个明亮的背景。
using (Graphics G = Graphics.FromImage(pictureBox1.Image) )
{
Font F = new Font("Arial", 8);
SolidBrush brush0 = new SolidBrush(Color.FromArgb(150, 0, 0, 0))
SolidBrush brush1 = new SolidBrush(Color.FromArgb(200, 255, 255, 222))
G.DrawString(textBox1.Text, F, brush0 , new Point(x-1, y-1));
G.DrawString(textBox1.Text, F, brush0 , new Point(x+1, y+1));
G.DrawString(textBox1.Text, F, brush1, new Point(x, y));
}
编辑:这是从一个按钮点击调用,但实际上应该在油漆事件。在那里,Graphics对象及其使用块G将被简单的e.Graphics事件参数替换。
我注意到您正在使用“透明”标签来显示数据,以避免Graphics.DrawString和data事件的详细信息。
好吧,这是可以做到的,结果看起来也很相似:
string theText ="123 - The quick brown fox..";
Label L1, L2, L3;
pictureBox1.Controls.Add(new trLabel());
L1 = (trLabel)pictureBox1.Controls[pictureBox1.Controls.Count - 1];
L1.Text = theText;
L1.ForeColor = Color.FromArgb(150, 0, 0, 0);
L1.Location = new Point(231, 31); // <- position in the image, change!
L1.Controls.Add(new trLabel());
L2 = (trLabel)L1.Controls[pictureBox1.Controls.Count - 1];
L2.Text = theText;
L2.ForeColor = Color.FromArgb(150, 0, 0, 0);
L2.Location = new Point(2, 2); // do not change relative postion in the 1st label!
L2.Controls.Add(new trLabel());
L3 = (trLabel)L2.Controls[pictureBox1.Controls.Count - 1];
L3.Text = theText;
L3.ForeColor = Color.FromArgb(200, 255, 255, 234);
L3.Location = new Point(-1,-1); // do not change relative postion in the 2nd label!
但是,您将注意到,由于在Winforms中不可能有真正的透明控件,我们需要做一些额外的工作。您可能使用的标签子类如下:
public partial class trLabel : Label
{
public trLabel()
{
SetStyle(ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
BackColor = Color.Transparent;
Visible = true;
AutoSize = true;
}
}
这似乎很管用。但在现实中,似乎只有这样,因为每个标签在创建时都会从其父标签中获取其当前背景的副本。从来没有更新过。这就是为什么我必须添加第二和第三标签,而不是我显示的图片框,而是第一和第二‘透明’标签。
除非您自己画东西,否则Winforms控件之间就没有真正的透明度。
因此,DrawString解决方案并不是很复杂。它给了您额外的好处,允许您扭曲图形对象的一些属性,如埋伏模式、TextContrast或InterpolationMode
发布于 2014-07-31 13:23:46
简短建议:只需使用黑色或白色。
这些算法给出了一个通过的标准,而不是用来确定哪些颜色符合该标准的算法。因此,您必须创建这样一个算法。一个简单的算法是遍历每一种可能的颜色,然后计算色差,然后看看差异是否大于125,如果是这样,就有一个很好的颜色可供使用。更好的是,您可以搜索颜色的最大差异。
但这是愚蠢的--如果我给你的颜色是R=152,G=138,B=129 --你认为与之形成对比的颜色是什么?凭直觉,我猜是0,0,0。我选择了最可能的R值、G值和B值的颜色。如果你给我50,200,75的颜色,我会选择R=255,G=0,B=255。同样的逻辑。所以我的算法是如果R<128选择R= 255,否则选择R= 0。G和B也是一样的。
现在,该算法只选择0或255的RGB值。但如果你不喜欢,现在你需要一个数学定义什么是“漂亮”,我会让你自己来解决这个问题。:-)
https://stackoverflow.com/questions/25068189
复制