我正在尝试混合两种编码为整数的颜色。这是我的小功能:
int blend (int a, int b, float ratio) {
if (ratio > 1f) {
ratio = 1f;
} else if (ratio < 0f) {
ratio = 0f;
}
float iRatio = 1.0f - ratio;
int aA = (a >> 24 & 0xff);
int aR = ((a & 0xff0000) >> 16);
int aG = ((a & 0xff00) >> 8);
int aB = (a & 0xff);
int bA = (b >> 24 & 0xff);
int bR = ((b & 0xff0000) >> 16);
int bG = ((b & 0xff00) >> 8);
int bB = (b & 0xff);
int A = ((int)(aA * iRatio) + (int)(bA * ratio));
int R = ((int)(aR * iRatio) + (int)(bR * ratio));
int G = ((int)(aG * iRatio) + (int)(bG * ratio));
int B = ((int)(aB * iRatio) + (int)(bB * ratio));
return A << 24 | R << 16 | G << 8 | B;
}
一切似乎都很好,但某些论据会产生错误的颜色。 例如:
int a = 0xbbccdd;
int b = 0xbbccdd;
int c = blend(a, b, 0.5f); // gives 0xbaccdc, although it should be 0xbbccdd
我的猜测是浮动比率或者施法都要归咎于此,但我无法弄清楚它们有什么问题......
那么在java中混合两种颜色的正确方法是什么?
答案 0 :(得分:4)
我的猜测是,添加之后应该将int转换为int。喜欢这个
int a = (int)((aA * iRatio) + (bA * ratio));
我还建议在使用变量时使用Java命名约定。只有常数应该是上限。
答案 1 :(得分:3)
感谢JuliusB和dARKpRINCE。我已经将它改编为接受java.awt.Color,修复了强制转换并将变量重命名为更像Java标准。它运作良好。再次感谢!
Color blend( Color c1, Color c2, float ratio ) {
if ( ratio > 1f ) ratio = 1f;
else if ( ratio < 0f ) ratio = 0f;
float iRatio = 1.0f - ratio;
int i1 = c1.getRGB();
int i2 = c2.getRGB();
int a1 = (i1 >> 24 & 0xff);
int r1 = ((i1 & 0xff0000) >> 16);
int g1 = ((i1 & 0xff00) >> 8);
int b1 = (i1 & 0xff);
int a2 = (i2 >> 24 & 0xff);
int r2 = ((i2 & 0xff0000) >> 16);
int g2 = ((i2 & 0xff00) >> 8);
int b2 = (i2 & 0xff);
int a = (int)((a1 * iRatio) + (a2 * ratio));
int r = (int)((r1 * iRatio) + (r2 * ratio));
int g = (int)((g1 * iRatio) + (g2 * ratio));
int b = (int)((b1 * iRatio) + (b2 * ratio));
return new Color( a << 24 | r << 16 | g << 8 | b );
}
答案 2 :(得分:3)
感谢JuliusB,dARKpRINCE和bmauter 根据您的输入,我创建了以下功能,它将n种颜色以相等的比例混合:
public static Color blend(Color... c) {
if (c == null || c.length <= 0) {
return null;
}
float ratio = 1f / ((float) c.length);
int a = 0;
int r = 0;
int g = 0;
int b = 0;
for (int i = 0; i < c.length; i++) {
int rgb = c[i].getRGB();
int a1 = (rgb >> 24 & 0xff);
int r1 = ((rgb & 0xff0000) >> 16);
int g1 = ((rgb & 0xff00) >> 8);
int b1 = (rgb & 0xff);
a += ((int) a1 * ratio);
r += ((int) r1 * ratio);
g += ((int) g1 * ratio);
b += ((int) b1 * ratio);
}
return new Color(a << 24 | r << 16 | g << 8 | b);
}
答案 3 :(得分:1)
@ dARKpRINCE的回答是正确的,但我有一些小技巧:
您的函数应该是静态的,因为它不依赖于任何对象字段。
通过x >>> 24
代替(x >> 24) & 0xFF
提取颜色的alpha分量,可以保存一个操作。
任何形式:
(a * (1 - ratio)) + (b * ratio)
可以写成:
a + (b - a) * ratio
将你需要的乘法数减半。
答案 4 :(得分:0)
如果有人对在LibGDX中混合颜色感兴趣(基于上述解决方案,但针对LibGDX API量身定制):
static Color blend( Color c1, Color c2, float ratio ) {
if ( ratio > 1f ) ratio = 1f;
else if ( ratio < 0f ) ratio = 0f;
float iRatio = 1.0f - ratio;
int i1 = Color.argb8888(c1);
int i2 = Color.argb8888(c2);
int a1 = (i1 >> 24 & 0xff);
int r1 = ((i1 & 0xff0000) >> 16);
int g1 = ((i1 & 0xff00) >> 8);
int b1 = (i1 & 0xff);
int a2 = (i2 >> 24 & 0xff);
int r2 = ((i2 & 0xff0000) >> 16);
int g2 = ((i2 & 0xff00) >> 8);
int b2 = (i2 & 0xff);
int a = (int)((a1 * iRatio) + (a2 * ratio));
int r = (int)((r1 * iRatio) + (r2 * ratio));
int g = (int)((g1 * iRatio) + (g2 * ratio));
int b = (int)((b1 * iRatio) + (b2 * ratio));
return new Color(r << 24 | g << 16 | b << 8 | a);
}
答案 5 :(得分:0)
最简单的答案可能是:
public static Color mixColors(Color... colors) {
float ratio = 1f / ((float) colors.length);
int r = 0, g = 0, b = 0, a = 0;
for (Color color : colors) {
r += color.getRed() * ratio;
g += color.getGreen() * ratio;
b += color.getBlue() * ratio;
a += color.getAlpha() * ratio;
}
return new Color(r, g, b, a);
}