【发布时间】:2014-07-31 20:19:14
【问题描述】:
作为此问题的后续:(How can I draw legible text on a bitmap (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]。如何为每个部分“添加”足够的内容以实现这两个差异?
编辑:具体来说,我的困惑在于:
看起来我需要添加三个单独的值(R、G、B)来实现两个不同的目标(新 RGB 加起来是原始加 125,新 RGB 加起来是原始加 500
看来我可能需要“加权”我添加的亮度值,以使 G 比 R 多于 B。
我不知道如何解决 #1。而且我并不肯定我对 #2 的看法是正确的。
编辑:建议的解决方案
我目前正在尝试这个:
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;
}
【问题讨论】:
-
链接文档中颜色亮度范围为125,差异范围为500。
-
OT,但只有当你的背景相当同质时,整个想法才能很好地发挥作用。我宁愿打印两次,黑色和白色,偏移量为 1,1。对比色看起来很糟糕,你需要的是亮度对比。亮度最好通过
color.GetBrightness()(0f-1f) 的系统调用来计算,最好的结果(在最小尺寸下可读)是提供背景。最不显眼的方法是用相同的颜色打印更大的、半透明的字母,但比背景更亮或更暗。.. -
我的意思是你的值颠倒了,所以你不能得到 500 单位的亮度增量。在试图找出一种修改颜色的方法时,我感到很困惑。
-
@Jared 哦!接得好。我会解决的。
-
@TaW - 请记住,我只是在计算自动调整大小标签后面的位图部分的颜色。到目前为止,我的测试表明,在一张大照片(现代相机照片)的如此小区域中存在相当多的同质性。我从 SO 中采样了一些不同的“绘制轮廓文本”,但是对于小字体,它在照片上不是很清晰 - 部分问题是(正如我在下面对 Moby 提到的)黑色根本不会出现在大范围内照片。