Module: wine Branch: master Commit: 895c6d8e1ea81ae10f927463692c01bffd58fda5 URL: http://source.winehq.org/git/wine.git/?a=commit;h=895c6d8e1ea81ae10f92746369...
Author: Vincent Povirk vincent@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 {