blob: 81e442ec8b0a8395ad6c11b1fbd72f6b7dada2a1 [file] [log] [blame]
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;
}
}