diff --git a/src/image.c b/src/image.c index cd47f246c..add797f9e 100644 --- a/src/image.c +++ b/src/image.c @@ -446,8 +446,7 @@ GdipDrawImageRect (GpGraphics *graphics, GpImage *image, REAL x, REAL y, REAL wi /* Create a surface for this bitmap if one doesn't exist */ gdip_bitmap_ensure_surface (image); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (image)) { + if (gdip_bitmap_format_needs_premultiplication (image)) { premul = gdip_bitmap_get_premultiplied_scan0 (image); if (premul) { BitmapData *data = image->active_bitmap; @@ -554,8 +553,7 @@ GdipDrawImagePoints (GpGraphics *graphics, GpImage *image, GDIPCONST GpPointF *d /* Create a surface for this bitmap if one doesn't exist */ gdip_bitmap_ensure_surface (image); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (image)) { + if (gdip_bitmap_format_needs_premultiplication (image)) { premul = gdip_bitmap_get_premultiplied_scan0 (image); if (premul) { BitmapData *data = image->active_bitmap; @@ -745,8 +743,7 @@ GdipDrawImageRectRect (GpGraphics *graphics, GpImage *image, gdip_flip_x (imgflipX); gdip_bitmap_ensure_surface (imgflipX); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (imgflipX)) { + if (gdip_bitmap_format_needs_premultiplication (imgflipX)) { premulX = gdip_bitmap_get_premultiplied_scan0 (imgflipX); if (premulX) { BitmapData *data = imgflipX->active_bitmap; @@ -764,8 +761,7 @@ GdipDrawImageRectRect (GpGraphics *graphics, GpImage *image, gdip_flip_y (imgflipY); gdip_bitmap_ensure_surface (imgflipY); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (imgflipY)) { + if (gdip_bitmap_format_needs_premultiplication (imgflipY)) { premulY = gdip_bitmap_get_premultiplied_scan0 (imgflipY); if (premulY) { BitmapData *data = imgflipY->active_bitmap; @@ -784,8 +780,7 @@ GdipDrawImageRectRect (GpGraphics *graphics, GpImage *image, gdip_flip_y (imgflipXY); gdip_bitmap_ensure_surface (imgflipXY); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (imgflipXY)) { + if (gdip_bitmap_format_needs_premultiplication (imgflipXY)) { premulXY = gdip_bitmap_get_premultiplied_scan0 (imgflipXY); if (premulXY) { BitmapData *data = imgflipXY->active_bitmap; @@ -800,8 +795,7 @@ GdipDrawImageRectRect (GpGraphics *graphics, GpImage *image, gdip_bitmap_ensure_surface (image); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (image)) { + if (gdip_bitmap_format_needs_premultiplication (image)) { premul = gdip_bitmap_get_premultiplied_scan0 (image); if (premul) { BitmapData *data = image->active_bitmap; @@ -896,8 +890,7 @@ GdipDrawImageRectRect (GpGraphics *graphics, GpImage *image, gdip_bitmap_ensure_surface (image); - if (graphics->type != gtMemoryBitmap && - gdip_bitmap_format_needs_premultiplication (image)) { + if (gdip_bitmap_format_needs_premultiplication (image)) { premul = gdip_bitmap_get_premultiplied_scan0 (image); if (premul) { BitmapData *data = image->active_bitmap; diff --git a/src/imageattributes.c b/src/imageattributes.c index e0841d272..8ff1f4ff5 100644 --- a/src/imageattributes.c +++ b/src/imageattributes.c @@ -221,6 +221,7 @@ gdip_process_bitmap_attributes (GpBitmap *bitmap, void **dest, GpImageAttributes ARGB *scan; ColorMatrixFlags flags = cmatrix->colormatrix_flags; ColorMatrix *cm; + BOOL bmpdest_is_premultiplied = !gdip_bitmap_format_needs_premultiplication (bmpdest); for (y = 0; y < data->height; y++) { scan = (ARGB*) v; @@ -244,7 +245,7 @@ gdip_process_bitmap_attributes (GpBitmap *bitmap, void **dest, GpImageAttributes } a_new = (r * cm->m[0][3] + g * cm->m[1][3] + b * cm->m[2][3] + a * cm->m[3][3] + (255 * cm->m[4][3])); - if (a_new == 0) { + if (a_new == 0 && bmpdest_is_premultiplied) { /* 100% transparency, don't waste time computing other values (pre-mul will always be 0) */ *scan++ = 0; } else { @@ -252,16 +253,26 @@ gdip_process_bitmap_attributes (GpBitmap *bitmap, void **dest, GpImageAttributes g_new = (r * cm->m[0][1] + g * cm->m[1][1] + b * cm->m[2][1] + a * cm->m[3][1] + (255 * cm->m[4][1])); b_new = (r * cm->m[0][2] + g * cm->m[1][2] + b * cm->m[2][2] + a * cm->m[3][2] + (255 * cm->m[4][2])); + if (bmpdest_is_premultiplied && a != (BYTE) a_new && a < 0xff && a != 0) { + /* reverse previous pre-multiplication if necessary */ + r_new = r_new * 255 / a; + g_new = g_new * 255 / a; + b_new = b_new * 255 / a; + } + r = (r_new > 0xff) ? 0xff : (BYTE) r_new; g = (g_new > 0xff) ? 0xff : (BYTE) g_new; b = (b_new > 0xff) ? 0xff : (BYTE) b_new; /* remember that Cairo use pre-multiplied alpha, e.g. 50% red == 0x80800000 not 0x80ff0000 */ - a = (BYTE) a_new; - if (a < 0xff) { + if (bmpdest_is_premultiplied && a != (BYTE) a_new && a_new < 0xff) { + /* apply new pre-multiplication */ + a = (BYTE) a_new; r = pre_multiplied_table [r][a]; g = pre_multiplied_table [g][a]; b = pre_multiplied_table [b][a]; + } else { + a = (BYTE) a_new; } set_pixel_bgra (color_p, 0, b, g, r, a); diff --git a/tests/testgraphics.c b/tests/testgraphics.c index db076a921..3093bb82c 100644 --- a/tests/testgraphics.c +++ b/tests/testgraphics.c @@ -2050,6 +2050,34 @@ static void test_region_mask() GdipDisposeImage (bitmap); } +static void test_premultiplication () +{ + GpStatus status; + GpBitmap *bitmap; + GpBitmap *bitmapBackground; + GpGraphics *graphicsBackground; + + BYTE bpp32ArgbData[] = { 0xFF, 0xFF, 0xFF, 0x80 }; + ARGB bpp32ArgbPixels[] = { 0x80FFFFFF }; + ARGB bpp32RgbPixels[] = { 0xFF808080 }; + + status = GdipCreateBitmapFromScan0 (1, 1, 4, PixelFormat32bppARGB, bpp32ArgbData, &bitmap); + assertEqualInt (status, Ok); + verifyBitmap (bitmap, memoryBmpRawFormat, PixelFormat32bppARGB, 1, 1, ImageFlagsHasAlpha, 0, TRUE); + verifyPixels (bitmap, bpp32ArgbPixels); + status = GdipCreateBitmapFromScan0 (1, 1, 4, PixelFormat32bppRGB, NULL, &bitmapBackground); + assertEqualInt (status, Ok); + status = GdipBitmapSetPixel (bitmapBackground, 0, 0, 0); + assertEqualInt (status, Ok); + GdipGetImageGraphicsContext (bitmapBackground, &graphicsBackground); + status = GdipDrawImage (graphicsBackground, (GpImage *)bitmap, 0, 0); + assertEqualInt (status, Ok); + GdipDeleteGraphics (graphicsBackground); + verifyPixels (bitmapBackground, bpp32RgbPixels); + GdipDisposeImage ((GpImage *) bitmapBackground); + GdipDisposeImage ((GpImage *) bitmap); +} + int main (int argc, char**argv) { @@ -2092,6 +2120,7 @@ main (int argc, char**argv) test_translateClip (); test_translateClipI (); test_region_mask (); + test_premultiplication (); SHUTDOWN; return 0;