Alex Shulgin wrote:
Hi,

I believe that alpha blending is broken in libgdiplus.

I've located the problem. It is due to the inconsistent handling of PixelFormat32bppPArgb (premultiplied alpha) in libgdiplus.

In the attached patch I've added the check on PArgb to DrawImageRect in analogy with texturebrush.c and fixed pngcodec.c to set pixel format to PArgb if premultiplication was done.

This fixes my demo program and there's no visible regressions in a fairly complex application which originally revealed the problem.

If the feeling is such that this is appropriate patch, I'd add the same handling for places like this (there's few).

--
Regards,
Alex

Index: src/image.c
===================================================================
--- src/image.c	(revision 130138)
+++ src/image.c	(working copy)
@@ -380,6 +380,8 @@
 	BOOL need_scaling = FALSE;
 	double scaled_width, scaled_height;
 	cairo_matrix_t orig_matrix;
+	BYTE *premul = NULL;
+	cairo_surface_t *surface = NULL;
 
 	if (!graphics || !image)
 		return InvalidParameter;
@@ -430,13 +432,24 @@
 	/* Create a surface for this bitmap if one doesn't exist */
 	gdip_bitmap_ensure_surface (image);
 
+	surface = image->surface;
+
+	if (gdip_bitmap_format_needs_premultiplication (image)) {
+                premul = gdip_bitmap_get_premultiplied_scan0 (image);
+                if (premul) {
+                        BitmapData *data = image->active_bitmap;
+                        surface = cairo_image_surface_create_for_data (premul, CAIRO_FORMAT_ARGB32, 
+                                data->width, data->height, data->stride);
+                }
+        }
+
 	if (width != image->active_bitmap->width || height != image->active_bitmap->height) {
 		scaled_width = (double) width / image->active_bitmap->width;
 		scaled_height = (double) height / image->active_bitmap->height;
 		need_scaling = TRUE;
 	}
 
-	pattern = cairo_pattern_create_for_surface (image->surface);
+	pattern = cairo_pattern_create_for_surface (surface);
 
 	cairo_pattern_set_filter (pattern, gdip_get_cairo_filter (graphics->interpolation));
 
@@ -458,6 +471,12 @@
 	cairo_pattern_destroy (org_pattern);
 	cairo_pattern_destroy (pattern);
 
+	if (premul)
+	{
+		cairo_surface_destroy (surface);
+		GdipFree (premul);
+	}
+
 	return Ok;
 }
 
Index: src/pngcodec.c
===================================================================
--- src/pngcodec.c	(revision 130138)
+++ src/pngcodec.c	(working copy)
@@ -527,7 +527,6 @@
 
 		result->cairo_format = CAIRO_FORMAT_ARGB32;
 		result->active_bitmap->stride = stride;
-		result->active_bitmap->pixel_format = PixelFormat32bppARGB;
 		result->active_bitmap->width = width;
 		result->active_bitmap->height = height;
 		result->active_bitmap->scan0 = rawdata;
@@ -543,7 +542,7 @@
 			result->active_bitmap->pixel_format = PixelFormat24bppRGB;
 			result->active_bitmap->image_flags = ImageFlagsColorSpaceRGB;
 		} else if (channels == 4) {
-			result->active_bitmap->pixel_format = PixelFormat32bppARGB;
+			result->active_bitmap->pixel_format = PixelFormat32bppPARGB;
 			result->active_bitmap->image_flags = ImageFlagsColorSpaceRGB;
 		} else if ((channels == 1) && (color_type == PNG_COLOR_TYPE_GRAY)) {
 			// doesn't apply to 2bpp images

_______________________________________________
Mono-winforms-list maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-winforms-list

Reply via email to