The blend functions in juce_PixelFormat.h
do not work properly. The colors in some bitmaps come out wrong. I tracked this down to lack of component clamping in the blend functions used when drawing.
The good news is, here are the fixes!
This is a unified patch for modules\juce_graphics\colour\juce_PixelFormats.h
[code]@@ -87,27 +87,31 @@
forcedinline uint8& getAlpha() noexcept { return components.a; }
forcedinline uint8& getRed() noexcept { return components.r; }
forcedinline uint8& getGreen() noexcept { return components.g; }
forcedinline uint8& getBlue() noexcept { return components.b; }
#endif
+#define CMASK 0x00ff00ff
+
+#define CLAMP(_x) \
-
(((_x) & CMASK) | (((_x) >> 8) & CMASK) * 0xff)
-
/** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends it accordingly.
*/
template
forcedinline void blend (const Pixel& src) noexcept
{
-
uint32 sargb = src.getARGB();
-
const uint32 alpha = 0x100 - (sargb >> 24);
-
sargb += 0x00ff00ff & ((getRB() * alpha) >> 8);
-
sargb += 0xff00ff00 & (getAG() * alpha);
-
argb = sargb;
-
const uint32 alpha = 0x100 - src.getAlpha();
-
uint32 rb = src.getRB() + ((getRB() * alpha >>8) & CMASK);
-
uint32 ag = src.getAG() + ((getAG() * alpha >>8) & CMASK);
-
argb = CLAMP(rb) + (CLAMP(ag)<<8);
}
/** Blends another pixel onto this one.
This takes into account the opacity of the pixel being overlaid, and blends it accordingly.
@@ -120,23 +124,21 @@
The opacity of the pixel being overlaid is scaled by the extraAlpha factor before
being used, so this can blend semi-transparently from a PixelRGB argument.
*/
template
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
{
-
++extraAlpha;
-
//++extraAlpha;
-
uint32 sargb = ((extraAlpha * src.getAG()) & 0xff00ff00)
-
| (((extraAlpha * src.getRB()) >> 8) & 0x00ff00ff);
-
const uint32 alpha = 0x100 - (sargb >> 24);
-
sargb += 0x00ff00ff & ((getRB() * alpha) >> 8);
-
sargb += 0xff00ff00 & (getAG() * alpha);
-
uint32 ag = (extraAlpha*src.getAG() >> 8) & CMASK;
-
const uint32 alpha = 0x100 - (ag >> 16);
-
ag += (getAG()*alpha >> 8) & CMASK;
-
uint32 rb = ((extraAlpha*src.getRB() >> 8) & CMASK) + ((getRB()*alpha >> 8) & CMASK);
-
argb = sargb;
-
argb = CLAMP(rb) + (CLAMP(ag)<<8);
}
/** Blends another pixel with this one, creating a colour that is somewhere
between the two, as specified by the amount.
*/
template
@@ -344,21 +346,23 @@
This takes into account the opacity of the pixel being overlaid, and blends
it accordingly.
*/
template
forcedinline void blend (const Pixel& src) noexcept
{
-
uint32 sargb = src.getARGB();
-
const uint32 alpha = 0x100 - (sargb >> 24);
-
const uint32 alpha = 0x100 - src.getAlpha();
-
sargb += 0x00ff00ff & ((getRB() * alpha) >> 8);
-
sargb += 0x0000ff00 & (g * alpha);
-
uint32 rb = src.getRB() + ((getRB()*alpha >> 8) & CMASK);
-
uint32 ag = src.getAG() + (g*alpha >> 8);
-
rb = CLAMP(rb);
-
ag = CLAMP(ag);
-
r = (uint8) (sargb >> 16);
-
g = (uint8) (sargb >> 8);
-
b = (uint8) sargb;
-
r = (uint8) (rb >> 16);
-
g = (uint8) ag;
-
b = (uint8) rb;
}
forcedinline void blend (const PixelRGB src) noexcept
{
set (src);
}
@@ -368,25 +372,25 @@
The opacity of the pixel being overlaid is scaled by the extraAlpha factor before
being used, so this can blend semi-transparently from a PixelRGB argument.
*/
template
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
{
-
++extraAlpha;
-
const uint32 srb = (extraAlpha * src.getRB()) >> 8;
-
const uint32 sag = extraAlpha * src.getAG();
-
uint32 sargb = (sag & 0xff00ff00) | (srb & 0x00ff00ff);
-
// ++extraAlpha;
-
uint32 ag = (extraAlpha*src.getAG() >> 8) & CMASK;
-
const uint32 alpha = 0x100 - (ag >> 16);
-
ag += g*alpha >> 8;
-
const uint32 alpha = 0x100 - (sargb >> 24);
-
uint32 rb = ((extraAlpha*src.getRB() >> 8) & CMASK) + ((getRB()*alpha >> 8) & CMASK);
-
sargb += 0x00ff00ff & ((getRB() * alpha) >> 8);
-
sargb += 0x0000ff00 & (g * alpha);
-
rb = CLAMP(rb);
-
ag = CLAMP(ag);
-
b = (uint8) sargb;
-
g = (uint8) (sargb >> 8);
-
r = (uint8) (sargb >> 16);
-
b = (uint8) rb;
-
g = (uint8) ag;
-
r = (uint8) (rb >> 16);
}
/** Blends another pixel with this one, creating a colour that is somewhere
between the two, as specified by the amount.
*/
template
[/code]