skip to Main Content

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

3

Answers


  1. Try this:

    int color = Color.argb(255, 118, 118, 188);
    
    Login or Signup to reply.
  2. 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%.

    Login or Signup to reply.
  3. 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, i.e. 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)

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search