Open jbeda opened 5 years ago
I poked through the source for this in PImage.java and I wasn't able to reach a conclusion. I'm not sure if the language is wrong or the math. @benfry, what do you think?
/**
* Blend
* O = S
*/
private static int blend_blend(int dst, int src) {
int a = src >>> 24;
int s_a = a + (a >= 0x7F ? 1 : 0);
int d_a = 0x100 - s_a;
return min((dst >>> 24) + a, 0xFF) << 24 |
((dst & RB_MASK) * d_a + (src & RB_MASK) * s_a) >>> 8 & RB_MASK |
((dst & GN_MASK) * d_a + (src & GN_MASK) * s_a) >>> 8 & GN_MASK;
}
I stumbled upon this issue and here are my 2 cents:
The first issue is that the documentation doesn't make it entirely clear what factor
refers to. (Judging from the source code, it refers to the alpha channel of the source pixels.)
And, I can confirm that the documentation is indeed wrong about BLEND - linear interpolation of colors: C = A*factor + B. This is the default.
. The slightly arcane code basically does the following
private static final int RB_MASK = 0x00FF00FF;
private static final int GN_MASK = 0x0000FF00;
private static int blend_blend(int dst, int src) {
// Get the alpha channel from the source
int a = src >>> 24;
// Probably to fix some off by one errors
int s_a = a + (a >= 0x7F ? 1 : 0);
// 256 - alpha! This is the part that's missing from the documentation
int d_a = 0x100 - s_a;
return
// Not entirely sure what this exactly does, but it's responsible for setting the alpha channel. It usually sets it to 255
min((dst >>> 24) + a, 0xFF) << 24 |
// Then, we're interpolating the colors.
// Since the color is stored in a single integer (ARGB), a simple lerp like (dst * d_a) + (src * s_a)
// could cause color components to overflow or underflow into the surrounding bytes/components
// So, the RB_MASK masks the red and blue components. (a funky little optimisation)
// Then they're lerped and overflows are taken care of. Afterwards, the green component gets masked and lerped.
// Lastly, the results are joined together.
((dst & RB_MASK) * d_a + (src & RB_MASK) * s_a) >>> 8 & RB_MASK |
((dst & GN_MASK) * d_a + (src & GN_MASK) * s_a) >>> 8 & GN_MASK;
}
Issue description
The docs state:
But linear interpolation would be
C = A*factor + B*(1-factor)
. As documented it is more like ADD without clamping.URL(s) of affected page(s)
https://processing.org/reference/blendMode_.html https://processing.org/reference/blend_.html
Proposed fix