gdiplus: Fix blend_colors when alpha channel differs.

Vincent Povirk madewokherd at gmail.com
Tue Mar 24 13:17:32 CDT 2015


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.
-------------- next part --------------
From 05de5fd798155ed9b273a4ad2b0f7b9ed45ffd5c Mon Sep 17 00:00:00 2001
From: Vincent Povirk <vincent at codeweavers.com>
Date: Tue, 24 Mar 2015 12:50:18 -0500
Subject: [PATCH] gdiplus: Fix blend_colors when alpha channel differs.

---
 dlls/gdiplus/graphics.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index ae530a9..580390f 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -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)
-- 
2.1.0



More information about the wine-patches mailing list