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

This commit is contained in:
Vincent Povirk 2009-08-28 17:21:10 -05:00 committed by Alexandre Julliard
parent 7fdc0208e8
commit 895c6d8e1e
3 changed files with 82 additions and 11 deletions

View File

@ -399,6 +399,25 @@ BOOL lengthen_path(GpPath *path, INT len)
return TRUE; 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 */ /* recursive deletion of GpRegion nodes */
inline void delete_element(region_element* element) inline void delete_element(region_element* element)
{ {

View File

@ -80,6 +80,9 @@ static inline REAL deg2rad(REAL degrees)
extern const char *debugstr_rectf(CONST RectF* rc); 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{ struct GpPen{
UINT style; UINT style;
GpUnit unit; GpUnit unit;

View File

@ -1877,8 +1877,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
{ {
HDC hdc; HDC hdc;
GpBitmap* bitmap = (GpBitmap*)image; GpBitmap* bitmap = (GpBitmap*)image;
int bm_is_selected; int temp_hdc=0, temp_bitmap=0;
HBITMAP old_hbm=NULL; HBITMAP hbitmap, old_hbm=NULL;
if (srcUnit == UnitInch) if (srcUnit == UnitInch)
dx = dy = 96.0; /* FIXME: use the image resolution */ dx = dy = 96.0; /* FIXME: use the image resolution */
@ -1887,24 +1887,73 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else else
return NotImplemented; return NotImplemented;
hdc = bitmap->hdc; if (bitmap->format == PixelFormat32bppARGB)
bm_is_selected = (hdc != 0);
if (!bm_is_selected)
{ {
BITMAPINFOHEADER bih;
BYTE *temp_bits;
/* we need a bitmap with premultiplied alpha */
hdc = CreateCompatibleDC(0); 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);
} }
/* FIXME: maybe alpha blend depending on the format */ if (temp_hdc)
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 (!hdc) hdc = CreateCompatibleDC(0);
old_hbm = SelectObject(hdc, hbitmap);
}
if (!bm_is_selected) 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 (temp_hdc)
{ {
SelectObject(hdc, old_hbm); SelectObject(hdc, old_hbm);
DeleteDC(hdc); DeleteDC(hdc);
} }
if (temp_bitmap)
DeleteObject(hbitmap);
} }
else else
{ {