Skip to content

Commit

Permalink
Merge pull request #373 from filipnavara/fix-premul
Browse files Browse the repository at this point in the history
Fix condition for bitmap premultiplication.
  • Loading branch information
migueldeicaza authored Jul 25, 2018
2 parents 0a78bf9 + b5c7e6e commit deee23d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 17 deletions.
21 changes: 7 additions & 14 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
17 changes: 14 additions & 3 deletions src/imageattributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -244,24 +245,34 @@ 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 {
r_new = (r * cm->m[0][0] + g * cm->m[1][0] + b * cm->m[2][0] + a * cm->m[3][0] + (255 * cm->m[4][0]));
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);
Expand Down
29 changes: 29 additions & 0 deletions tests/testgraphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -2092,6 +2120,7 @@ main (int argc, char**argv)
test_translateClip ();
test_translateClipI ();
test_region_mask ();
test_premultiplication ();

SHUTDOWN;
return 0;
Expand Down

0 comments on commit deee23d

Please sign in to comment.