Revert "Revert "Bug 493455 - [win32] remove alpha and alphaData from Image""

This reverts commit 7c722277240e346e521b5c97e802e261efcc8883.

Reason for revert: Considering for 4.24 M1

Change-Id: I1a6fc26f96a0ccd82c7aa5994fa134f798e40ef4
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/191861
Tested-by: Niraj Modi <niraj.modi@in.ibm.com>
Reviewed-by: Niraj Modi <niraj.modi@in.ibm.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
index 6311b10..ac2dfaf 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
@@ -1220,8 +1220,8 @@
 			data.hNullBitmap = 0;
 		}
 	}
-	if (srcImage.alpha != -1 || srcImage.alphaData != null) {
-		drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+	if (bm.bmPlanes * bm.bmBitsPixel == 32) {
+		drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
 	} else if (srcImage.transparentPixel != -1) {
 		drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
 	} else {
@@ -1233,35 +1233,15 @@
 	}
 }
 
-void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
-	/* Simple cases */
-	if (srcImage.alpha == 0) return;
-	if (srcImage.alpha == 255) {
-		drawBitmapColor(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
-		return;
-	}
-
+void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
 	boolean alphaBlendSupport = true;
 	boolean isPrinter = OS.GetDeviceCaps(handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER;
+	int sourceAlpha = -1;
 	if (isPrinter) {
 		int caps = OS.GetDeviceCaps(handle, OS.SHADEBLENDCAPS);
 		if (caps != 0) {
-			if (srcImage.alpha != -1) {
-				alphaBlendSupport = (caps & OS.SB_CONST_ALPHA) != 0;
-			} else {
-				alphaBlendSupport = (caps & OS.SB_PIXEL_ALPHA) != 0;
-			}
-		}
-	}
-	if (alphaBlendSupport) {
-		BLENDFUNCTION blend = new BLENDFUNCTION();
-		blend.BlendOp = OS.AC_SRC_OVER;
-		long srcHdc = OS.CreateCompatibleDC(handle);
-		long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
-		if (srcImage.alpha != -1) {
-			blend.SourceConstantAlpha = (byte)srcImage.alpha;
-			OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, blend);
-		} else {
+			long srcHdc = OS.CreateCompatibleDC(handle);
+			long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
 			long memDib = Image.createDIB(srcWidth, srcHeight, 32);
 			if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
 			long memHdc = OS.CreateCompatibleDC(handle);
@@ -1271,34 +1251,41 @@
 			OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
 			byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight];
 			OS.MoveMemory(srcData, dibBM.bmBits, srcData.length);
-			final int apinc = imgWidth - srcWidth;
-			int ap = srcY * imgWidth + srcX, sp = 0;
-			byte[] alphaData = srcImage.alphaData;
-			for (int y = 0; y < srcHeight; ++y) {
-				for (int x = 0; x < srcWidth; ++x) {
-					int alpha = alphaData[ap++] & 0xff;
-					int r = ((srcData[sp + 0] & 0xFF) * alpha) + 128;
-					r = (r + (r >> 8)) >> 8;
-					int g = ((srcData[sp + 1] & 0xFF) * alpha) + 128;
-					g = (g + (g >> 8)) >> 8;
-					int b = ((srcData[sp + 2] & 0xFF) * alpha) + 128;
-					b = (b + (b >> 8)) >> 8;
-					srcData[sp+0] = (byte)r;
-					srcData[sp+1] = (byte)g;
-					srcData[sp+2] = (byte)b;
-					srcData[sp+3] = (byte)alpha;
-					sp += 4;
+			int size = srcData.length;
+			sourceAlpha = srcData[3] & 0xFF;
+			for (int sp = 7; sp < size; sp += 4) {
+				int currentAlpha = srcData[sp] & 0xFF;
+				if (sourceAlpha != currentAlpha) {
+					sourceAlpha = -1;
+					break;
 				}
-				ap += apinc;
 			}
-			OS.MoveMemory(dibBM.bmBits, srcData, srcData.length);
-			blend.SourceConstantAlpha = (byte)0xff;
-			blend.AlphaFormat = OS.AC_SRC_ALPHA;
-			OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, blend);
 			OS.SelectObject(memHdc, oldMemBitmap);
 			OS.DeleteDC(memHdc);
 			OS.DeleteObject(memDib);
+			OS.SelectObject(srcHdc, oldSrcBitmap);
+			OS.DeleteDC(srcHdc);
+			if (sourceAlpha != -1) {
+				if (sourceAlpha == 0) return;
+				if (sourceAlpha == 255) {
+					drawBitmapColor(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
+					return;
+				}
+				alphaBlendSupport = (caps & OS.SB_CONST_ALPHA) != 0;
+			}
+			else {
+				alphaBlendSupport = (caps & OS.SB_PIXEL_ALPHA) != 0;
+			}
 		}
+	}
+	if (alphaBlendSupport) {
+		BLENDFUNCTION blend = new BLENDFUNCTION();
+		blend.BlendOp = OS.AC_SRC_OVER;
+		long srcHdc = OS.CreateCompatibleDC(handle);
+		long oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
+		blend.SourceConstantAlpha = (byte)sourceAlpha;
+		blend.AlphaFormat = OS.AC_SRC_ALPHA;
+		OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, 0, 0, srcWidth, srcHeight, blend);
 		OS.SelectObject(srcHdc, oldSrcBitmap);
 		OS.DeleteDC(srcHdc);
 		return;
@@ -1348,26 +1335,6 @@
 	byte[] srcData = new byte[sizeInBytes];
 	OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
 
-	/* Merge the alpha channel in place */
-	int alpha = srcImage.alpha;
-	final boolean hasAlphaChannel = (srcImage.alpha == -1);
-	if (hasAlphaChannel) {
-		final int apinc = imgWidth - srcWidth;
-		final int spinc = dibBM.bmWidthBytes - srcWidth * 4;
-		int ap = srcY * imgWidth + srcX, sp = 3;
-		byte[] alphaData = srcImage.alphaData;
-		for (int y = 0; y < srcHeight; ++y) {
-			for (int x = 0; x < srcWidth; ++x) {
-				srcData[sp] = alphaData[ap++];
-				sp += 4;
-			}
-			ap += apinc;
-			sp += spinc;
-		}
-	}
-
-	/* Scale the foreground pixels with alpha */
-	OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes);
 	/*
 	* When drawing to a printer, StretchBlt does not correctly stretch if
 	* the source and destination HDCs are the same.  The workaround is to
@@ -1403,10 +1370,10 @@
 	int dp = 0;
 	for (int y = 0; y < destHeight; ++y) {
 		for (int x = 0; x < destWidth; ++x) {
-			if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff;
-			destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255;
-			destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255;
-			destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255;
+			int alpha = srcData[dp + 3] & 0xFF;
+			destData[dp    ] += (srcData[dp    ] & 0xFF) - (destData[dp    ] & 0xFF) * alpha / 255;
+			destData[dp + 1] += (srcData[dp + 1] & 0xFF) - (destData[dp + 1] & 0xFF) * alpha / 255;
+			destData[dp + 2] += (srcData[dp + 2] & 0xFF) - (destData[dp + 2] & 0xFF) * alpha / 255;
 			dp += 4;
 		}
 		dp += dpinc;
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
index c0766cc..17cc993 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
@@ -112,16 +112,6 @@
 	GC memGC;
 
 	/**
-	 * the alpha data for the image
-	 */
-	byte[] alphaData;
-
-	/**
-	 * the global alpha value to be used for every pixel
-	 */
-	int alpha = -1;
-
-	/**
 	 * ImageFileNameProvider to provide file names at various Zoom levels
 	 */
 	private ImageFileNameProvider imageFileNameProvider;
@@ -283,11 +273,6 @@
 					device.internal_dispose_GC(hDC, null);
 
 					transparentPixel = srcImage.transparentPixel;
-					alpha = srcImage.alpha;
-					if (srcImage.alphaData != null) {
-						alphaData = new byte[srcImage.alphaData.length];
-						System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length);
-					}
 					break;
 				case SWT.ICON:
 					handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, rect.width, rect.height, 0);
@@ -977,9 +962,10 @@
 long [] createGdipImage() {
 	switch (type) {
 		case SWT.BITMAP: {
-			if (alpha != -1 || alphaData != null || transparentPixel != -1) {
-				BITMAP bm = new BITMAP();
-				OS.GetObject(handle, BITMAP.sizeof, bm);
+			BITMAP bm = new BITMAP();
+			OS.GetObject(handle, BITMAP.sizeof, bm);
+			int depth = bm.bmPlanes * bm.bmBitsPixel;
+			if (depth == 32 || transparentPixel != -1) {
 				int imgWidth = bm.bmWidth;
 				int imgHeight = bm.bmHeight;
 				long hDC = device.internal_new_GC(null);
@@ -993,8 +979,14 @@
 				OS.GetObject(memDib, BITMAP.sizeof, dibBM);
 				int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
 				OS.BitBlt(memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
+				long hHeap = OS.GetProcessHeap();
+				long pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, sizeInBytes);
+				if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
 				byte red = 0, green = 0, blue = 0;
-				if (transparentPixel != -1) {
+				if (depth == 32) {
+					OS.MoveMemory(pixels, bm.bmBits, sizeInBytes);
+				}
+				else {
 					if (bm.bmBitsPixel <= 8)  {
 						byte[] color = new byte[4];
 						OS.GetDIBColorTable(srcHdc, transparentPixel, 1, color);
@@ -1029,30 +1021,8 @@
 								break;
 						}
 					}
-				}
-				OS.SelectObject(srcHdc, oldSrcBitmap);
-				OS.SelectObject(memHdc, oldMemBitmap);
-				OS.DeleteObject(srcHdc);
-				OS.DeleteObject(memHdc);
-				byte[] srcData = new byte[sizeInBytes];
-				OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
-				OS.DeleteObject(memDib);
-				device.internal_dispose_GC(hDC, null);
-				if (alpha != -1) {
-					for (int y = 0, dp = 0; y < imgHeight; ++y) {
-						for (int x = 0; x < imgWidth; ++x) {
-							srcData[dp + 3] = (byte)alpha;
-							dp += 4;
-						}
-					}
-				} else if (alphaData != null) {
-					for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
-						for (int x = 0; x < imgWidth; ++x) {
-							srcData[dp + 3] = alphaData[ap++];
-							dp += 4;
-						}
-					}
-				} else if (transparentPixel != -1) {
+					byte[] srcData = new byte[sizeInBytes];
+					OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
 					for (int y = 0, dp = 0; y < imgHeight; ++y) {
 						for (int x = 0; x < imgWidth; ++x) {
 							if (srcData[dp] == blue && srcData[dp + 1] == green && srcData[dp + 2] == red) {
@@ -1063,12 +1033,15 @@
 							dp += 4;
 						}
 					}
+					OS.MoveMemory(pixels, srcData, sizeInBytes);
 				}
-				long hHeap = OS.GetProcessHeap();
-				long pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, srcData.length);
-				if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
-				OS.MoveMemory(pixels, srcData, sizeInBytes);
-				return new long []{Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, Gdip.PixelFormat32bppARGB, pixels), pixels};
+				OS.SelectObject(srcHdc, oldSrcBitmap);
+				OS.SelectObject(memHdc, oldMemBitmap);
+				OS.DeleteObject(srcHdc);
+				OS.DeleteObject(memHdc);
+				OS.DeleteObject(memDib);
+				int pixelFormat = depth == 32 ? Gdip.PixelFormat32bppPARGB : Gdip.PixelFormat32bppARGB;
+				return new long []{Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, pixelFormat, pixels), pixels};
 			}
 			return new long []{Gdip.Bitmap_new(handle, 0), 0};
 		}
@@ -1633,10 +1606,32 @@
 			/* Construct and return the ImageData */
 			ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
 			imageData.transparentPixel = this.transparentPixel;
-			imageData.alpha = alpha;
-			if (alpha == -1 && alphaData != null) {
-				imageData.alphaData = new byte[alphaData.length];
-				System.arraycopy(alphaData, 0, imageData.alphaData, 0, alphaData.length);
+			if (depth == 32) {
+				byte straightData[] = new byte[imageSize];
+				byte alphaData[] = new byte[width * height];
+				boolean validAlpha = true;
+				for (int ap = 0, dp = 0; validAlpha && ap < alphaData.length; ap++, dp += 4) {
+					int b = data[dp    ] & 0xFF;
+					int g = data[dp + 1] & 0xFF;
+					int r = data[dp + 2] & 0xFF;
+					int a = data[dp + 3] & 0xFF;
+					alphaData[ap] = (byte) a;
+					validAlpha = validAlpha && b <= a && g <= a && r <= a;
+					if (a != 0) {
+						straightData[dp    ] = (byte) (((b * 0xFF) + a / 2) / a);
+						straightData[dp + 1] = (byte) (((g * 0xFF) + a / 2) / a);
+						straightData[dp + 2] = (byte) (((r * 0xFF) + a / 2) / a);
+					}
+				}
+				if (validAlpha) {
+					imageData.data = straightData;
+					imageData.alphaData = alphaData;
+				}
+				else {
+					for (int dp = 3; dp < imageSize; dp += 4) {
+						data[dp] = (byte) 0xFF;
+					}
+				}
 			}
 			return imageData;
 		}
@@ -1729,6 +1724,9 @@
 		img.alphaData = i.alphaData;
 		i = img;
 	}
+
+	boolean hasAlpha = i.alpha != -1 || i.alphaData != null;
+
 	/*
 	 * Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F),
 	 * 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask
@@ -1745,51 +1743,56 @@
 		int newOrder = ImageData.MSB_FIRST;
 		PaletteData newPalette = null;
 
-		switch (i.depth) {
-			case 8:
-				/*
-				 * Bug 566545. Usually each color mask selects a different part of the pixel
-				 * value to encode the according color. In this common case it is rather trivial
-				 * to convert an 8-bit direct color image to the Windows supported 16-bit image.
-				 * However there is no enforcement for the color masks to be disjunct. For
-				 * example an 8-bit image where all color masks select the same 8-bit of pixel
-				 * value (mask = 0xFF and shift = 0 for all colors) results in a very efficient
-				 * 8-bit gray-scale image without the need of defining a color table.
-				 *
-				 * That's why we need to calculate the actual required depth if all colors are
-				 * stored non-overlapping which might require 24-bit instead of the usual
-				 * expected 16-bit.
-				 */
-				int minDepth = ImageData.getChannelWidth(redMask, palette.redShift)
-						+ ImageData.getChannelWidth(greenMask, palette.greenShift)
-						+ ImageData.getChannelWidth(blueMask, palette.blueShift);
-				if (minDepth <= 16) {
-					newDepth = 16;
+		if (hasAlpha) {
+			newDepth = 32;
+			newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+		}
+		else {
+			switch (i.depth) {
+				case 8:
+					/*
+					 * Bug 566545. Usually each color mask selects a different part of the pixel
+					 * value to encode the according color. In this common case it is rather trivial
+					 * to convert an 8-bit direct color image to the Windows supported 16-bit image.
+					 * However there is no enforcement for the color masks to be disjunct. For
+					 * example an 8-bit image where all color masks select the same 8-bit of pixel
+					 * value (mask = 0xFF and shift = 0 for all colors) results in a very efficient
+					 * 8-bit gray-scale image without the need of defining a color table.
+					 *
+					 * That's why we need to calculate the actual required depth if all colors are
+					 * stored non-overlapping which might require 24-bit instead of the usual
+					 * expected 16-bit.
+					 */
+					int minDepth = ImageData.getChannelWidth(redMask, palette.redShift)
+							+ ImageData.getChannelWidth(greenMask, palette.greenShift)
+							+ ImageData.getChannelWidth(blueMask, palette.blueShift);
+					if (minDepth <= 16) {
+						newDepth = 16;
+						newOrder = ImageData.LSB_FIRST;
+						newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+					} else {
+						newDepth = 24;
+						newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+					}
+					break;
+				case 16:
 					newOrder = ImageData.LSB_FIRST;
-					newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
-				} else {
+					if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) {
+						newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+					}
+					break;
+				case 24:
+					if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) {
+						newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+					}
+					break;
+				case 32:
 					newDepth = 24;
 					newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
-				}
-				break;
-			case 16:
-				newOrder = ImageData.LSB_FIRST;
-				if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) {
-					newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
-				}
-				break;
-			case 24:
-				if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) {
-					newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
-				}
-				break;
-			case 32:
-				if (!(redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) {
-					newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
-				}
-				break;
-			default:
-				SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+					break;
+				default:
+					SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+			}
 		}
 		if (newPalette != null) {
 			ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
@@ -1808,6 +1811,73 @@
 			i = img;
 		}
 	}
+	else if (hasAlpha) {
+		int newDepth = 32;
+		PaletteData newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+		int newOrder = ImageData.MSB_FIRST;
+		RGB[] rgbs = i.palette.getRGBs();
+		int length = rgbs.length;
+		byte[] srcReds = new byte[length];
+		byte[] srcGreens = new byte[length];
+		byte[] srcBlues = new byte[length];
+		for (int j = 0; j < rgbs.length; j++) {
+			RGB rgb = rgbs[j];
+			if (rgb == null) continue;
+			srcReds[j] = (byte)rgb.red;
+			srcGreens[j] = (byte)rgb.green;
+			srcBlues[j] = (byte)rgb.blue;
+		}
+		ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
+		ImageData.blit(ImageData.BLIT_SRC,
+				i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, srcReds, srcGreens, srcBlues,
+				ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+				img.data, img.depth, img.bytesPerLine, newOrder, 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
+				false, false);
+
+		if (i.transparentPixel != -1) {
+			img.transparentPixel = newPalette.getPixel(i.palette.getRGB(i.transparentPixel));
+		}
+		img.maskPad = i.maskPad;
+		img.maskData = i.maskData;
+		img.alpha = i.alpha;
+		img.alphaData = i.alphaData;
+		i = img;
+	}
+	if (i.alpha != -1) {
+		int alpha = i.alpha & 0xFF;
+		byte[] data = i.data;
+		for (int dp = 0; dp < i.data.length; dp += 4) {
+			/* pre-multiplied alpha */
+			int r = ((data[dp    ] & 0xFF) * alpha) + 128;
+			r = (r + (r >> 8)) >> 8;
+			int g = ((data[dp + 1] & 0xFF) * alpha) + 128;
+			g = (g + (g >> 8)) >> 8;
+			int b = ((data[dp + 2] & 0xFF) * alpha) + 128;
+			b = (b + (b >> 8)) >> 8;
+			data[dp    ] = (byte) b;
+			data[dp + 1] = (byte) g;
+			data[dp + 2] = (byte) r;
+			data[dp + 3] = (byte) alpha;
+		}
+	}
+	else if (i.alphaData != null) {
+		byte[] data = i.data;
+		for (int ap = 0, dp = 0; dp < i.data.length; ap++, dp += 4) {
+			/* pre-multiplied alpha */
+			int a = i.alphaData[ap] & 0xFF;
+			int r = ((data[dp    ] & 0xFF) * a) + 128;
+			r = (r + (r >> 8)) >> 8;
+			int g = ((data[dp + 1] & 0xFF) * a) + 128;
+			g = (g + (g >> 8)) >> 8;
+			int b = ((data[dp + 2] & 0xFF) * a) + 128;
+			b = (b + (b >> 8)) >> 8;
+			data[dp    ] = (byte) r;
+			data[dp + 1] = (byte) g;
+			data[dp + 2] = (byte) b;
+			data[dp + 3] = (byte) a;
+		}
+	}
+
 	/* Construct bitmap info header by hand */
 	RGB[] rgbs = i.palette.getRGBs();
 	BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
@@ -1894,14 +1964,6 @@
 			image.handle = hDib;
 			image.type = SWT.BITMAP;
 			image.transparentPixel = i.transparentPixel;
-			if (image.transparentPixel == -1) {
-				image.alpha = i.alpha;
-				if (i.alpha == -1 && i.alphaData != null) {
-					int length = i.alphaData.length;
-					image.alphaData = new byte[length];
-					System.arraycopy(i.alphaData, 0, image.alphaData, 0, length);
-				}
-			}
 		}
 	}
 	return result;