gdiplus: Don't use gdi32 to draw to bitmaps with formats it can't handle.

This commit is contained in:
Vincent Povirk 2010-03-28 22:25:20 -05:00 committed by Alexandre Julliard
parent af7b8efc94
commit 5433969ec8
2 changed files with 182 additions and 74 deletions

View file

@ -78,6 +78,29 @@ static inline REAL deg2rad(REAL degrees)
return M_PI * degrees / 180.0;
}
static inline ARGB color_over(ARGB bg, ARGB fg)
{
BYTE b, g, r, a;
BYTE bg_alpha, fg_alpha;
fg_alpha = (fg>>24)&0xff;
if (fg_alpha == 0xff) return fg;
if (fg_alpha == 0) return bg;
bg_alpha = (((bg>>24)&0xff) * (0xff-fg_alpha)) / 0xff;
if (bg_alpha == 0) return fg;
a = bg_alpha + fg_alpha;
b = ((bg&0xff)*bg_alpha + (fg&0xff)*fg_alpha)*0xff/a;
g = (((bg>>8)&0xff)*bg_alpha + ((fg>>8)&0xff)*fg_alpha)*0xff/a;
r = (((bg>>16)&0xff)*bg_alpha + ((fg>>16)&0xff)*fg_alpha)*0xff/a;
return (a<<24)|(r<<16)|(g<<8)|b;
}
extern const char *debugstr_rectf(CONST RectF* rc);
extern const char *debugstr_pointf(CONST PointF* pt);

View file

@ -1872,9 +1872,10 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
REAL srcheight, GpUnit srcUnit, GDIPCONST GpImageAttributes* imageAttributes,
DrawImageAbort callback, VOID * callbackData)
{
GpPointF ptf[3];
POINT pti[3];
GpPointF ptf[4];
POINT pti[4];
REAL dx, dy;
GpStatus stat;
TRACE("(%p, %p, %p, %d, %f, %f, %f, %f, %d, %p, %p, %p)\n", graphics, image, points,
count, srcx, srcy, srcwidth, srcheight, srcUnit, imageAttributes, callback,
@ -1887,7 +1888,9 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
debugstr_pointf(&points[2]));
memcpy(ptf, points, 3 * sizeof(GpPointF));
transform_and_round_points(graphics, pti, ptf, 3);
ptf[3].X = ptf[2].X + ptf[1].X - ptf[0].X;
ptf[3].Y = ptf[2].Y + ptf[1].Y - ptf[0].Y;
transform_and_round_points(graphics, pti, ptf, 4);
if (image->picture)
{
@ -1914,10 +1917,8 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
}
else if (image->type == ImageTypeBitmap && ((GpBitmap*)image)->hbitmap)
{
HDC hdc;
GpBitmap* bitmap = (GpBitmap*)image;
int temp_hdc=0, temp_bitmap=0;
HBITMAP hbitmap, old_hbm=NULL;
int use_software=0;
if (srcUnit == UnitInch)
dx = dy = 96.0; /* FIXME: use the image resolution */
@ -1926,83 +1927,167 @@ GpStatus WINGDIPAPI GdipDrawImagePointsRect(GpGraphics *graphics, GpImage *image
else
return NotImplemented;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
bitmap->format == PixelFormat24bppRGB ||
bitmap->format == PixelFormat32bppRGB ||
bitmap->format == PixelFormat32bppPARGB))
if (graphics->image && graphics->image->type == ImageTypeBitmap)
{
BITMAPINFOHEADER bih;
BYTE *temp_bits;
PixelFormat dst_format;
GpBitmap *dst_bitmap = (GpBitmap*)graphics->image;
if (!(dst_bitmap->format == PixelFormat16bppRGB555 ||
dst_bitmap->format == PixelFormat24bppRGB ||
dst_bitmap->format == PixelFormat32bppRGB))
use_software = 1;
}
/* we can't draw a bitmap of this format directly */
hdc = CreateCompatibleDC(0);
temp_hdc = 1;
temp_bitmap = 1;
if (use_software)
{
RECT src_area, dst_area;
int i, x, y;
GpMatrix *dst_to_src;
REAL m11, m12, m21, m22, mdx, mdy;
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;
src_area.left = srcx*dx;
src_area.top = srcy*dy;
src_area.right = (srcx+srcwidth)*dx;
src_area.bottom = (srcy+srcheight)*dy;
hbitmap = CreateDIBSection(hdc, (BITMAPINFO*)&bih, DIB_RGB_COLORS,
(void**)&temp_bits, NULL, 0);
dst_area.left = dst_area.right = pti[0].x;
dst_area.top = dst_area.bottom = pti[0].y;
for (i=1; i<4; i++)
{
if (dst_area.left > pti[i].x) dst_area.left = pti[i].x;
if (dst_area.right < pti[i].x) dst_area.right = pti[i].x;
if (dst_area.top > pti[i].y) dst_area.top = pti[i].y;
if (dst_area.bottom < pti[i].y) dst_area.bottom = pti[i].y;
}
m11 = (ptf[1].X - ptf[0].X) / srcwidth;
m12 = (ptf[2].X - ptf[0].X) / srcheight;
mdx = ptf[0].X - m11 * srcx - m12 * srcy;
m21 = (ptf[1].Y - ptf[0].Y) / srcwidth;
m22 = (ptf[2].Y - ptf[0].Y) / srcheight;
mdy = ptf[0].Y - m21 * srcx - m22 * srcy;
stat = GdipCreateMatrix2(m11, m12, m21, m22, mdx, mdy, &dst_to_src);
if (stat != Ok) return stat;
stat = GdipInvertMatrix(dst_to_src);
if (stat != Ok)
{
GdipDeleteMatrix(dst_to_src);
return stat;
}
for (x=dst_area.left; x<dst_area.right; x++)
{
for (y=dst_area.top; y<dst_area.bottom; y++)
{
GpPointF src_pointf;
int src_x, src_y;
ARGB src_color, dst_color;
src_pointf.X = x;
src_pointf.Y = y;
GdipTransformMatrixPoints(dst_to_src, &src_pointf, 1);
src_x = roundr(src_pointf.X);
src_y = roundr(src_pointf.Y);
if (src_x < src_area.left || src_x >= src_area.right ||
src_y < src_area.top || src_y >= src_area.bottom)
/* FIXME: Use wrapmode */
continue;
GdipBitmapGetPixel(bitmap, src_x, src_y, &src_color);
GdipBitmapGetPixel((GpBitmap*)graphics->image, x, y, &dst_color);
GdipBitmapSetPixel((GpBitmap*)graphics->image, x, y, color_over(dst_color, src_color));
}
}
GdipDeleteMatrix(dst_to_src);
}
else
{
HDC hdc;
int temp_hdc=0, temp_bitmap=0;
HBITMAP hbitmap, old_hbm=NULL;
if (!(bitmap->format == PixelFormat16bppRGB555 ||
bitmap->format == PixelFormat24bppRGB ||
bitmap->format == PixelFormat32bppRGB ||
bitmap->format == PixelFormat32bppPARGB))
{
BITMAPINFOHEADER bih;
BYTE *temp_bits;
PixelFormat dst_format;
/* we can't draw a bitmap of this format directly */
hdc = CreateCompatibleDC(0);
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);
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
dst_format = PixelFormat32bppPARGB;
else
dst_format = PixelFormat32bppRGB;
convert_pixels(bitmap->width, bitmap->height,
bitmap->width*4, temp_bits, dst_format,
bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries);
}
else
{
hbitmap = bitmap->hbitmap;
hdc = bitmap->hdc;
temp_hdc = (hdc == 0);
}
if (temp_hdc)
{
if (!hdc) hdc = CreateCompatibleDC(0);
old_hbm = SelectObject(hdc, hbitmap);
}
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
dst_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
dst_format = PixelFormat32bppRGB;
{
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);
}
convert_pixels(bitmap->width, bitmap->height,
bitmap->width*4, temp_bits, dst_format,
bitmap->stride, bitmap->bits, bitmap->format, bitmap->image.palette_entries);
if (temp_hdc)
{
SelectObject(hdc, old_hbm);
DeleteDC(hdc);
}
if (temp_bitmap)
DeleteObject(hbitmap);
}
else
{
hbitmap = bitmap->hbitmap;
hdc = bitmap->hdc;
temp_hdc = (hdc == 0);
}
if (temp_hdc)
{
if (!hdc) hdc = CreateCompatibleDC(0);
old_hbm = SelectObject(hdc, hbitmap);
}
if (bitmap->format & (PixelFormatAlpha|PixelFormatPAlpha))
{
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);
DeleteDC(hdc);
}
if (temp_bitmap)
DeleteObject(hbitmap);
}
else
{