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)
{
ARGB result=0;
ARGB i;
INT a1, a2, a3;
INT start_a, end_a, final_a;
INT pos;
a1 = (start >> 24) & 0xff;
a2 = (end >> 24) & 0xff;
pos = gdip_round(position * 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)
result |= (int)((start&i)*(1.0f - position)+(end&i)*(position))&i;
return result;
if (final_a < 0xff) return 0;
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)