package org.eclipse.swt.graphics; | |
/* | |
* (c) Copyright IBM Corp. 2000, 2001. | |
* All Rights Reserved | |
*/ | |
import org.eclipse.swt.internal.win32.*; | |
import org.eclipse.swt.*; | |
import java.io.*; | |
/** | |
* Instances of this class are graphics which have been prepared | |
* for display on a specific device. That is, they are ready | |
* to paint using methods such as <code>GC.drawImage()</code> | |
* and display on widgets with, for example, <code>Button.setImage()</code>. | |
* <p> | |
* If loaded from a file format that supports it, an | |
* <code>Image</code> may have transparency, meaning that certain | |
* pixels are specified as being transparent when drawn. Examples | |
* of file formats that support transparency are GIF and PNG. | |
* </p><p> | |
* There are two primary ways to use <code>Images</code>. | |
* The first is to load a graphic file from disk and create an | |
* <code>Image</code> from it. This is done using an <code>Image</code> | |
* constructor, for example: | |
* <pre> | |
* Image i = new Image(device, "C:\\graphic.bmp"); | |
* </pre> | |
* A graphic file may contain a color table specifying which | |
* colors the image was intended to possess. In the above example, | |
* these colors will be mapped to the closest available color in | |
* SWT. It is possible to get more control over the mapping of | |
* colors as the image is being created, using code of the form: | |
* <pre> | |
* ImageData data = new ImageData("C:\\graphic.bmp"); | |
* RGB[] rgbs = data.getRGBs(); | |
* // At this point, rgbs contains specifications of all | |
* // the colors contained within this image. You may | |
* // allocate as many of these colors as you wish by | |
* // using the Color constructor Color(RGB), then | |
* // create the image: | |
* Image i = new Image(device, data); | |
* </pre> | |
* <p> | |
* Applications which require even greater control over the image | |
* loading process should use the support provided in class | |
* <code>ImageLoader</code>. | |
* </p><p> | |
* Application code must explicitely invoke the <code>Image.dispose()</code> | |
* method to release the operating system resources managed by each instance | |
* when those instances are no longer required. | |
* </p> | |
* | |
* @see Color | |
* @see ImageData | |
* @see ImageLoader | |
*/ | |
public final class Image implements Drawable { | |
/** | |
* specifies whether the receiver is a bitmap or an icon | |
* (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>) | |
*/ | |
public int type; | |
/** | |
* the OS resource of the image | |
* (Warning: This field is platform dependent) | |
*/ | |
public int handle; | |
/** | |
* the device where this image was created | |
*/ | |
Device device; | |
/** | |
* specifies the transparent pixel | |
* (Warning: This field is platform dependent) | |
*/ | |
int transparentPixel = -1; | |
/** | |
* the GC which is drawing on the image | |
* (Warning: This field is platform dependent) | |
*/ | |
GC memGC; | |
/** | |
* the alpha data for the image | |
* (Warning: This field is platform dependent) | |
*/ | |
byte[] alphaData; | |
/** | |
* the global alpha value to be used for every pixel | |
* (Warning: This field is platform dependent) | |
*/ | |
int alpha = -1; | |
/** | |
* specifies the default scanline padding | |
* (Warning: This field is platform dependent) | |
*/ | |
static final int DEFAULT_SCANLINE_PAD = 4; | |
/** | |
* Prevents uninitialized instances from being created outside the package. | |
*/ | |
Image () { | |
} | |
/** | |
* Constructs an empty instance of this class with the | |
* specified width and height. The result may be drawn upon | |
* by creating a GC and using any of its drawing operations, | |
* as shown in the following example: | |
* <pre> | |
* Image i = new Image(device, width, height); | |
* GC gc = new GC(i); | |
* gc.drawRectangle(0, 0, 50, 50); | |
* gc.dispose(); | |
* </pre> | |
* | |
* @param device the device on which to create the image | |
* @param width the width of the new image | |
* @param height the height of the new image | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative</li> | |
* </ul> | |
*/ | |
public Image(Device device, int width, int height) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
init(device, width, height); | |
if (device.tracking) device.new_Object(this); | |
} | |
/** | |
* Constructs a new instance of this class based on the | |
* provided image, with an appearance that varies depending | |
* on the value of the flag. The possible flag values are: | |
* <dl> | |
* <dt><b>IMAGE_COPY</b></dt> | |
* <dd>the result is an identical copy of srcImage</dd> | |
* <dt><b>IMAGE_DISABLE</b></dt> | |
* <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd> | |
* <dt><b>IMAGE_GRAY</b></dt> | |
* <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd> | |
* </dl> | |
* | |
* @param device the device on which to create the image | |
* @param srcImage the image to use as the source | |
* @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code> | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if srcImage is null</li> | |
* <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li> | |
* <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or | |
* is otherwise in an invalid state</li> | |
* </ul> | |
* @exception SWTError <ul> | |
* <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li> | |
* </ul> | |
*/ | |
public Image(Device device, Image srcImage, int flag) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
this.device = device; | |
if (srcImage == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
switch (flag) { | |
case SWT.IMAGE_COPY: { | |
Rectangle r = srcImage.getBounds(); | |
this.type = srcImage.type; | |
switch (type) { | |
case SWT.BITMAP: | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Copy the bitmap */ | |
int hdcSource = OS.CreateCompatibleDC(hDC); | |
int hdcDest = OS.CreateCompatibleDC(hDC); | |
int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle); | |
handle = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
int hOldDest = OS.SelectObject(hdcDest, handle); | |
OS.BitBlt(hdcDest, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); | |
OS.SelectObject(hdcSource, hOldSrc); | |
OS.SelectObject(hdcDest, hOldDest); | |
OS.DeleteDC(hdcSource); | |
OS.DeleteDC(hdcDest); | |
/* Release the HDC for the device */ | |
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: | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, r.width, r.height, 0); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
break; | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); | |
} | |
if (device.tracking) device.new_Object(this); | |
return; | |
} | |
case SWT.IMAGE_DISABLE: { | |
Rectangle r = srcImage.getBounds(); | |
this.type = srcImage.type; | |
byte[] rgbBwBitmapInfo = { | |
40,0,0,0, /* biSize */ | |
(byte)(r.width & 0xFF), /* biWidth */ | |
(byte)((r.width & 0xFF00) >> 8), | |
(byte)((r.width & 0xFF0000) >> 16), | |
(byte)((r.width & 0xFF000000) >> 24), | |
(byte)(r.height & 0xFF), /* biHeight */ | |
(byte)((r.height & 0xFF00) >> 8), | |
(byte)((r.height & 0xFF0000) >> 16), | |
(byte)((r.height & 0xFF000000) >> 24), | |
1,0, /* biPlanes */ | |
1,0, /* biBitCount */ | |
0,0,0,0, /* biCompression */ | |
0,0,0,0, /* biSizeImage */ | |
0,0,0,0, /* biXPelsPerMeter */ | |
0,0,0,0, /* biYPelsPerMeter */ | |
0,0,0,0, /* biClrUsed */ | |
0,0,0,0, /* biClrImportant */ | |
0,0,0,0, /* First color: black */ | |
(byte)0xFF,(byte)0xFF,(byte)0xFF,0 /* Second color: white */ | |
}; | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Source DC */ | |
int hdcSource = OS.CreateCompatibleDC(hDC); | |
if (hdcSource == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Monochrome (Intermediate) DC */ | |
int bwDC = OS.CreateCompatibleDC(hdcSource); | |
if (bwDC == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Destination DC */ | |
int hdcBmp = OS.CreateCompatibleDC(hDC); | |
if (hdcBmp == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Monochrome (Intermediate) DIB section */ | |
int[] pbitsBW = new int[1]; | |
int hbmBW = OS.CreateDIBSection(bwDC, rgbBwBitmapInfo, OS.DIB_RGB_COLORS, pbitsBW, 0, 0); | |
if (hbmBW == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
switch (type) { | |
case SWT.BITMAP: | |
/* Attach the bitmap to the source DC */ | |
int hOldSrc = OS.SelectObject(hdcSource, srcImage.handle); | |
/* Create the destination bitmap */ | |
handle = OS.CreateCompatibleBitmap(hDC, r.width, r.height); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Attach the DIB section and the new bitmap to the DCs */ | |
int hOldBw = OS.SelectObject(bwDC, hbmBW); | |
int hOldBmp = OS.SelectObject(hdcBmp, handle); | |
/* BitBlt the bitmap into the monochrome DIB section */ | |
OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); | |
/* Paint the destination rectangle in gray */ | |
RECT rect = new RECT(); | |
rect.left = 0; | |
rect.top = 0; | |
rect.right = r.width; | |
rect.bottom = r.height; | |
OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE)); | |
/* | |
* BitBlt the black bits in the monochrome bitmap into | |
* COLOR_3DHILIGHT bits in the destination DC. | |
* The magic ROP comes from Charles Petzold's book | |
*/ | |
int hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DHILIGHT)); | |
int oldBrush = OS.SelectObject(hdcBmp, hb); | |
OS.BitBlt(hdcBmp, 1, 1, r.width, r.height, bwDC, 0, 0, 0xB8074A); | |
/* | |
* BitBlt the black bits in the monochrome bitmap into | |
* COLOR_3DSHADOW bits in the destination DC. | |
*/ | |
hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW)); | |
OS.DeleteObject(OS.SelectObject(hdcBmp, hb)); | |
OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); | |
OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush)); | |
/* Free resources */ | |
OS.SelectObject(hdcSource, hOldSrc); | |
OS.SelectObject(hdcBmp, hOldBmp); | |
OS.SelectObject(bwDC, hOldBw); | |
OS.DeleteDC(hdcSource); | |
OS.DeleteDC(bwDC); | |
OS.DeleteDC(hdcBmp); | |
OS.DeleteObject(hbmBW); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
break; | |
case SWT.ICON: | |
/* Get icon information */ | |
ICONINFO iconInfo = new ICONINFO(); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
if (!OS.GetIconInfo(srcImage.handle, iconInfo)) | |
SWT.error(SWT.ERROR_INVALID_IMAGE); | |
int hdcMask = OS.CreateCompatibleDC(hDC); | |
/* Create the destination bitmaps */ | |
if (iconInfo.hbmColor == 0) | |
hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmMask); | |
else | |
hOldSrc = OS.SelectObject(hdcSource, iconInfo.hbmColor); | |
int newHbmp = OS.CreateCompatibleBitmap(hdcSource, r.width, r.height); | |
if (newHbmp == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
int newHmask = OS.CreateBitmap(r.width, r.height, 1, 1, null); | |
if (newHmask == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* BitBlt the source mask into the destination mask */ | |
int hOldMask = OS.SelectObject(hdcMask, newHmask); | |
if (iconInfo.hbmColor != 0) | |
OS.SelectObject(hdcSource, iconInfo.hbmMask); | |
OS.SelectObject(hdcSource, iconInfo.hbmMask); | |
OS.BitBlt(hdcMask, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); | |
/* Attach the monochrome DIB section and the destination bitmap to the DCs */ | |
hOldBw = OS.SelectObject(bwDC, hbmBW); | |
/* BitBlt the bitmap into the monochrome DIB section */ | |
if (iconInfo.hbmColor == 0) { | |
OS.SelectObject(hdcSource, iconInfo.hbmMask); | |
OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, r.height, OS.SRCCOPY); | |
} else { | |
OS.SelectObject(hdcSource, iconInfo.hbmColor); | |
OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcSource, 0, 0, OS.SRCCOPY); | |
} | |
/* Paint the destination rectangle in grey */ | |
rect = new RECT(); | |
rect.left = 0; | |
rect.top = 0; | |
rect.right = r.width; | |
rect.bottom = r.height; | |
hOldBmp = OS.SelectObject(hdcBmp, newHbmp); | |
OS.FillRect(hdcBmp, rect, OS.GetSysColorBrush(OS.COLOR_3DFACE)); | |
/* | |
* BitBlt the black bits in the monochrome bitmap into | |
* COLOR_3DHILIGHT bits in the destination DC. | |
* The magic ROP comes from Charles Petzold's book | |
*/ | |
hb = OS.CreateSolidBrush(OS.GetSysColor(OS.COLOR_3DSHADOW)); | |
oldBrush = OS.SelectObject(hdcBmp, hb); | |
OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); | |
/* Invert mask into hdcBw */ | |
OS.BitBlt(bwDC, 0, 0, r.width, r.height, hdcMask, 0, 0, OS.NOTSRCCOPY); | |
/* Select black brush into destination */ | |
hb = OS.CreateSolidBrush(0); | |
OS.DeleteObject(OS.SelectObject(hdcBmp, hb)); | |
/* | |
* Copy black bits from monochrome bitmap into black bits in the | |
* destination DC. | |
*/ | |
OS.BitBlt(hdcBmp, 0, 0, r.width, r.height, bwDC, 0, 0, 0xB8074A); | |
OS.DeleteObject(OS.SelectObject(hdcBmp, oldBrush)); | |
/* Free resources */ | |
OS.SelectObject(hdcSource, hOldSrc); | |
OS.DeleteDC(hdcSource); | |
OS.SelectObject(bwDC, hOldBw); | |
OS.DeleteDC(bwDC); | |
OS.SelectObject(hdcBmp, hOldBmp); | |
OS.DeleteDC(hdcBmp); | |
OS.SelectObject(hdcMask, hOldMask); | |
OS.DeleteDC(hdcMask); | |
OS.DeleteObject(hbmBW); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
/* Create the new iconinfo */ | |
ICONINFO newIconInfo = new ICONINFO(); | |
newIconInfo.fIcon = iconInfo.fIcon; | |
newIconInfo.hbmMask = newHmask; | |
newIconInfo.hbmColor = newHbmp; | |
/* Create the new icon */ | |
handle = OS.CreateIconIndirect(newIconInfo); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Free bitmaps */ | |
OS.DeleteObject(newHbmp); | |
OS.DeleteObject(newHmask); | |
if (iconInfo.hbmColor != 0) | |
OS.DeleteObject(iconInfo.hbmColor); | |
OS.DeleteObject(iconInfo.hbmMask); | |
break; | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); | |
} | |
if (device.tracking) device.new_Object(this); | |
return; | |
} | |
case SWT.IMAGE_GRAY: { | |
Rectangle r = srcImage.getBounds(); | |
ImageData data = srcImage.getImageData(); | |
PaletteData palette = data.palette; | |
ImageData newData = data; | |
if (!palette.isDirect) { | |
/* Convert the palette entries to gray. */ | |
RGB [] rgbs = palette.getRGBs(); | |
for (int i=0; i<rgbs.length; i++) { | |
if (data.transparentPixel != i) { | |
RGB color = rgbs [i]; | |
int red = color.red; | |
int green = color.green; | |
int blue = color.blue; | |
int intensity = (red+red+green+green+green+green+green+blue) >> 3; | |
color.red = color.green = color.blue = intensity; | |
} | |
} | |
newData.palette = new PaletteData(rgbs); | |
} else { | |
/* Create a 8 bit depth image data with a gray palette. */ | |
RGB[] rgbs = new RGB[256]; | |
for (int i=0; i<rgbs.length; i++) { | |
rgbs[i] = new RGB(i, i, i); | |
} | |
newData = new ImageData(r.width, r.height, 8, new PaletteData(rgbs)); | |
newData.maskData = data.maskData; | |
newData.maskPad = data.maskPad; | |
/* Convert the pixels. */ | |
int[] scanline = new int[r.width]; | |
int redMask = palette.redMask; | |
int greenMask = palette.greenMask; | |
int blueMask = palette.blueMask; | |
int redShift = palette.redShift; | |
int greenShift = palette.greenShift; | |
int blueShift = palette.blueShift; | |
for (int y=0; y<r.height; y++) { | |
int offset = y * newData.bytesPerLine; | |
data.getPixels(0, y, r.width, scanline, 0); | |
for (int x=0; x<r.width; x++) { | |
int pixel = scanline[x]; | |
int red = pixel & redMask; | |
red = (redShift < 0) ? red >>> -redShift : red << redShift; | |
int green = pixel & greenMask; | |
green = (greenShift < 0) ? green >>> -greenShift : green << greenShift; | |
int blue = pixel & blueMask; | |
blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift; | |
newData.data[offset++] = | |
(byte)((red+red+green+green+green+green+green+blue) >> 3); | |
} | |
} | |
} | |
init (device, newData); | |
if (device.tracking) device.new_Object(this); | |
return; | |
} | |
default: | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
} | |
/** | |
* Constructs an empty instance of this class with the | |
* width and height of the specified rectangle. The result | |
* may be drawn upon by creating a GC and using any of its | |
* drawing operations, as shown in the following example: | |
* <pre> | |
* Image i = new Image(device, boundsRectangle); | |
* GC gc = new GC(i); | |
* gc.drawRectangle(0, 0, 50, 50); | |
* gc.dispose(); | |
* </pre> | |
* | |
* @param device the device on which to create the image | |
* @param bounds a rectangle specifying the image's width and height (must not be null) | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li> | |
* <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li> | |
* </ul> | |
*/ | |
public Image(Device device, Rectangle bounds) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
init(device, bounds.width, bounds.height); | |
if (device.tracking) device.new_Object(this); | |
} | |
/** | |
* Constructs an instance of this class from the given | |
* <code>ImageData</code>. | |
* | |
* @param device the device on which to create the image | |
* @param data the image data to create the image from (must not be null) | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the image data is null</li> | |
* </ul> | |
*/ | |
public Image(Device device, ImageData data) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
init(device, data); | |
if (device.tracking) device.new_Object(this); | |
} | |
/** | |
* Constructs an instance of this class, whose type is | |
* <code>SWT.ICON</code>, from the two given <code>ImageData</code> | |
* objects. The two images must be the same size, and the mask image | |
* must have a color depth of 1. Pixel transparency in either image | |
* will be ignored. If either image is an icon to begin with, an | |
* exception is thrown. | |
* <p> | |
* The mask image should contain white wherever the icon is to be visible, | |
* and black wherever the icon is to be transparent. In addition, | |
* the source image should contain black wherever the icon is to be | |
* transparent. | |
* </p> | |
* | |
* @param device the device on which to create the icon | |
* @param source the color data for the icon | |
* @param mask the mask data for the icon | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li> | |
* <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes or | |
* if the mask is not monochrome, or if either the source or mask | |
* is already an icon</li> | |
* </ul> | |
*/ | |
public Image(Device device, ImageData source, ImageData mask) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (mask == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (source.width != mask.width || source.height != mask.height) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
if (mask.depth != 1) { | |
/* | |
* Feature in Windows. 1-bit DIB sections are buggy on Win98, so we | |
* create 4-bit DIBs when given a 1-bit ImageData. In order to allow | |
* users to draw on the masks, we must also support 4-bit masks in | |
* icon creation by converting them into 1-bit masks. | |
*/ | |
if (mask.depth != 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
PaletteData palette = new PaletteData(new RGB[] {new RGB(0, 0, 0), new RGB(255,255,255)}); | |
ImageData tempMask = new ImageData(mask.width, mask.height, 1, palette); | |
/* Find index of black in mask palette */ | |
RGB[] rgbs = mask.getRGBs(); | |
int blackIndex = 0; | |
while (blackIndex < rgbs.length) { | |
if (rgbs[blackIndex].equals(palette.colors[0])) break; | |
blackIndex++; | |
} | |
if (blackIndex == rgbs.length) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
int[] pixels = new int[mask.width]; | |
for (int y = 0; y < mask.height; y++) { | |
mask.getPixels(0, y, mask.width, pixels, 0); | |
for (int i = 0; i < pixels.length; i++) { | |
if (pixels[i] == blackIndex) { | |
pixels[i] = 0; | |
} else { | |
pixels[i] = 1; | |
} | |
} | |
tempMask.setPixels(0, y, mask.width, pixels, 0); | |
} | |
mask = tempMask; | |
} | |
/* Create a temporary image and locate the black pixel */ | |
ImageData image; | |
int blackIndex = 0; | |
if (source.palette.isDirect) { | |
image = new ImageData(source.width, source.height, source.depth, source.palette); | |
} else { | |
RGB black = new RGB(0, 0, 0); | |
RGB[] rgbs = source.getRGBs(); | |
if (source.transparentPixel != -1) { | |
/* | |
* The source had transparency, so we can use the transparent pixel | |
* for black. | |
*/ | |
RGB[] newRGBs = new RGB[rgbs.length]; | |
System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length); | |
if (source.transparentPixel >= newRGBs.length) { | |
/* Grow the palette with black */ | |
rgbs = new RGB[source.transparentPixel + 1]; | |
System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length); | |
for (int i = newRGBs.length; i <= source.transparentPixel; i++) { | |
rgbs[i] = new RGB(0, 0, 0); | |
} | |
} else { | |
newRGBs[source.transparentPixel] = black; | |
rgbs = newRGBs; | |
} | |
blackIndex = source.transparentPixel; | |
image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs)); | |
} else { | |
while (blackIndex < rgbs.length) { | |
if (rgbs[blackIndex].equals(black)) break; | |
blackIndex++; | |
} | |
if (blackIndex == rgbs.length) { | |
/* | |
* We didn't find black in the palette, and there is no transparent | |
* pixel we can use. | |
*/ | |
if ((1 << source.depth) > rgbs.length) { | |
/* We can grow the palette and add black */ | |
RGB[] newRGBs = new RGB[rgbs.length + 1]; | |
System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length); | |
newRGBs[rgbs.length] = black; | |
rgbs = newRGBs; | |
} else { | |
/* No room to grow the palette */ | |
blackIndex = -1; | |
} | |
} | |
image = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs)); | |
} | |
} | |
if (blackIndex == -1) { | |
/* There was no black in the palette, so just copy the data over */ | |
System.arraycopy(source.data, 0, image.data, 0, image.data.length); | |
} else { | |
/* Modify the source image to contain black wherever the mask is 0 */ | |
int[] imagePixels = new int[image.width]; | |
int[] maskPixels = new int[mask.width]; | |
for (int y = 0; y < image.height; y++) { | |
source.getPixels(0, y, image.width, imagePixels, 0); | |
mask.getPixels(0, y, mask.width, maskPixels, 0); | |
for (int i = 0; i < imagePixels.length; i++) { | |
if (maskPixels[i] == 0) imagePixels[i] = blackIndex; | |
} | |
image.setPixels(0, y, source.width, imagePixels, 0); | |
} | |
} | |
/* | |
* Make sure the mask is padded properly. Windows requires icon masks | |
* to have a scanline pad of 2. | |
*/ | |
int bytesPerLine = (((mask.width + 7) / 8) + 1) / 2 * 2; | |
byte[] newMaskData = new byte[bytesPerLine * mask.height]; | |
ImageData newMask = new ImageData(mask.width, mask.height, 1, mask.palette, 2, newMaskData); | |
int[] maskPixels = new int[mask.width]; | |
for (int y = 0; y < mask.height; y++) { | |
mask.getPixels(0, y, mask.width, maskPixels, 0); | |
newMask.setPixels(0, y, newMask.width, maskPixels, 0); | |
} | |
/* Set the fields and create the icon */ | |
image.maskPad = newMask.scanlinePad; | |
image.maskData = newMask.data; | |
init(device, image); | |
if (device.tracking) device.new_Object(this); | |
} | |
/** | |
* Constructs an instance of this class by loading its representation | |
* from the specified input stream. Throws an error if an error | |
* occurs while loading the image, or if the result is an image | |
* of an unsupported type. | |
* <p> | |
* This constructor is provided for convenience when loading a single | |
* image only. If the stream contains multiple images, only the first | |
* one will be loaded. To load multiple images, use | |
* <code>ImageLoader.load()</code>. | |
* </p><p> | |
* This constructor may be used to load a resource as follows: | |
* </p> | |
* <pre> | |
* new Image(device, clazz.getResourceAsStream("file.gif")); | |
* </pre> | |
* | |
* @param device the device on which to create the image | |
* @param stream the input stream to load the image from | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li> | |
* <li>ERROR_IO - if an IO error occurs while reading data</li> | |
* </ul> | |
*/ | |
public Image (Device device, InputStream stream) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
init(device, new ImageData(stream)); | |
if (device.tracking) device.new_Object(this); | |
} | |
/** | |
* Constructs an instance of this class by loading its representation | |
* from the file with the specified name. Throws an error if an error | |
* occurs while loading the image, or if the result is an image | |
* of an unsupported type. | |
* <p> | |
* This constructor is provided for convenience when loading | |
* a single image only. If the specified file contains | |
* multiple images, only the first one will be used. | |
* | |
* @param device the device on which to create the image | |
* @param filename the name of the file to load the image from | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li> | |
* <li>ERROR_IO - if an IO error occurs while reading data</li> | |
* </ul> | |
*/ | |
public Image (Device device, String filename) { | |
if (device == null) device = Device.getDevice(); | |
if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
init(device, new ImageData(filename)); | |
if (device.tracking) device.new_Object(this); | |
} | |
/* Create a DIB from a DDB without using GetDIBits */ | |
int createDIBFromDDB(int hDC, int hBitmap, int width, int height) { | |
/* Determine the DDB depth */ | |
byte[] bmi; | |
int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL); | |
int planes = OS.GetDeviceCaps (hDC, OS.PLANES); | |
int depth = bits * planes; | |
/* Determine the DIB palette */ | |
boolean isDirect = depth > 8; | |
RGB[] rgbs = null; | |
if (!isDirect) { | |
int numColors = 1 << depth; | |
byte[] logPalette = new byte[4 * numColors]; | |
OS.GetPaletteEntries(device.hPalette, 0, numColors, logPalette); | |
rgbs = new RGB[numColors]; | |
for (int i = 0; i < numColors; i++) { | |
rgbs[i] = new RGB(logPalette[i] & 0xFF, logPalette[i + 1] & 0xFF, logPalette[i + 2] & 0xFF); | |
} | |
} | |
int biClrUsed = 0; | |
boolean useBitfields = OS.IsWinCE && (depth == 16 || depth == 32); | |
if (isDirect) bmi = new byte[40 + (useBitfields ? 12 : 0)]; | |
else bmi = new byte[40 + rgbs.length * 4]; | |
/* DWORD biSize = 40 */ | |
bmi[0] = 40; bmi[1] = 0; bmi[2] = 0; bmi[3] = 0; | |
/* LONG biWidth = width */ | |
bmi[4] = (byte)(width & 0xFF); | |
bmi[5] = (byte)((width >> 8) & 0xFF); | |
bmi[6] = (byte)((width >> 16) & 0xFF); | |
bmi[7] = (byte)((width >> 24) & 0xFF); | |
/* LONG biHeight = height */ | |
int height2 = -height; | |
bmi[8] = (byte)(height2 & 0xFF); | |
bmi[9] = (byte)((height2 >> 8) & 0xFF); | |
bmi[10] = (byte)((height2 >> 16) & 0xFF); | |
bmi[11] = (byte)((height2 >> 24) & 0xFF); | |
/* WORD biPlanes = 1 */ | |
bmi[12] = 1; | |
bmi[13] = 0; | |
/* WORD biBitCount = depth */ | |
bmi[14] = (byte)(depth & 0xFF); | |
bmi[15] = (byte)((depth >> 8) & 0xFF); | |
if (useBitfields) { | |
/* DWORD biCompression = BI_BITFIELDS = 3 */ | |
bmi[16] = 3; bmi[17] = bmi[18] = bmi[19] = 0; | |
} else { | |
/* DWORD biCompression = BI_RGB = 0 */ | |
bmi[16] = bmi[17] = bmi[18] = bmi[19] = 0; | |
} | |
/* DWORD biSizeImage = 0 (default) */ | |
bmi[20] = bmi[21] = bmi[22] = bmi[23] = 0; | |
/* LONG biXPelsPerMeter = 0 */ | |
bmi[24] = bmi[25] = bmi[26] = bmi[27] = 0; | |
/* LONG biYPelsPerMeter = 0 */ | |
bmi[28] = bmi[29] = bmi[30] = bmi[31] = 0; | |
/* DWORD biClrUsed */ | |
bmi[32] = bmi[33] = bmi[34] = bmi[35] = 0; | |
/* DWORD biClrImportant = 0 */ | |
bmi[36] = bmi[37] = bmi[38] = bmi[39] = 0; | |
/* Set the rgb colors into the bitmap info */ | |
int offset = 40; | |
if (isDirect) { | |
if (useBitfields) { | |
int redMask = 0; | |
int greenMask = 0; | |
int blueMask = 0; | |
switch (depth) { | |
case 16: | |
redMask = 0x7C00; | |
greenMask = 0x3E0; | |
blueMask = 0x1F; | |
break; | |
case 24: | |
redMask = 0xFF; | |
greenMask = 0xFF00; | |
blueMask = 0xFF0000; | |
break; | |
case 32: | |
redMask = 0xFF00; | |
greenMask = 0xFF0000; | |
blueMask = 0xFF000000; | |
break; | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
} | |
bmi[40] = (byte)((redMask & 0xFF) >> 0); | |
bmi[41] = (byte)((redMask & 0xFF00) >> 8); | |
bmi[42] = (byte)((redMask & 0xFF0000) >> 16); | |
bmi[43] = (byte)((redMask & 0xFF000000) >> 24); | |
bmi[44] = (byte)((greenMask & 0xFF) >> 0); | |
bmi[45] = (byte)((greenMask & 0xFF00) >> 8); | |
bmi[46] = (byte)((greenMask & 0xFF0000) >> 16); | |
bmi[47] = (byte)((greenMask & 0xFF000000) >> 24); | |
bmi[48] = (byte)((blueMask & 0xFF) >> 0); | |
bmi[49] = (byte)((blueMask & 0xFF00) >> 8); | |
bmi[50] = (byte)((blueMask & 0xFF0000) >> 16); | |
bmi[51] = (byte)((blueMask & 0xFF000000) >> 24); | |
} | |
} else { | |
for (int j = 0; j < rgbs.length; j++) { | |
bmi[offset] = (byte)rgbs[j].blue; | |
bmi[offset + 1] = (byte)rgbs[j].green; | |
bmi[offset + 2] = (byte)rgbs[j].red; | |
bmi[offset + 3] = 0; | |
offset += 4; | |
} | |
} | |
int[] pBits = new int[1]; | |
int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0); | |
if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* Bitblt DDB into DIB */ | |
int hdcSource = OS.CreateCompatibleDC(hDC); | |
int hdcDest = OS.CreateCompatibleDC(hDC); | |
int hOldSrc = OS.SelectObject(hdcSource, hBitmap); | |
int hOldDest = OS.SelectObject(hdcDest, hDib); | |
OS.BitBlt(hdcDest, 0, 0, width, height, hdcSource, 0, 0, OS.SRCCOPY); | |
OS.SelectObject(hdcSource, hOldSrc); | |
OS.SelectObject(hdcDest, hOldDest); | |
OS.DeleteDC(hdcSource); | |
OS.DeleteDC(hdcDest); | |
return hDib; | |
} | |
/** | |
* Disposes of the operating system resources associated with | |
* the image. Applications must dispose of all images which | |
* they allocate. | |
*/ | |
public void dispose () { | |
if (handle == 0) return; | |
if (type == SWT.ICON) { | |
OS.DestroyIcon (handle); | |
} else { | |
OS.DeleteObject (handle); | |
} | |
handle = 0; | |
memGC = null; | |
if (device.tracking) device.dispose_Object(this); | |
device = null; | |
} | |
/** | |
* Compares the argument to the receiver, and returns true | |
* if they represent the <em>same</em> object using a class | |
* specific comparison. | |
* | |
* @param object the object to compare with this object | |
* @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise | |
* | |
* @see #hashCode | |
*/ | |
public boolean equals (Object object) { | |
if (object == this) return true; | |
if (!(object instanceof Image)) return false; | |
Image image = (Image) object; | |
return device == image.device && handle == image.handle; | |
} | |
/** | |
* Returns the color to which to map the transparent pixel, or null if | |
* the receiver has no transparent pixel. | |
* <p> | |
* There are certain uses of Images that do not support transparency | |
* (for example, setting an image into a button or label). In these cases, | |
* it may be desired to simulate transparency by using the background | |
* color of the widget to paint the transparent pixels of the image. | |
* Use this method to check which color will be used in these cases | |
* in place of transparency. This value may be set with setBackground(). | |
* <p> | |
* | |
* @return the background color of the image, or null if there is no transparency in the image | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
*/ | |
public Color getBackground() { | |
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
if (transparentPixel == -1) return null; | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Compute the background color */ | |
BITMAP bm = new BITMAP(); | |
OS.GetObject(handle, BITMAP.sizeof, bm); | |
int hdcMem = OS.CreateCompatibleDC(hDC); | |
int hOldObject = OS.SelectObject(hdcMem, handle); | |
int red = 0, green = 0, blue = 0; | |
if (bm.bmBitsPixel <= 8) { | |
if (OS.IsWinCE) { | |
byte[] pBits = new byte[1]; | |
OS.MoveMemory(pBits, bm.bmBits, 1); | |
byte oldValue = pBits[0]; | |
int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; | |
pBits[0] = (byte)((transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); | |
OS.MoveMemory(bm.bmBits, pBits, 1); | |
int color = OS.GetPixel(hdcMem, 0, 0); | |
pBits[0] = oldValue; | |
OS.MoveMemory(bm.bmBits, pBits, 1); | |
blue = (color & 0xFF0000) >> 16; | |
green = (color & 0xFF00) >> 8; | |
red = color & 0xFF; | |
} else { | |
byte[] color = new byte[4]; | |
int numColors = OS.GetDIBColorTable(hdcMem, transparentPixel, 1, color); | |
blue = color[0] & 0xFF; | |
green = color[1] & 0xFF; | |
red = color[2] & 0xFF; | |
} | |
} else { | |
switch (bm.bmBitsPixel) { | |
case 16: | |
blue = (transparentPixel & 0x1F) << 3; | |
green = (transparentPixel & 0x3E0) >> 2; | |
red = (transparentPixel & 0x7C00) >> 7; | |
break; | |
case 24: | |
blue = (transparentPixel & 0xFF0000) >> 16; | |
green = (transparentPixel & 0xFF00) >> 8; | |
red = transparentPixel & 0xFF; | |
break; | |
case 32: | |
blue = (transparentPixel & 0xFF000000) >>> 24; | |
green = (transparentPixel & 0xFF0000) >> 16; | |
red = (transparentPixel & 0xFF00) >> 8; | |
break; | |
default: | |
return null; | |
} | |
} | |
OS.SelectObject(hdcMem, hOldObject); | |
OS.DeleteDC(hdcMem); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
return Color.win32_new(device, 0x02000000 | (blue << 16) | (green << 8) | red); | |
} | |
/** | |
* Returns the bounds of the receiver. The rectangle will always | |
* have x and y values of 0, and the width and height of the | |
* image. | |
* | |
* @return a rectangle specifying the image's bounds | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li> | |
* </ul> | |
*/ | |
public Rectangle getBounds() { | |
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
switch (type) { | |
case SWT.BITMAP: | |
BITMAP bm = new BITMAP(); | |
OS.GetObject(handle, BITMAP.sizeof, bm); | |
return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight); | |
case SWT.ICON: | |
if (OS.IsWinCE) { | |
int width = OS.GetSystemMetrics (OS.SM_CXICON); | |
int height = OS.GetSystemMetrics (OS.SM_CYICON); | |
return new Rectangle(0, 0, width, height); | |
} else { | |
ICONINFO info = new ICONINFO(); | |
OS.GetIconInfo(handle, info); | |
int hBitmap = info.hbmColor; | |
if (hBitmap == 0) hBitmap = info.hbmMask; | |
bm = new BITMAP(); | |
OS.GetObject(hBitmap, BITMAP.sizeof, bm); | |
if (hBitmap == info.hbmMask) bm.bmHeight /= 2; | |
if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor); | |
if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask); | |
return new Rectangle(0, 0, bm.bmWidth, bm.bmHeight); | |
} | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); | |
return null; | |
} | |
} | |
/** | |
* Returns an <code>ImageData</code> based on the receiver | |
* Modifications made to this <code>ImageData</code> will not | |
* affect the Image. | |
* | |
* @return an <code>ImageData</code> containing the image's data and attributes | |
* | |
* @exception SWTException <ul> | |
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
* <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li> | |
* </ul> | |
* | |
* @see ImageData | |
*/ | |
public ImageData getImageData() { | |
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
BITMAP bm; | |
int depth, width, height; | |
switch (type) { | |
case SWT.ICON: { | |
ICONINFO info = new ICONINFO(); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetIconInfo(handle, info); | |
/* Get the basic BITMAP information */ | |
int hBitmap = info.hbmColor; | |
if (hBitmap == 0) hBitmap = info.hbmMask; | |
bm = new BITMAP(); | |
OS.GetObject(hBitmap, BITMAP.sizeof, bm); | |
depth = bm.bmPlanes * bm.bmBitsPixel; | |
width = bm.bmWidth; | |
if (hBitmap == info.hbmMask) bm.bmHeight /= 2; | |
height = bm.bmHeight; | |
int numColors = 0; | |
if (depth <= 8) numColors = 1 << depth; | |
/* Create the BITMAPINFO */ | |
byte[] bmi = new byte[40 + numColors * 4]; | |
/* DWORD biSize = 40 */ | |
bmi[0] = 40; bmi[1] = bmi[2] = bmi[3] = 0; | |
/* LONG biWidth = width */ | |
bmi[4] = (byte)(width & 0xFF); | |
bmi[5] = (byte)((width >> 8) & 0xFF); | |
bmi[6] = (byte)((width >> 16) & 0xFF); | |
bmi[7] = (byte)((width >> 24) & 0xFF); | |
/* LONG biHeight = height */ | |
bmi[8] = (byte)(-height & 0xFF); | |
bmi[9] = (byte)((-height >> 8) & 0xFF); | |
bmi[10] = (byte)((-height >> 16) & 0xFF); | |
bmi[11] = (byte)((-height >> 24) & 0xFF); | |
/* WORD biPlanes = 1 */ | |
bmi[12] = 1; | |
bmi[13] = 0; | |
/* WORD biBitCount = bm.bmPlanes * bm.bmBitsPixel */ | |
bmi[14] = (byte)(depth & 0xFF); | |
bmi[15] = (byte)((depth >> 8) & 0xFF); | |
/* DWORD biCompression = BI_RGB = 0 */ | |
bmi[16] = bmi[17] = bmi[18] = bmi[19] = 0; | |
/* DWORD biSizeImage = 0 (default) */ | |
bmi[20] = bmi[21] = bmi[22] = bmi[23] = 0; | |
/* LONG biXPelsPerMeter = 0 */ | |
bmi[24] = bmi[25] = bmi[26] = bmi[27] = 0; | |
/* LONG biYPelsPerMeter = 0 */ | |
bmi[28] = bmi[29] = bmi[30] = bmi[31] = 0; | |
/* DWORD biClrUsed = 0 */ | |
bmi[32] = bmi[33] = bmi[34] = bmi[35] = 0; | |
/* DWORD biClrImportant = 0 */ | |
bmi[36] = bmi[37] = bmi[38] = bmi[39] = 0; | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Create the DC and select the bitmap */ | |
int hBitmapDC = OS.CreateCompatibleDC(hDC); | |
int hOldBitmap = OS.SelectObject(hBitmapDC, hBitmap); | |
/* Select the palette if necessary */ | |
int oldPalette = 0; | |
if (depth <= 8) { | |
int hPalette = device.hPalette; | |
if (hPalette != 0) { | |
oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false); | |
OS.RealizePalette(hBitmapDC); | |
} | |
} | |
/* Find the size of the image and allocate data */ | |
int imageSize; | |
/* Call with null lpBits to get the image size */ | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, hBitmap, 0, height, 0, bmi, OS.DIB_RGB_COLORS); | |
imageSize = (bmi[20] & 0xFF) | ((bmi[21] & 0xFF) << 8) | ((bmi[22] & 0xFF) << 16) | ((bmi[23] & 0xFF) << 24); | |
byte[] data = new byte[imageSize]; | |
/* Get the bitmap data */ | |
int hHeap = OS.GetProcessHeap(); | |
int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, hBitmap, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS); | |
OS.MoveMemory(data, lpvBits, imageSize); | |
/* Calculate the palette */ | |
PaletteData palette = null; | |
if (depth <= 8) { | |
RGB[] rgbs = new RGB[numColors]; | |
int srcIndex = 40; | |
for (int i = 0; i < numColors; i++) { | |
rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF); | |
srcIndex += 4; | |
} | |
palette = new PaletteData(rgbs); | |
} else if (depth == 16) { | |
palette = new PaletteData(0x7C00, 0x3E0, 0x1F); | |
} else if (depth == 24) { | |
palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); | |
} else if (depth == 32) { | |
palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); | |
} else { | |
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
} | |
/* Do the mask */ | |
byte [] maskData = null; | |
if (info.hbmColor == 0) { | |
/* Do the bottom half of the mask */ | |
maskData = new byte[imageSize]; | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, hBitmap, height, height, lpvBits, bmi, OS.DIB_RGB_COLORS); | |
OS.MoveMemory(maskData, lpvBits, imageSize); | |
} else { | |
/* Do the entire mask */ | |
/* Create the BITMAPINFO */ | |
bmi = new byte[48]; | |
/* DWORD biSize = 40 */ | |
bmi[0] = 40; bmi[1] = bmi[2] = bmi[3] = 0; | |
/* LONG biWidth = width */ | |
bmi[4] = (byte)(width & 0xFF); | |
bmi[5] = (byte)((width >> 8) & 0xFF); | |
bmi[6] = (byte)((width >> 16) & 0xFF); | |
bmi[7] = (byte)((width >> 24) & 0xFF); | |
/* LONG biHeight = height */ | |
bmi[8] = (byte)(-height & 0xFF); | |
bmi[9] = (byte)((-height >> 8) & 0xFF); | |
bmi[10] = (byte)((-height >> 16) & 0xFF); | |
bmi[11] = (byte)((-height >> 24) & 0xFF); | |
/* WORD biPlanes = 1 */ | |
bmi[12] = 1; | |
bmi[13] = 0; | |
/* WORD biBitCount = 1 */ | |
bmi[14] = 1; | |
bmi[15] = 0; | |
/* DWORD biCompression = BI_RGB = 0 */ | |
bmi[16] = bmi[17] = bmi[18] = bmi[19] = 0; | |
/* DWORD biSizeImage = 0 (default) */ | |
bmi[20] = bmi[21] = bmi[22] = bmi[23] = 0; | |
/* LONG biXPelsPerMeter = 0 */ | |
bmi[24] = bmi[25] = bmi[26] = bmi[27] = 0; | |
/* LONG biYPelsPerMeter = 0 */ | |
bmi[28] = bmi[29] = bmi[30] = bmi[31] = 0; | |
/* DWORD biClrUsed = 0 */ | |
bmi[32] = bmi[33] = bmi[34] = bmi[35] = 0; | |
/* DWORD biClrImportant = 0 */ | |
bmi[36] = bmi[37] = bmi[38] = bmi[39] = 0; | |
/* First color black */ | |
bmi[40] = bmi[41] = bmi[42] = bmi[43] = 0; | |
/* Second color white */ | |
bmi[44] = bmi[45] = bmi[46] = (byte)0xFF; | |
bmi[47] = 0; | |
OS.SelectObject(hBitmapDC, info.hbmMask); | |
/* Call with null lpBits to get the image size */ | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, 0, bmi, OS.DIB_RGB_COLORS); | |
imageSize = (bmi[20] & 0xFF) | ((bmi[21] & 0xFF) << 8) | ((bmi[22] & 0xFF) << 16) | ((bmi[23] & 0xFF) << 24); | |
maskData = new byte[imageSize]; | |
int lpvMaskBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, lpvMaskBits, bmi, OS.DIB_RGB_COLORS); | |
OS.MoveMemory(maskData, lpvMaskBits, imageSize); | |
OS.HeapFree(hHeap, 0, lpvMaskBits); | |
/* Loop to invert the mask */ | |
for (int i = 0; i < maskData.length; i++) { | |
maskData[i] ^= -1; | |
} | |
/* Make sure mask scanlinePad is 2 */ | |
int desiredScanline = (width + 7) / 8; | |
desiredScanline = desiredScanline + (desiredScanline % 2); | |
int realScanline = imageSize / height; | |
if (realScanline != desiredScanline) { | |
byte[] newData = new byte[desiredScanline * height]; | |
int srcIndex = 0; | |
int destIndex = 0; | |
for (int i = 0; i < height; i++) { | |
System.arraycopy(maskData, srcIndex, newData, destIndex, desiredScanline); | |
destIndex += desiredScanline; | |
srcIndex += realScanline; | |
} | |
maskData = newData; | |
} | |
} | |
/* Clean up */ | |
OS.HeapFree(hHeap, 0, lpvBits); | |
OS.SelectObject(hBitmapDC, hOldBitmap); | |
if (oldPalette != 0) { | |
OS.SelectPalette(hBitmapDC, oldPalette, false); | |
OS.RealizePalette(hBitmapDC); | |
} | |
OS.DeleteDC(hBitmapDC); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor); | |
if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask); | |
/* Construct and return the ImageData */ | |
ImageData imageData = new ImageData(width, height, depth, palette, 4, data); | |
imageData.maskData = maskData; | |
// imageData.maskPad = 4; | |
imageData.maskPad = 2; | |
return imageData; | |
} | |
case SWT.BITMAP: { | |
/* Get the basic BITMAP information */ | |
bm = new BITMAP(); | |
OS.GetObject(handle, BITMAP.sizeof, bm); | |
depth = bm.bmPlanes * bm.bmBitsPixel; | |
width = bm.bmWidth; | |
height = bm.bmHeight; | |
/* Find out whether this is a DIB or a DDB. */ | |
boolean isDib = (bm.bmBits != 0); | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* | |
* Feature in WinCE. GetDIBits is not available in WinCE. The | |
* workaround is to create a temporary DIB from the DDB and use | |
* the bmBits field of DIBSECTION to retrieve the image data. | |
*/ | |
int handle = this.handle; | |
if (OS.IsWinCE) { | |
if (!isDib) { | |
handle = createDIBFromDDB(hDC, handle, width, height); | |
isDib = true; | |
} | |
} | |
DIBSECTION dib = null; | |
if (isDib) { | |
dib = new DIBSECTION(); | |
OS.GetObject(handle, DIBSECTION.sizeof, dib); | |
} | |
/* Calculate number of colors */ | |
int numColors = 0; | |
if (depth <= 8) { | |
if (isDib) { | |
numColors = dib.biClrUsed; | |
} else { | |
numColors = 1 << depth; | |
} | |
} | |
/* Create the BITMAPINFO */ | |
byte[] bmi = null; | |
if (!isDib) { | |
bmi = new byte[40 + numColors * 4]; | |
/* DWORD biSize = 40 */ | |
bmi[0] = 40; bmi[1] = bmi[2] = bmi[3] = 0; | |
/* LONG biWidth = width */ | |
bmi[4] = (byte)(width & 0xFF); | |
bmi[5] = (byte)((width >> 8) & 0xFF); | |
bmi[6] = (byte)((width >> 16) & 0xFF); | |
bmi[7] = (byte)((width >> 24) & 0xFF); | |
/* LONG biHeight = height */ | |
bmi[8] = (byte)(-height & 0xFF); | |
bmi[9] = (byte)((-height >> 8) & 0xFF); | |
bmi[10] = (byte)((-height >> 16) & 0xFF); | |
bmi[11] = (byte)((-height >> 24) & 0xFF); | |
/* WORD biPlanes = 1 */ | |
bmi[12] = 1; | |
bmi[13] = 0; | |
/* WORD biBitCount = bm.bmPlanes * bm.bmBitsPixel */ | |
bmi[14] = (byte)(depth & 0xFF); | |
bmi[15] = (byte)((depth >> 8) & 0xFF); | |
/* DWORD biCompression = BI_RGB = 0 */ | |
bmi[16] = bmi[17] = bmi[18] = bmi[19] = 0; | |
/* DWORD biSizeImage = 0 (default) */ | |
bmi[20] = bmi[21] = bmi[22] = bmi[23] = 0; | |
/* LONG biXPelsPerMeter = 0 */ | |
bmi[24] = bmi[25] = bmi[26] = bmi[27] = 0; | |
/* LONG biYPelsPerMeter = 0 */ | |
bmi[28] = bmi[29] = bmi[30] = bmi[31] = 0; | |
/* DWORD biClrUsed = 0 */ | |
bmi[32] = bmi[33] = bmi[34] = bmi[35] = 0; | |
/* DWORD biClrImportant = 0 */ | |
bmi[36] = bmi[37] = bmi[38] = bmi[39] = 0; | |
} | |
/* Create the DC and select the bitmap */ | |
int hBitmapDC = OS.CreateCompatibleDC(hDC); | |
int hOldBitmap = OS.SelectObject(hBitmapDC, handle); | |
/* Select the palette if necessary */ | |
int oldPalette = 0; | |
if (!isDib && depth <= 8) { | |
int hPalette = device.hPalette; | |
if (hPalette != 0) { | |
oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false); | |
OS.RealizePalette(hBitmapDC); | |
} | |
} | |
/* Find the size of the image and allocate data */ | |
int imageSize; | |
if (isDib) { | |
imageSize = dib.biSizeImage; | |
} else { | |
/* Call with null lpBits to get the image size */ | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, handle, 0, height, 0, bmi, OS.DIB_RGB_COLORS); | |
imageSize = (bmi[20] & 0xFF) | ((bmi[21] & 0xFF) << 8) | ((bmi[22] & 0xFF) << 16) | ((bmi[23] & 0xFF) << 24); | |
} | |
byte[] data = new byte[imageSize]; | |
/* Get the bitmap data */ | |
if (isDib) { | |
if (OS.IsWinCE && this.handle != handle) { | |
/* get image data from the temporary DIB */ | |
OS.MoveMemory(data, dib.bmBits, imageSize); | |
} else { | |
OS.MoveMemory(data, bm.bmBits, imageSize); | |
} | |
} else { | |
int hHeap = OS.GetProcessHeap(); | |
int lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.GetDIBits(hBitmapDC, handle, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS); | |
OS.MoveMemory(data, lpvBits, imageSize); | |
OS.HeapFree(hHeap, 0, lpvBits); | |
} | |
/* Calculate the palette */ | |
PaletteData palette = null; | |
if (isDib) { | |
if (depth <= 8) { | |
RGB[] rgbs = new RGB[numColors]; | |
if (OS.IsWinCE) { | |
/* | |
* Feature on WinCE. GetDIBColorTable is not supported. | |
* The workaround is to set a pixel to the desired | |
* palette index and use getPixel to get the corresponding | |
* RGB value. | |
*/ | |
int red = 0, green = 0, blue = 0; | |
byte[] pBits = new byte[1]; | |
OS.MoveMemory(pBits, bm.bmBits, 1); | |
byte oldValue = pBits[0]; | |
int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF; | |
for (int i = 0; i < numColors; i++) { | |
pBits[0] = (byte)((i << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask)); | |
OS.MoveMemory(bm.bmBits, pBits, 1); | |
int color = OS.GetPixel(hBitmapDC, 0, 0); | |
blue = (color & 0xFF0000) >> 16; | |
green = (color & 0xFF00) >> 8; | |
red = color & 0xFF; | |
rgbs[i] = new RGB(red, green, blue); | |
} | |
pBits[0] = oldValue; | |
OS.MoveMemory(bm.bmBits, pBits, 1); | |
} else { | |
byte[] colors = new byte[numColors * 4]; | |
OS.GetDIBColorTable(hBitmapDC, 0, numColors, colors); | |
int colorIndex = 0; | |
for (int i = 0; i < rgbs.length; i++) { | |
rgbs[i] = new RGB(colors[colorIndex + 2] & 0xFF, colors[colorIndex + 1] & 0xFF, colors[colorIndex] & 0xFF); | |
colorIndex += 4; | |
} | |
} | |
palette = new PaletteData(rgbs); | |
} else if (depth == 16) { | |
palette = new PaletteData(0x7C00, 0x3E0, 0x1F); | |
} else if (depth == 24 || depth == 32) { | |
palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); | |
} else { | |
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
} | |
} else { | |
if (depth <= 8) { | |
RGB[] rgbs = new RGB[numColors]; | |
int srcIndex = 40; | |
for (int i = 0; i < numColors; i++) { | |
rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF); | |
srcIndex += 4; | |
} | |
palette = new PaletteData(rgbs); | |
} else if (depth == 16) { | |
palette = new PaletteData(0x7C00, 0x3E0, 0x1F); | |
} else if (depth == 24) { | |
palette = new PaletteData(0xFF, 0xFF00, 0xFF0000); | |
} else if (depth == 32) { | |
palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); | |
} else { | |
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
} | |
} | |
/* Clean up */ | |
OS.SelectObject(hBitmapDC, hOldBitmap); | |
if (oldPalette != 0) { | |
OS.SelectPalette(hBitmapDC, oldPalette, false); | |
OS.RealizePalette(hBitmapDC); | |
} | |
if (OS.IsWinCE) { | |
if (handle != this.handle) { | |
/* free temporary DIB */ | |
OS.DeleteObject (handle); | |
} | |
} | |
OS.DeleteDC(hBitmapDC); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
/* 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); | |
} | |
return imageData; | |
} | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_FORMAT); | |
return null; | |
} | |
} | |
/** | |
* Returns an integer hash code for the receiver. Any two | |
* objects which return <code>true</code> when passed to | |
* <code>equals</code> must return the same value for this | |
* method. | |
* | |
* @return the receiver's hash | |
* | |
* @see #equals | |
*/ | |
public int hashCode () { | |
return handle; | |
} | |
void init(Device device, int width, int height) { | |
if (width <= 0 || height <= 0) { | |
SWT.error (SWT.ERROR_INVALID_ARGUMENT); | |
} | |
this.device = device; | |
type = SWT.BITMAP; | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Fill the bitmap with the current background color */ | |
handle = OS.CreateCompatibleBitmap(hDC, width, height); | |
if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
int memDC = OS.CreateCompatibleDC(hDC); | |
int hOldBitmap = OS.SelectObject(memDC, handle); | |
OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY); | |
OS.SelectObject(memDC, hOldBitmap); | |
OS.DeleteDC(memDC); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
} | |
void init(Device device, ImageData i) { | |
if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
this.device = device; | |
/* | |
* BUG in Windows 98: | |
* A monochrome DIBSection will display as solid black | |
* on Windows 98 machines, even though it contains the | |
* correct data. The fix is to convert 1-bit ImageData | |
* into 4-bit ImageData before creating the image. | |
*/ | |
/* Windows does not support 2-bit images. Convert to 4-bit image. */ | |
if ((i.depth == 1 && i.getTransparencyType() != SWT.TRANSPARENCY_MASK) || i.depth == 2) { | |
ImageData img = new ImageData(i.width, i.height, 4, i.palette); | |
ImageData.blit(ImageData.BLIT_SRC, | |
i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, null, null, null, | |
ImageData.ALPHA_OPAQUE, null, 0, | |
img.data, img.depth, img.bytesPerLine, i.getByteOrder(), 0, 0, img.width, img.height, null, null, null, | |
false, false); | |
img.transparentPixel = i.transparentPixel; | |
img.maskPad = i.maskPad; | |
img.maskData = i.maskData; | |
img.alpha = i.alpha; | |
img.alphaData = i.alphaData; | |
i = img; | |
} | |
/* | |
* Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F), | |
* 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask | |
* (0xFF000000, 0xFF0000, 0xFF00). Make sure the image is | |
* Windows-supported. | |
*/ | |
if (i.palette.isDirect) { | |
final PaletteData palette = i.palette; | |
final int redMask = palette.redMask; | |
final int greenMask = palette.greenMask; | |
final int blueMask = palette.blueMask; | |
int newDepth = i.depth; | |
int newOrder = ImageData.MSB_FIRST; | |
PaletteData newPalette = null; | |
switch (i.depth) { | |
case 8: | |
newDepth = 16; | |
newOrder = ImageData.LSB_FIRST; | |
newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F); | |
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 == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) { | |
newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); | |
} | |
break; | |
default: | |
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
} | |
if (newPalette != null) { | |
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, redMask, greenMask, blueMask, | |
ImageData.ALPHA_OPAQUE, null, 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(palette.getRGB(i.transparentPixel)); | |
} | |
img.maskPad = i.maskPad; | |
img.maskData = i.maskData; | |
img.alpha = i.alpha; | |
img.alphaData = i.alphaData; | |
i = img; | |
} | |
} | |
/* Construct bitmap info header by hand */ | |
RGB[] rgbs = i.palette.getRGBs(); | |
byte[] bmi; | |
boolean useBitfields = OS.IsWinCE && (i.depth == 16 || i.depth == 32); | |
if (i.palette.isDirect) | |
bmi = new byte[40 + (useBitfields ? 12 : 0)]; | |
else | |
bmi = new byte[40 + rgbs.length * 4]; | |
/* DWORD biSize = 40 */ | |
bmi[0] = 40; bmi[1] = 0; bmi[2] = 0; bmi[3] = 0; | |
/* LONG biWidth = width */ | |
bmi[4] = (byte)(i.width & 0xFF); | |
bmi[5] = (byte)((i.width >> 8) & 0xFF); | |
bmi[6] = (byte)((i.width >> 16) & 0xFF); | |
bmi[7] = (byte)((i.width >> 24) & 0xFF); | |
/* LONG biHeight = height */ | |
int height = -i.height; | |
bmi[8] = (byte)(height & 0xFF); | |
bmi[9] = (byte)((height >> 8) & 0xFF); | |
bmi[10] = (byte)((height >> 16) & 0xFF); | |
bmi[11] = (byte)((height >> 24) & 0xFF); | |
/* WORD biPlanes = 1 */ | |
bmi[12] = 1; | |
bmi[13] = 0; | |
/* WORD biBitCount = depth */ | |
bmi[14] = (byte)(i.depth & 0xFF); | |
bmi[15] = (byte)((i.depth >> 8) & 0xFF); | |
if (useBitfields) { | |
/* DWORD biCompression = BI_BITFIELDS = 3 */ | |
bmi[16] = 3; bmi[17] = bmi[18] = bmi[19] = 0; | |
} else { | |
/* DWORD biCompression = BI_RGB = 0 */ | |
bmi[16] = bmi[17] = bmi[18] = bmi[19] = 0; | |
} | |
/* DWORD biSizeImage = 0 (default) */ | |
bmi[20] = bmi[21] = bmi[22] = bmi[23] = 0; | |
/* LONG biXPelsPerMeter = 0 */ | |
bmi[24] = bmi[25] = bmi[26] = bmi[27] = 0; | |
/* LONG biYPelsPerMeter = 0 */ | |
bmi[28] = bmi[29] = bmi[30] = bmi[31] = 0; | |
/* DWORD biClrUsed */ | |
if (rgbs == null) { | |
bmi[32] = bmi[33] = bmi[34] = bmi[35] = 0; | |
} else { | |
bmi[32] = (byte)(rgbs.length & 0xFF); | |
bmi[33] = (byte)((rgbs.length >> 8) & 0xFF); | |
bmi[34] = (byte)((rgbs.length >> 16) & 0xFF); | |
bmi[35] = (byte)((rgbs.length >> 24) & 0xFF); | |
} | |
/* DWORD biClrImportant = 0 */ | |
bmi[36] = bmi[37] = bmi[38] = bmi[39] = 0; | |
/* Set the rgb colors into the bitmap info */ | |
int offset = 40; | |
if (i.palette.isDirect) { | |
if (useBitfields) { | |
PaletteData palette = i.palette; | |
int redMask = palette.redMask; | |
int greenMask = palette.greenMask; | |
int blueMask = palette.blueMask; | |
bmi[40] = (byte)((redMask & 0xFF) >> 0); | |
bmi[41] = (byte)((redMask & 0xFF00) >> 8); | |
bmi[42] = (byte)((redMask & 0xFF0000) >> 16); | |
bmi[43] = (byte)((redMask & 0xFF000000) >> 24); | |
bmi[44] = (byte)((greenMask & 0xFF) >> 0); | |
bmi[45] = (byte)((greenMask & 0xFF00) >> 8); | |
bmi[46] = (byte)((greenMask & 0xFF0000) >> 16); | |
bmi[47] = (byte)((greenMask & 0xFF000000) >> 24); | |
bmi[48] = (byte)((blueMask & 0xFF) >> 0); | |
bmi[49] = (byte)((blueMask & 0xFF00) >> 8); | |
bmi[50] = (byte)((blueMask & 0xFF0000) >> 16); | |
bmi[51] = (byte)((blueMask & 0xFF000000) >> 24); | |
} | |
} else { | |
for (int j = 0; j < rgbs.length; j++) { | |
bmi[offset] = (byte)rgbs[j].blue; | |
bmi[offset + 1] = (byte)rgbs[j].green; | |
bmi[offset + 2] = (byte)rgbs[j].red; | |
bmi[offset + 3] = 0; | |
offset += 4; | |
} | |
} | |
int[] pBits = new int[1]; | |
int hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0); | |
if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
/* In case of a scanline pad other than 4, do the work to convert it */ | |
byte[] data = i.data; | |
if (i.scanlinePad != 4 && (i.bytesPerLine % 4 != 0)) { | |
int newBpl = i.bytesPerLine + (4 - (i.bytesPerLine % 4)); | |
byte[] newData = new byte[i.height * newBpl]; | |
int srcPtr = 0; | |
int destPtr = 0; | |
for (int y = 0; y < i.height; y++) { | |
System.arraycopy(data, srcPtr, newData, destPtr, i.bytesPerLine); | |
srcPtr += i.bytesPerLine; | |
destPtr += newBpl; | |
} | |
data = newData; | |
} | |
OS.MoveMemory(pBits[0], data, data.length); | |
if (i.getTransparencyType() == SWT.TRANSPARENCY_MASK) { | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Create the color bitmap */ | |
int hdcSrc = OS.CreateCompatibleDC(hDC); | |
OS.SelectObject(hdcSrc, hDib); | |
int hBitmap = OS.CreateCompatibleBitmap(hDC, i.width, i.height); | |
if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
int hdcDest = OS.CreateCompatibleDC(hDC); | |
OS.SelectObject(hdcDest, hBitmap); | |
OS.BitBlt(hdcDest, 0, 0, i.width, i.height, hdcSrc, 0, 0, OS.SRCCOPY); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
/* Create the mask */ | |
// int hHeap = OS.GetProcessHeap(); | |
// int bmBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, i.maskData.length); | |
// OS.MoveMemory(bmBits, i.maskData, i.maskData.length); | |
// BITMAP bm = new BITMAP(); | |
// bm.bmWidth = i.width; | |
// bm.bmHeight = i.height; | |
// bm.bmWidthBytes = (((i.width + 7) / 8) + 3) / 4 * 4; | |
// bm.bmPlanes = 1; | |
// bm.bmBitsPixel = 1; | |
// bm.bmBits = bmBits; | |
// int hMask = OS.CreateBitmapIndirect(bm); | |
// OS.HeapFree(hHeap, 0, bmBits); | |
int hMask = OS.CreateBitmap(i.width, i.height, 1, 1, i.maskData); | |
if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
OS.SelectObject(hdcSrc, hMask); | |
OS.PatBlt(hdcSrc, 0, 0, i.width, i.height, OS.DSTINVERT); | |
OS.DeleteDC(hdcSrc); | |
OS.DeleteDC(hdcDest); | |
/* Create the icon */ | |
ICONINFO info = new ICONINFO(); | |
info.fIcon = true; | |
info.hbmColor = hBitmap; | |
info.hbmMask = hMask; | |
int hIcon = OS.CreateIconIndirect(info); | |
if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
OS.DeleteObject(hBitmap); | |
OS.DeleteObject(hMask); | |
OS.DeleteObject(hDib); | |
this.handle = hIcon; | |
this.type = SWT.ICON; | |
} else { | |
this.handle = hDib; | |
this.type = SWT.BITMAP; | |
this.transparentPixel = i.transparentPixel; | |
if (this.transparentPixel == -1) { | |
this.alpha = i.alpha; | |
if (i.alpha == -1 && i.alphaData != null) { | |
this.alphaData = new byte[i.alphaData.length]; | |
System.arraycopy(i.alphaData, 0, this.alphaData, 0, alphaData.length); | |
} | |
} | |
} | |
} | |
/** | |
* Invokes platform specific functionality to allocate a new GC handle. | |
* <p> | |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
* API for <code>Image</code>. It is marked public only so that it | |
* can be shared within the packages provided by SWT. It is not | |
* available on all platforms, and should never be called from | |
* application code. | |
* </p> | |
* | |
* @param data the platform specific GC data | |
* @return the platform specific GC handle | |
* | |
* @private | |
*/ | |
public int internal_new_GC (GCData data) { | |
if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
/* | |
* Create a new GC that can draw into the image. | |
* Only supported for bitmaps. | |
*/ | |
if (type != SWT.BITMAP || memGC != null) { | |
SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
} | |
/* Create a compatible HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
int imageDC = OS.CreateCompatibleDC(hDC); | |
device.internal_dispose_GC(hDC, null); | |
if (imageDC == 0) SWT.error(SWT.ERROR_NO_HANDLES); | |
if (data != null) { | |
/* Set the GCData fields */ | |
data.device = device; | |
data.image = this; | |
data.hFont = device.systemFont; | |
} | |
return imageDC; | |
} | |
/** | |
* Invokes platform specific functionality to dispose a GC handle. | |
* <p> | |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
* API for <code>Image</code>. It is marked public only so that it | |
* can be shared within the packages provided by SWT. It is not | |
* available on all platforms, and should never be called from | |
* application code. | |
* </p> | |
* | |
* @param handle the platform specific GC handle | |
* @param data the platform specific GC data | |
* | |
* @private | |
*/ | |
public void internal_dispose_GC (int hDC, GCData data) { | |
OS.DeleteDC(hDC); | |
} | |
/** | |
* Returns <code>true</code> if the image has been disposed, | |
* and <code>false</code> otherwise. | |
* <p> | |
* This method gets the dispose state for the image. | |
* When an image has been disposed, it is an error to | |
* invoke any other method using the image. | |
* | |
* @return <code>true</code> when the image is disposed and <code>false</code> otherwise | |
*/ | |
public boolean isDisposed() { | |
return handle == 0; | |
} | |
/** | |
* Sets the color to which to map the transparent pixel. | |
* <p> | |
* There are certain uses of <code>Images</code> that do not support | |
* transparency (for example, setting an image into a button or label). | |
* In these cases, it may be desired to simulate transparency by using | |
* the background color of the widget to paint the transparent pixels | |
* of the image. This method specifies the color that will be used in | |
* these cases. For example: | |
* <pre> | |
* Button b = new Button(); | |
* image.setBackground(b.getBackground());> | |
* b.setImage(image); | |
* </pre> | |
* </p><p> | |
* The image may be modified by this operation (in effect, the | |
* transparent regions may be filled with the supplied color). Hence | |
* this operation is not reversible and it is not legal to call | |
* this function twice or with a null argument. | |
* </p><p> | |
* This method has no effect if the receiver does not have a transparent | |
* pixel value. | |
* </p> | |
* | |
* @param color the color to use when a transparent pixel is specified | |
* | |
* @exception IllegalArgumentException <ul> | |
* <li>ERROR_NULL_ARGUMENT - if the color is null</li> | |
* <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li> | |
* </ul> | |
* @exception SWTException <ul> | |
* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li> | |
* </ul> | |
*/ | |
public void setBackground(Color color) { | |
/* | |
* Note. Not implemented on WinCE. | |
*/ | |
if (OS.IsWinCE) return; | |
if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); | |
if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); | |
if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); | |
if (transparentPixel == -1) return; | |
/* Get the HDC for the device */ | |
int hDC = device.internal_new_GC(null); | |
/* Change the background color in the image */ | |
BITMAP bm = new BITMAP(); | |
OS.GetObject(handle, BITMAP.sizeof, bm); | |
int hdcMem = OS.CreateCompatibleDC(hDC); | |
OS.SelectObject(hdcMem, handle); | |
int maxColors = 1 << bm.bmBitsPixel; | |
byte[] colors = new byte[maxColors * 4]; | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
int numColors = OS.GetDIBColorTable(hdcMem, 0, maxColors, colors); | |
int offset = transparentPixel * 4; | |
colors[offset] = (byte)color.getBlue(); | |
colors[offset + 1] = (byte)color.getGreen(); | |
colors[offset + 2] = (byte)color.getRed(); | |
if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED); | |
OS.SetDIBColorTable(hdcMem, 0, numColors, colors); | |
OS.DeleteDC(hdcMem); | |
/* Release the HDC for the device */ | |
device.internal_dispose_GC(hDC, null); | |
} | |
/** | |
* Returns a string containing a concise, human-readable | |
* description of the receiver. | |
* | |
* @return a string representation of the receiver | |
*/ | |
public String toString () { | |
if (isDisposed()) return "Image {*DISPOSED*}"; | |
return "Image {" + handle + "}"; | |
} | |
/** | |
* Invokes platform specific functionality to allocate a new image. | |
* <p> | |
* <b>IMPORTANT:</b> This method is <em>not</em> part of the public | |
* API for <code>Image</code>. It is marked public only so that it | |
* can be shared within the packages provided by SWT. It is not | |
* available on all platforms, and should never be called from | |
* application code. | |
* </p> | |
* | |
* @param device the device on which to allocate the color | |
* @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>) | |
* @param handle the OS handle for the image | |
* @param hPalette the OS handle for the palette, or 0 | |
* | |
* @private | |
*/ | |
public static Image win32_new(Device device, int type, int handle) { | |
if (device == null) device = Device.getDevice(); | |
Image image = new Image(); | |
image.type = type; | |
image.handle = handle; | |
image.device = device; | |
return image; | |
} | |
} |