gdiplus: Fix blend_colors when alpha channel differs.

When picking a color halfway between 100% white (0xffffffff) and fully
transparent (0x00000000), the result was 50% opaque 50% grey
(0x80808080) when it should really be 50% opaque white (0x80ffffff).
This had a tendency to create grey fringes on things. The fix is to
weight the non-alpha components based on how much they contribute to
the final alpha value.
This commit is contained in:
Vincent Povirk 2015-03-24 12:50:18 -05:00 committed by Alexandre Julliard
parent e95dbb3b74
commit 9c579023f0
1 changed files with 12 additions and 10 deletions

View File

@ -521,20 +521,22 @@ static GpStatus alpha_blend_pixels(GpGraphics *graphics, INT dst_x, INT dst_y,
static ARGB blend_colors(ARGB start, ARGB end, REAL position) static ARGB blend_colors(ARGB start, ARGB end, REAL position)
{ {
ARGB result=0; INT start_a, end_a, final_a;
ARGB i; INT pos;
INT a1, a2, a3;
a1 = (start >> 24) & 0xff; pos = gdip_round(position * 0xff);
a2 = (end >> 24) & 0xff;
a3 = (int)(a1*(1.0f - position)+a2*(position)); start_a = ((start >> 24) & 0xff) * (pos ^ 0xff);
end_a = ((end >> 24) & 0xff) * pos;
result |= a3 << 24; final_a = start_a + end_a;
for (i=0xff; i<=0xff0000; i = i << 8) if (final_a < 0xff) return 0;
result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
return result; return (final_a / 0xff) << 24 |
((((start >> 16) & 0xff) * start_a + (((end >> 16) & 0xff) * end_a)) / final_a) << 16 |
((((start >> 8) & 0xff) * start_a + (((end >> 8) & 0xff) * end_a)) / final_a) << 8 |
(((start & 0xff) * start_a + ((end & 0xff) * end_a)) / final_a);
} }
static ARGB blend_line_gradient(GpLineGradient* brush, REAL position) static ARGB blend_line_gradient(GpLineGradient* brush, REAL position)