简体   繁体   中英

Converting ARGB to RGB in java

I'm trying some algorithms to write a method to remove alpha value from a color and give its identical rgb values but seems my test is always failing. I belive it is called alpha blending? I'm not sure. This is the algorithm I use for converting.

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);
    }

And the test like this

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

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

when i draw red in photoshop and set the opacity to 50%, it gives me 255,127,127 rgb which seems identical to 50% opaque pure red. I think there the algorithm is false. Any helps would be appreciated.

Edit: Here are the mock Color:

 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;
            }
        });

Your formula treats 1 as 100%, but your Color functions are returning / expecting values in the range of [0, 255] , which means that 255 = 100% .

You have to use the following formula:

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

Example:

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

In the range of [0,255] , 25% are equal to 63. T he result of this example should be 63 since foreground * 25% + background * 75% is 63 .

So in order to get the 75%, you need 100% - 25% = 256 - 63 = 193

Second problem:

Your test case is wrong. You are taking 100% red + 100% white which should result in 100% red, not 0xFFFF7F7F .

As @frarugi87 said in his answer, you first have to set red's alpha channel to 50%.

NOTE: I'm not really into java, so I can be wrong. I'm just using common programming notions, so some tweakings can be needed.

I think you are messing with data types... You are getting the integer representation of your color, ie 0-255, and multiplying it as if it was a 0-1 representation. Try this:

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))));

There can be rounding issues, but... this should work.

Just another remark: Color.RED has a 255 alpha channel. This means that removeAlpha(red, 0xFFFFFFFF) returns red itself, not 0xFFFF7F7F. In order to get that value you should write

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

(or some close value)

尝试这个:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM