【发布时间】:2011-09-17 16:02:38
【问题描述】:
我想根据 0 到 100 的值显示一种颜色。一端 (100) 是纯红色,另一端 (0) 是纯绿色。在中间(50),我希望它是黄色的。
我希望颜色逐渐从一种渐变到另一种,这样在 75 时,颜色是半红半黄,等等。
如何对 RGB 值进行编程以反映这种渐变?谢谢。
【问题讨论】:
-
WPF?表格?你打算将渐变应用到什么地方?
我想根据 0 到 100 的值显示一种颜色。一端 (100) 是纯红色,另一端 (0) 是纯绿色。在中间(50),我希望它是黄色的。
我希望颜色逐渐从一种渐变到另一种,这样在 75 时,颜色是半红半黄,等等。
如何对 RGB 值进行编程以反映这种渐变?谢谢。
【问题讨论】:
看看LinearGradientBrush。它应该是您正在寻找的完整实现。
【讨论】:
我不懂 C#,所以这个答案只是一个建议的方法。让x 表示范围从0 到100 的int。这样的事情应该可以工作:
red = (x > 50 ? 1-2*(x-50)/100.0 : 1.0);
green = (x > 50 ? 1.0 : 2*x/100.0);
blue = 0.0
这个想法是从红色开始:(1.0,0.0,0.0)。然后增加绿色变成黄色:(1.0,1.0,0.0)。然后将红色减小为绿色:(0.0,1.0,0.0)。
编辑:这是 C# 中的代码
static Color GetColorFromRedYellowGreenGradient(double percentage)
{
var red = (percentage > 50 ? 1 - 2 * (percentage - 50) / 100.0 : 1.0) * 255;
var green = (percentage > 50 ? 1.0 : 2 * percentage / 100.0) * 255;
var blue = 0.0;
Color result = Color.FromArgb((int)red, (int)green, (int)blue);
return result;
}
【讨论】:
颜色的 RGB 值:
在红色和黄色之间,将您添加到绿色通道的距离相等,直到达到 255。在黄色和绿色之间,将您从红色通道中的减法间隔相等。
【讨论】:
您需要改用HSB or HSV color representation,并使用 H(“色调”)值。请参阅其他 SO 问题以了解 RGB 和 HSB/HSV 之间的转换:How to change RGB color to HSV?
【讨论】:
这是一个非常简单的颜色分量线性插值。它可能会满足您的需求。
public Color GetBlendedColor(int percentage)
{
if (percentage < 50)
return Interpolate(Color.Red, Color.Yellow, percentage / 50.0);
return Interpolate(Color.Yellow, Color.Lime, (percentage - 50) / 50.0);
}
private Color Interpolate(Color color1, Color color2, double fraction)
{
double r = Interpolate(color1.R, color2.R, fraction);
double g = Interpolate(color1.G, color2.G, fraction);
double b = Interpolate(color1.B, color2.B, fraction);
return Color.FromArgb((int)Math.Round(r), (int)Math.Round(g), (int)Math.Round(b));
}
private double Interpolate(double d1, double d2, double fraction)
{
return d1 + (d2 - d1) * fraction;
}
【讨论】:
d1 和d2 的修复帮助很大。
我也有同样的需求,我刚刚解决了这个问题:
myColor = new Color(2.0f * x, 2.0f * (1 - x), 0);
说明: 让我们关注颜色分量的 [0.0-1.0] 范围,而不是 [0-255] 范围:
如果你只是将绿色分量从 0.0(一端)缩放到 1.0(另一端)并对红色分量做同样的事情(但向后),你会得到丑陋和不均匀的颜色分布。
为了让它看起来更好看,我们可以写很多代码,或者我们可以更聪明。
如果您仔细查看单个分量,您会发现我们可以将范围分成两个相等的部分:在第一个部分中,我们将红色分量从 0.0 增加到 1.0,使绿色为 1.0,蓝色为 0.0 ;在第二个中,我们减少了绿色分量,将其他 2 个保持原样。我们可以利用任何高于 1.0 的值都将被读取为 1.0 的事实,通过最大化我们的值来简化代码。假设您的 x 值从 0.00 (0%) 变为 1.00 (100%),您可以将其乘以 2 以使其超过颜色分量的 1.0 限制。现在您的组件从 0.0 变为 2.0(红色)和从 2.0 变为 0.0(绿色)。让它们被剪裁到 [0.0-1.0] 范围,然后就可以了。
如果您的 x 在另一个范围内移动(例如 [0-100]),您需要选择适当的因子而不是 2
【讨论】:
QColor(min(255,2*255*(temp)),min(255,2*255*(1-temp)),0)
简化的扩展方法;
public static Color Interpolate(this Color source, Color target, double percent)
{
var r = (byte)(source.R + (target.R - source.R) * percent);
var g = (byte)(source.G + (target.G - source.G) * percent);
var b = (byte)(source.B + (target.B - source.B) * percent);
return Color.FromArgb(255, r, g, b);
}
用法;
var low = 33.0;
var high = 100.0;
var color = Color.Red.Interpolate(Color.Green, low / high);
【讨论】:
你只需要创建一个带有整数参数的函数
输入 1 将返回 RGB (1, 99, 0)
私人颜色推子(int v){ 返回 Color.FromArgb(v, 100-v, 0); }【讨论】:
r.g.b 的值最多为 255 而不是 100。
我今天需要类似的东西。输入是从 0.0 到 1.0 的百分比,输出红色到绿色。基于jterrace的回答实现:
Color percentToColor(float percent)
{
if (percent<0 || percent>1) { return Color.Black; }
int r, g;
if (percent<0.5)
{
r=255;
g = (int)(255*percent/0.5); //closer to 0.5, closer to yellow (255,255,0)
}
else
{
g=255;
r = 255 - (int)(255*(percent-0.5)/0.5); //closer to 1.0, closer to green (0,255,0)
}
return Color.FromArgb(r, g, 0);
}
【讨论】:
在我用更逼真的颜色试验了一段时间后,这是我的公式:
public Color GetColorOf(double value, double minValue, double maxValue)
{
if (value == 0 || minValue == maxValue) return Color.White;
var g = (int)(240 * value / maxValue);
var r = (int)(240 * value / minValue);
return (value > 0
? Color.FromArgb(240 - g, 255 - (int)(g * ((255 - 155) / 240.0)), 240 - g)
: Color.FromArgb(255 - (int)(r * ((255 - 230) / 240.0)), 240 - r, 240 - r));
}
【讨论】:
我使用此函数将 1400 MHz 和 3500 MHz 之间的 CPU 速度值映射到 rgb() 值以从绿色 -> 黄色 -> 红色
function green_yellow_red(core_MHz, core_id){
var core_color = ~~core_MHz.map(1400, 3500, 0, 510)
if(core_color < 255){
$('#cpu_core_'+core_id).css('background', 'rgb('+core_color+',255 , 0)')
}else{
core_color-=255
$('#cpu_core_'+core_id).css('background', 'rgb(255 ,'+ (255-core_color) +', 0)')
}
}
【讨论】:
我为 UIColor 编写了一个 Swift 4 扩展,它将百分比 (0-100) 转换为从红色到绿色的 UIColor。
我目前正在将它用于分析应用程序中的进度条。这是一个例子:
let myNewColor = UIColor().greenRedProgress(percent: Int))
这是扩展名:
extension UIColor{
func greenRedProgress(percent: Int) -> UIColor{
let modVal = CGFloat((Double(percent).truncatingRemainder(dividingBy: 50) / 50) * 255)
if percent <= 0{
return UIColor(red: 1.0, green: 0, blue: 0, alpha: 1)
}else if percent >= 100{
return UIColor(red: 0, green: 1.0, blue: 0, alpha: 1)
}else{
switch percent{
case 1..<50: return UIColor(red: 1.0, green: (modVal/255), blue: 0, alpha: 1)
case 51..<100: return UIColor(red: (255 - modVal)/255, green: 1.0, blue: 0, alpha: 1)
case 50: return UIColor(red: 1.0, green: 1.0, blue: 0, alpha: 1)
default: return UIColor(red: 0, green: 1.0, blue: 0, alpha: 1)
}
}
}}
【讨论】:
此方法(在 c# 中,但可以轻松翻译成其他语言)将采用百分比和颜色列表,并根据您的百分比返回渐变颜色。当您传递颜色时,它们需要按从 0 值到 100 值的顺序排列(因此您需要按绿色、黄色、红色的顺序传递)。如果您发现中间需要不同或更多颜色,只需按照您希望它们出现的顺序将它们添加到您传递的颜色列表中即可。
public Color ColorBasedOnPercent(decimal percent, params Color[] colors)
{
if (colors.Length == 0)
{
//I am using Transparent as my default color if nothing was passed
return Color.Transparent;
}
if (percent > 1)
{
percent = percent / 100;
}
//find the two colors within your list of colors that the percent should fall between
var colorRangeIndex = (colors.Length - 1) * percent;
var minColorIndex = (int)Math.Truncate(colorRangeIndex);
var maxColorIndex = minColorIndex + 1;
var minColor = colors[minColorIndex];
if (maxColorIndex < colors.Length)
{
var maxColor = colors[maxColorIndex];
//get the differences between all the color values for the two colors you are fading between
var aScale = maxColor.A - minColor.A;
var redScale = maxColor.R - minColor.R;
var greenScale = maxColor.G - minColor.G;
var blueScale = maxColor.B - minColor.B;
//the decimal distance of how "far" this color should be from the minColor in the range
var gradientPct = colorRangeIndex - minColorIndex;
//for each piece of the color (ARGB), add a percentage(gradientPct) of the distance between the two colors
int getRGB(int originalRGB, int scale) => (int)Math.Round(originalRGB + (scale * gradientPct));
return Color.FromArgb(getRGB(minColor.A, aScale), getRGB(minColor.R, redScale), getRGB(minColor.G, greenScale), getRGB(minColor.B, blueScale));
}
return minColor;
}
【讨论】:
更多相同。只需 Delphi Pascal 编码并简化+锁定为信号量颜色(红色/黄色/绿色)。
rectangle1.Fill.Color:=DefineColorSemaphore(newcolor);
function TForm1.DefineColorSemaphore(valperc:integer):TAlphaColor;
var
vcol: TAlphaColorRec;
begin
vcol.B := 0; // blue: always 0
vcol.A := 255; // alpha: 255=no
if (valperc < 50) then
begin
// starts @ RGB=255,0,0 and increases G 0->255
vcol.R := 255;
vcol.G := trunc(255*valperc/50);
end
else
begin
// starts @ RGB=255,255,0 and decreases R 255->0
vcol.R := 255-trunc(255* (valperc - 50)/50);
vcol.G := 255;
end;
result:= TAlphaColor(vcol);
end;
【讨论】:
最近我打算用 Javascript 做同样的事情。我遵循了两个步骤。
这是我用于此目的的代码。
var blue = 0.0, red = 0.0, green = 0.0;
if(scaledValue <= 0.5)
{
red = (scaledValue * 2) * 255.0;
green = 255.0;
blue = 0;
}else
{
red = 255.0;
green = 255.0 + 255.0 - ((scaledValue * 2)* 255);
blue = 0;
}
A sample code for showing this works in C++
此解决方案的灵感来自@jterrace 答案。
【讨论】:
// 在 WM_DRAWITEM 上用红黄绿渐变填充 OwnerDraw 控件
int cx = lpDis->rcItem.right - lpDis->rcItem.left;
for (int x = 0; x < cx; x++)
{
COLORREF cr;
double d = 255 * 2 * (double)x/(double)cx;
cr = x <= cx/2 ? RGB(255, d, 0) :
RGB(255 - d, 255, 0);
HPEN hPen = CreatePen(PS_SOLID, 1, cr);
HPEN hOldPen = (HPEN)SelectObject(lpDis->hDC, hPen);
MoveToEx(lpDis->hDC, x, lpDis->rcItem.top, NULL);
LineTo(lpDis->hDC, x, lpDis->rcItem.bottom);
SelectObject(lpDis->hDC, hOldPen);
DeleteObject(hPen);
}
【讨论】:
如果您使用的是 python,那么这可能会有所帮助...
def rgb(p):# <-- percentage as parameter
#Starting with color red
d = [255,0,0]
#formula for finding green value by percentage
d[1] = int((510*p)/100)
print(d[1])
#if green value more than 255
#set green value 255
#reduce the red value from remaining green value
if d[1]>255:
d[0] -= d[1]-255
d[1] = 255
return d
print(rgb(0))
【讨论】: