我将您的问题理解为:我希望将给定的 rgba 颜色分量更改某个因素,同时保持相同的整体透明度。
对于具有完整 alpha(1.0 或 255)的颜色,这是微不足道的:只需将组件相乘而不接触其他组件:
//typedef unsigned char uint8
enum COMPONENT {
RED,
GREEN,
BLUE,
ALPHA
};
struct rgba {
uint8 components[4];
// uint8 alpha, blue, green, red; // little endian
uint8 &operator[](int index){
return components[index];
}
};
rgba color;
if (color[ALPHA] == 255)
color[RED] *= factor;
else
ComponentFactor(color, RED, factor);
在一般情况下,这个问题可能没有一个单一的答案。考虑到颜色可以交替编码为HSL 或 HSV。您可能希望将其中一些参数保持固定,并允许其他参数进行更改。
我解决这个问题的方法是首先尝试在全 alpha 处找到源颜色和目标颜色之间的色调距离,然后将真实的源颜色转换为 HSV,应用色调的变化,然后再转换回 RGBA。显然,如果 alpha 实际上是 1.0,则不需要第二步。
在伪代码中:
rgba ComponentFactor(rgba color, int component, double factor){
rgba fsrc = color, ftgt;
fsrc.alpha = 1.0; // set full alpha
ftgt = fsrc;
ftgt[component] *= factor; // apply factor
hsv hsrc = fsrc, htgt = ftgt; // convert to hsv color space
int distance = htgt.hue - hsrc.hue; // find the hue difference
hsv tmp = color; // convert actual color to hsv
tmp.hue += distance; // apply change in hue
rgba res = tmp; // convert back to RGBA space
return res;
}
请注意上面如何依赖类型rgba
并hsv
具有隐式转换构造函数。通过网络搜索可以很容易地找到转换算法。从 rgba 派生 hsv 的结构定义也应该很容易,或者将单个组件访问作为字段成员包含在内(而不是使用[]
运算符)。例如:
//typedef DWORD uint32;
struct rgba {
union {
uint8 components[4];
struct {
uint8 alpha,blue,green,red; // little endian plaform
}
uint32 raw;
};
uint8 &operator[](int index){
return components[4 - index];
}
rgba (uint32 raw_):raw(raw_){}
rgba (uint8 r, uint8 g, uint8 b, uint8 a):
red(r), green(g), blue(b),alpha(a){}
};
也许您必须找到色调因子而不是距离,或者调整其他 HSV 组件以达到所需的结果。