Vincent Povirk : gdiplus: Use AlphaBlend for 32-bit images with alpha channels.

Alexandre Julliard julliard at winehq.org
Sat Aug 29 11:36:23 CDT 2009


Module: wine
Branch: master
Commit: 895c6d8e1ea81ae10f927463692c01bffd58fda5
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=895c6d8e1ea81ae10f927463692c01bffd58fda5

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Fri Aug 28 17:21:10 2009 -0500

gdiplus: Use AlphaBlend for 32-bit images with alpha channels.

---

 dlls/gdiplus/gdiplus.c         |   19 +++++++++++
 dlls/gdiplus/gdiplus_private.h |    3 ++
 dlls/gdiplus/graphics.c        |   71 +++++++++++++++++++++++++++++++++------
 3 files changed, 82 insertions(+), 11 deletions(-)

diff --git a/dlls/gdiplus/gdiplus.c b/dlls/gdiplus/gdiplus.c
index 06019a2..ec956f3 100644
--- a/dlls/gdiplus/gdiplus.c
+++ b/dlls/gdiplus/gdiplus.c
@@ -399,6 +399,25 @@ BOOL lengthen_path(GpPath *path, INT len)
     return TRUE;
 }
 
+void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
+    BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride)
+{
+    UINT x, y;
+    for (y=0; y<height; y++)
+    {
+        const BYTE *src=src_bits+y*src_stride;
+        BYTE *dst=dst_bits+y*dst_stride;
+        for (x=0; x<width; x++)
+        {
+            BYTE alpha=src[3];
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++ * alpha / 255;
+            *dst++ = *src++;
+        }
+    }
+}
+
 /* recursive deletion of GpRegion nodes */
 inline void delete_element(region_element* element)
 {
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 5e615e1..e87176e 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -80,6 +80,9 @@ static inline REAL deg2rad(REAL degrees)
 
 extern const char *debugstr_rectf(CONST RectF* rc);
 
+extern void convert_32bppARGB_to_32bppPARGB(UINT width, UINT height,
+    BYTE *dst_bits, INT dst_stride, const BYTE *src_bits, INT src_stride);
+
 struct GpPen{
     UINT style;
     GpUnit unit;
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index a455d45..1df3eee 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -1877,8 +1877,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
     {
         HDC hdc;
         GpBitmap* bitmap = (GpBitmap*)image;
-        int bm_is_selected;
-        HBITMAP old_hbm=NULL;
+        int temp_hdc=0, temp_bitmap=0;
+        HBITMAP hbitmap, old_hbm=NULL;
 
         if (srcUnit == UnitInch)
             dx = dy = 96.0; /* FIXME: use the image resolution */
@@ -1887,24 +1887,73 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
         else
             return NotImplemented;
 
-        hdc = bitmap->hdc;
-        bm_is_selected = (hdc != 0);
-
-        if (!bm_is_selected)
+        if (bitmap->format == PixelFormat32bppARGB)
         {
+            BITMAPINFOHEADER bih;
+            BYTE *temp_bits;
+
+            /* we need a bitmap with premultiplied alpha */
             hdc = CreateCompatibleDC(0);
-            old_hbm = SelectObject(hdc, bitmap->hbitmap);
+            temp_hdc = 1;
+            temp_bitmap = 1;
+
+            bih.biSize = sizeof(BITMAPINFOHEADER);
+            bih.biWidth = bitmap->width;
+            bih.biHeight = -bitmap->height;
+            bih.biPlanes = 1;
+            bih.biBitCount = 32;
+            bih.biCompression = BI_RGB;
+            bih.biSizeImage = 0;
+            bih.biXPelsPerMeter = 0;
+            bih.biYPelsPerMeter = 0;
+            bih.biClrUsed = 0;
+            bih.biClrImportant = 0;
+
+            hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
+                (void**)&temp_bits, NULL, 0);
+
+            convert_32bppARGB_to_32bppPARGB(bitmap->width, bitmap->height,
+                temp_bits, bitmap->width*4, bitmap->bits, bitmap->stride);
+        }
+        else
+        {
+            hbitmap = bitmap->hbitmap;
+            hdc = bitmap->hdc;
+            temp_hdc = (hdc == 0);
+        }
+
+        if (temp_hdc)
+        {
+            if (!hdc) hdc = CreateCompatibleDC(0);
+            old_hbm = SelectObject(hdc, hbitmap);
         }
 
-        /* FIXME: maybe alpha blend depending on the format */
-        StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
-            hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY);
+        if (bitmap->format == PixelFormat32bppARGB || bitmap->format == PixelFormat32bppPARGB)
+        {
+            BLENDFUNCTION bf;
+
+            bf.BlendOp = AC_SRC_OVER;
+            bf.BlendFlags = 0;
+            bf.SourceConstantAlpha = 255;
+            bf.AlphaFormat = AC_SRC_ALPHA;
+
+            GdiAlphaBlend(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+                hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, bf);
+        }
+        else
+        {
+            StretchBlt(graphics->hdc, pti[0].x, pti[0].y, pti[1].x-pti[0].x, pti[2].y-pti[0].y,
+                hdc, srcx*dx, srcy*dy, srcwidth*dx, srcheight*dy, SRCCOPY);
+        }
 
-        if (!bm_is_selected)
+        if (temp_hdc)
         {
             SelectObject(hdc, old_hbm);
             DeleteDC(hdc);
         }
+
+        if (temp_bitmap)
+            DeleteObject(hbitmap);
     }
     else
     {




More information about the wine-cvs mailing list