动机
我想找到一种方法来采取任意颜色并使其变暗一些阴影,这样我就可以以编程方式创建从一种颜色到较轻版本的漂亮渐变.渐变将用作UI中的背景.
可能性1
显然,我可以将RGB值分开并逐个增加一定量.这实际上是我想要的吗?
可能性2
我的第二个想法是将RGB转换为HSV/HSB/HSL(色调,饱和度,值/亮度/亮度),稍微增加亮度,稍微降低饱和度,然后将其转换回RGB.这一般会产生预期的效果吗?
正如Wedge所说的那样,你想要乘以使事物更亮,但这只有在其中一种颜色变得饱和(即达到255或更高)时才有效.此时,您可以将值限制为255,但随着颜色变浅,您将巧妙地更改色调.要保持色调,您需要保持(中 - 最低)/(最高 - 最低)的比率.
这是Python中的两个函数.第一个实现了朴素的方法,如果它们结束,它只会将RGB值钳位到255.第二个重新分配多余的值以保持色调完整.
def clamp_rgb(r, g, b): return min(255, int(r)), min(255, int(g)), min(255, int(b)) def redistribute_rgb(r, g, b): threshold = 255.999 m = max(r, g, b) if m <= threshold: return int(r), int(g), int(b) total = r + g + b if total >= 3 * threshold: return int(threshold), int(threshold), int(threshold) x = (3 * threshold - total) / (3 * m - total) gray = threshold - x * m return int(gray + x * r), int(gray + x * g), int(gray + x * b)
我创建了一个以RGB值(224,128,0)开始的渐变,并将其乘以1.0,1.1,1.2等,直到2.0.上半部分是结果使用clamp_rgb
,下半部分是结果redistribute_rgb
.我认为很容易看出重新分配溢出会产生更好的结果,而不必离开RGB色彩空间.
为了比较,这里是HLS和HSV颜色空间中的相同渐变,由Python的colorsys
模块实现.仅L
修改了组件,并对生成的RGB值执行了夹紧.结果类似,但每个像素都需要色彩空间转换.
我会选择第二种选择.一般来说,RGB空间并不适合进行颜色处理(从一种颜色转换为另一种颜色,使颜色变亮/变暗等).下面是我发现的两个站点,通过快速搜索从/到RGB转换为HSL:
来自"计算机图形学基础"
C#中的一些源代码 - 应该很容易适应其他编程语言.
在C#中:
public static Color Lighten(Color inColor, double inAmount) { return Color.FromArgb( inColor.A, (int) Math.Min(255, inColor.R + 255 * inAmount), (int) Math.Min(255, inColor.G + 255 * inAmount), (int) Math.Min(255, inColor.B + 255 * inAmount) ); }
我到处都用过这个.
System.Windows.Forms命名空间中的ControlPaint类具有静态方法Light和Dark:
public static Color Dark(Color baseColor, float percOfDarkDark);
这些方法使用HLSColor的私有实现.我希望这个结构是公共的,并且在System.Drawing中.
或者,您可以在Color struct上使用GetHue,GetSaturation,GetBrightness来获取HSB组件.不幸的是,我没有找到逆转换.
将其转换为RGB并在原始颜色和目标颜色(通常为白色)之间进行线性插值.因此,如果您想在两种颜色之间使用16种阴影,则可以:
for(i = 0; i < 16; i++) { colors[i].R = start.R + (i * (end.R - start.R)) / 15; colors[i].G = start.G + (i * (end.G - start.G)) / 15; colors[i].B = start.B + (i * (end.B - start.B)) / 15; }
为了获得给定颜色的较浅或较暗版本,您应该修改其亮度.即使不将颜色转换为HSL或HSB颜色,也可以轻松完成此操作.例如,为了使颜色变浅,您可以使用以下代码:
float correctionFactor = 0.5f; float red = (255 - color.R) * correctionFactor + color.R; float green = (255 - color.G) * correctionFactor + color.G; float blue = (255 - color.B) * correctionFactor + color.B; Color lighterColor = Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
如果您需要更多详细信息,请阅读我博客上的完整故事.