首先,你要求进行线性插值,但你没有说明颜色B位于颜色A和颜色C之间的直线上;这是必须的。其次,你没有明确指定,但我做了一个简化的假设,即颜色B是颜色A和颜色C之间直线的中点;如果不是这样的话,下面的代码很容易修改。最后,我改变了你对参数的假设,将它从0到100之间的整数改为了0到1之间的双精度浮点型。在后一种情况下,代码更容易编写和理解,并且仍然可以与前一种情况一起使用(将输入除以100)。
class ColorInterpolator {
delegate byte ComponentSelector(Color color);
static ComponentSelector _redSelector = color => color.R;
static ComponentSelector _greenSelector = color => color.G;
static ComponentSelector _blueSelector = color => color.B;
public static Color InterpolateBetween(
Color endPoint1,
Color endPoint2,
double lambda) {
if (lambda < 0 || lambda > 1) {
throw new ArgumentOutOfRangeException("lambda");
}
Color color = Color.FromRgb(
InterpolateComponent(endPoint1, endPoint2, lambda, _redSelector),
InterpolateComponent(endPoint1, endPoint2, lambda, _greenSelector),
InterpolateComponent(endPoint1, endPoint2, lambda, _blueSelector)
);
return color;
}
static byte InterpolateComponent(
Color endPoint1,
Color endPoint2,
double lambda,
ComponentSelector selector) {
return (byte)(selector(endPoint1)
+ (selector(endPoint2) - selector(endPoint1)) * lambda);
}
}
如果颜色B不是颜色A和颜色C之间的中点,你如何进行修改?最简单的方法如下。如果参数(我称之为“
lambda
”)小于
0.5
,则将
lambda
乘以2并返回颜色A和颜色B之间的插值颜色。如果参数大于
0.5
,则将
lambda
乘以2再减去1(这将
[0.5, 1]
映射到
[0, 1]
),然后返回颜色B和颜色C之间的插值颜色。
如果您不喜欢颜色B必须在颜色A和颜色C之间的限制,则可以使用刚刚描述的修改来对颜色进行分段线性插值。
最后,您没有指定是否要插值所谓的alpha值("ARGB"中的'A')。上述代码很容易进行修改以处理这种情况。添加一个额外的
ComponentSelector
定义为
color => color.A
,使用
InterpolateComponent
插值该值,并使用
Color.FromArgb(int, int, int, int)
重载的
Color.FromArgb
。