Setting pixel Alpha to 0 changes RGB values as well?

Hey all -

I think I am not understanding something about how colours get resampled when an image is rescaled.

I have 2 images, both ARGB and cleared.

In the image below I am drawing a green circle on one image and then copy that image to the second image while applying an Affinetransform (rescaling), then copying it back (for feedback).

This is the standard way to do this sort of recursive drawing (think, winamp visualization, etc).

Anyway, I can’t figure out why I’m getting any black in there … I know that it does some resampling / antialiasing … which (I would think) would mean that some pixels start to fade away, as opposed to darkening.

Graphics instGraphic1(outlineCanvas);
Graphics instGraphic2(outlineCanvasTransformed);

// periodically draw a green circle
if (circle%70 == 0)
{
    instGraphic1.setColour(Colours::green);
    instGraphic1.drawEllipse(100, 100, 200, 200, 5);
    circle = 0;
}

circle++;

// feedback ->
instGraphic2.drawImageTransformed(outlineCanvas, AffineTransform::scale(1.01, 1.01, 200, 200));
instGraphic1.drawImageAt(outlineCanvasTransformed, 0, 0);

g.drawImageAt(outlineCanvas, 0, 0);

Surely, someone knows the answer here …

The cleared images are filled with transparent black. When green ist blended during the interpolation with the transparent black the result is darker and slightly transparent green. Simplified example (r, g, b, a):

blended = 0.5*a + 0.5*b
(0.0, 0.5, 0.0, 0.5) = 0.5*(0, 0, 0, 0) + 0.5*(0,1,0,1)

You can clear your image to transparent green instead, then it won’t darken during interpolation.

Well, this is a good point, but the fault is in my example.

Let me try and demonstrate the problem this way:

Here is a simple test that illustrates that
when alpha goes to 0, the color becomes black, regardless of starting color:

    // clear the image to WHITE
    myImage.clear(outlineCanvas.getBounds(), Colours::white);
    
    // now MULTIPLY all alphas 
    myImage.multiplyAllAlphas(0.0f);
   
    // GRAB a pixel, and bring transparency back up
    px = outlineCanvas.getPixelAt(0, 0).getPixelARGB();
    Colour c2(px);
    c2 = c2.withAlpha(1.0f);
    
    // Is it still the same color? 
    // Or is it now transparentBlack ??
    jassert(c2 == Colours::white); // This FAILS

Presumably, we would want to RGB values to be maintained even when transparency becomes 0?

The problem I am having is that whatever the initial color is, once I multiply the transparency some number of times it gets close enough to 0 that the RGB values become 0 as well (ie, black).

I should also note that this is NOT how it behaves with just a Colour. So, Colours::white with multiplied Alpha to 0, then back to 1, will still be white. It’s only with image pixel data.

Premultiplied alpha?

Or maybe the blending isn’t gamma correct? (Alpha compositing - Wikipedia)

I’m not convinced that your two examples illustrate the same thing. But TBH now I don’t really understand what the issue is - i.e. what you expect your image to look like. I.e. what exactly is getting unexpectedly darker? Maybe draw a big fat arrow or something :relaxed:

1 Like

You may just

auto c2{ outlineCanvas.getPixelAt(0, 0) };

PixelARGB uses premultiplied alpha -it’s stated everywhere in the docs. After multiplyAllAlphas (0.0f), RGB values are lost. As you have seen, this doesn’t happen with Colour. Any operations that require preserving RGB through alpha changes cannot be done on Images directly. You can see some discussion about it here.

Yeah, that’s it alright. Thanks a bunch.

I can understand not wanting to rewrite the rendering engine but it sure would be cool to have multiple blending modes.

Of course, juce can’t do everything, eh? Thanks for the linked discussion.

For anyone else who gets here but hasn’t come across premultiplied alpha before, there is another great discussion here: