【问题标题】:Converting ARGB to RGB in java在java中将ARGB转换为RGB
【发布时间】:2015-07-14 12:22:07
【问题描述】:

我正在尝试一些算法来编写一种从颜色中删除 alpha 值并给出相同 rgb 值的方法,但似乎我的测试总是失败。我相信它被称为阿尔法混合?我不确定。这是我用于转换的算法。

public static int removeAlpha(int foreground, int background) {
        int redForeground = Color.red(foreground);
        int redBackground = Color.red(background);
        int greenForeground = Color.green(foreground);
        int greenBackground = Color.green(background);
        int blueForeground = Color.blue(foreground);
        int blueBackground = Color.blue(background);
        int alphaForeground = Color.alpha(foreground);
        int redNew = (redForeground * alphaForeground) + (redBackground * (1 - alphaForeground));
        int greenNew = (greenForeground * alphaForeground) + (greenBackground * (1 - alphaForeground));
        int blueNew = (blueForeground * alphaForeground) + (blueBackground * (1 - alphaForeground));
        return Color.rgb(redNew, greenNew, blueNew);
    }

还有这样的测试

@Test
    public void removeAlpha() {
        int red = Color.RED;
        Assert.assertEquals(0xFFFF7F7F, Heatmap.removeAlpha(red, 0xFFFFFFFF));
    }

junit.framework.AssertionFailedError: 
Expected :-32897
Actual   :-258

当我在 Photoshop 中绘制红色并将不透明度设置为 50% 时,它给了我 255,127,127 rgb,这似乎与 50% 不透明的纯红色相同。我认为那里的算法是错误的。任何帮助将不胜感激。

编辑:这是模拟颜色:

 PowerMockito.mockStatic(Color.class);
        PowerMockito.when(Color.rgb(Mockito.anyInt(), Mockito.anyInt(), Mockito.anyInt())).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                int red = (int) invocation.getArguments()[0];
                int green = (int) invocation.getArguments()[1];
                int blue = (int) invocation.getArguments()[2];
                return (0xFF << 24) | (red << 16) | (green << 8) | blue;
            }
        });
        PowerMockito.when(Color.alpha(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return ((int)invocation.getArguments()[0])>>>24;
            }
        });
        PowerMockito.when(Color.red(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return (((int)invocation.getArguments()[0])>>16) & 0xFF;
            }
        });
        PowerMockito.when(Color.green(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return (((int)invocation.getArguments()[0])>>8) & 0XFF;
            }
        });
        PowerMockito.when(Color.blue(Mockito.anyInt())).thenAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                return (int)invocation.getArguments()[0] & 0xFF;
            }
        });

【问题讨论】:

  • 哦忘了提到我嘲笑了 Color 静态类,但这并不重要。我只是嘲笑他们,因为junit不会让我不嘲笑他们。我只是使用了它们的源代码,所以它们工作正常。
  • 您的公式似乎是正确的。然而,我认识到你忽略了alphaBackground。但这不是问题,因为您的测试用例将此属性设置为 100%。
  • 您将颜色值视为[0, 1] 之间的范围。您的 Color.xx 函数是否有可能返回 [0, 255] 的值?
  • @maja 是的,那是因为我认为背景颜色将始终完全不透明,以免使事情复杂化。
  • 尝试用255-替换公式中的1-

标签: java android colors


【解决方案1】:

注意:我不是很喜欢java,所以我可能是错的。我只是使用常见的编程概念,因此可能需要进行一些调整。

我认为您在弄乱数据类型...您正在获取颜色的整数表示形式,即 0-255,并将其相乘,就好像它是 0-1 表示形式一样。试试这个:

double alphaForeground = ((double)Color.alpha(foreground)) / 255.0;
int redNew = ((int)round((redForeground * alphaForeground) + (redBackground * (1 - alphaForeground))));
int greenNew = ((int)round((greenForeground * alphaForeground) + (greenBackground * (1 - alphaForeground))));
int blueNew = ((int)round((blueForeground * alphaForeground) + (blueBackground * (1 - alphaForeground))));

可能存在舍入问题,但是……这应该可行。

还有一句话:Color.RED 有一个 255 alpha 通道。这意味着 removeAlpha(red, 0xFFFFFFFF) 返回红色本身,而不是 0xFFFF7F7F。为了获得该值,您应该编写

int red = Color.RED;
red.alpha = 0x80;

(或某个接近的值)

【讨论】:

  • 我认为在这种情况下 255 更好,因为使用 256 你永远不会有 100% 的不透明度......但是,255 与 256 的误差小于 0.4% ;)
【解决方案2】:

您的公式将 1 视为 100%,但您的颜色函数返回/期望值在 [0, 255] 范围内,这意味着 255 = 100%

您必须使用以下公式:

newColor = (colorA * opacityA + colorB * (255 - opacityA)) / 255

示例:

foreground = 256
background = 0
foreground-alpha = 25%

[0,255]的范围内,25%等于63。T 这个例子的结果应该是 63,因为 foreground * 25% + background * 75%63

所以为了获得 75%,你需要100% - 25% = 256 - 63 = 193

第二个问题:

你的测试用例是错误的。您正在使用100% red + 100% white,这应该会导致 100% 红色,而不是 0xFFFF7F7F

正如@frarugi87 在他的回答中所说,您首先必须将红色的 Alpha 通道设置为 50%。

【讨论】:

  • 嗯.. 是的,你是对的,我改变了它,但测试仍然失败。我会尝试重新制定它并再试一次。谢谢
  • 这不是真的,因为 255 的不透明度会导致 colorA 增加。正确的公式是(colorA * opacityA + colorB * (255 - opacityA))/255,但我认为我的解决方案(将 alpha 通道转换为 0-1)更好
  • 看来公式是一样的。但是结果还是不行。预期:-32897 实际:-16711680
  • @BarışcanKayaoğlu 你的测试用例是错误的。我更新了我的答案
  • @BarışcanKayaoğlu 不,不要编辑您的原始问题以响应已经给出的答案。这不应该在 SE 网站上进行。相反,在您的问题中使用 cmets 或和“编辑”块来添加其他信息。
【解决方案3】:

试试这个:

int color = Color.argb(255, 118, 118, 188);

【讨论】:

  • 我想你误解了我的意思。我要做的是用 alpha 获取颜色的 rgb 值,这意味着使用不同的红色、绿色和蓝色值使其完全不透明。
  • @BarışcanKayaoğlu,抱歉...我只看到函数名称 removeAlpha,据我所知,这是删除 alpha 的正确方法
  • @BarışcanKayaoğlu 要删除 alpha,正如 Alexander 正确显示的那样,只需将其值拉到最大不透明度 (255)
  • 不,不一样.. 128,R,G,B != R,G,B 因为 50% 的 alpha 会完全改变颜色。这就是断言失败的原因。我说你需要移除 alpha 但保持颜色相同,这就是所谓的 alpha blending。
  • @BarışcanKayaoğlu 没有人谈论过128,R,G,B。我们说:255,R,G,B.
猜你喜欢
  • 2011-07-27
  • 2017-06-29
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多