/*******************************************************************************
* Copyright (c) 2000, 2007 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.swt.graphics;
import org.eclipse.swt.internal.carbon.*;
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 GC.drawImage()
* and display on widgets with, for example, Button.setImage()
.
*
* If loaded from a file format that supports it, an
* Image
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.
*
* There are two primary ways to use Images
.
* The first is to load a graphic file from disk and create an
* Image
from it. This is done using an Image
* constructor, for example:
*
* Image i = new Image(device, "C:\\graphic.bmp"); ** 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: *
* 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); **
* Applications which require even greater control over the image
* loading process should use the support provided in class
* ImageLoader
.
*
* Application code must explicitly invoke the Image.dispose()
* method to release the operating system resources managed by each instance
* when those instances are no longer required.
*
SWT.BITMAP
, SWT.ICON
)
* * IMPORTANT: This field is not part of the SWT * public API. 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 accessed from application code. *
*/ public int type; /** * the handle to the OS image resource * (Warning: This field is platform dependent) ** IMPORTANT: This field is not part of the SWT * public API. 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 accessed from application code. *
*/ public int handle; /** * The data to the OS image resource. * (Warning: This field is platform dependent) ** IMPORTANT: This field is not part of the SWT * public API. 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 accessed from application code. *
*/ public int data; /** * specifies the transparent pixel */ int transparentPixel = -1; /** * The GC the image is currently selected in. */ GC memGC; /** * The alpha data of the image. */ byte[] alphaData; /** * The global alpha value to be used for every pixel. */ int alpha = -1; /** * The width of the image. */ int width = -1; /** * The height of the image. */ int height = -1; /** * Specifies the default scanline padding. */ static final int DEFAULT_SCANLINE_PAD = 4; Image(Device device) { super(device); } /** * 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: ** Image i = new Image(device, width, height); * GC gc = new GC(i); * gc.drawRectangle(0, 0, 50, 50); * gc.dispose(); **
* Note: Some platforms may have a limitation on the size * of image that can be created (size depends on width, height, * and depth). For example, Windows 95, 98, and ME do not allow * images larger than 16M. *
* * @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 IllegalArgumentExceptionIMAGE_COPY
, IMAGE_DISABLE
or IMAGE_GRAY
*
* @exception IllegalArgumentException IMAGE_COPY
, IMAGE_DISABLE
or IMAGE_GRAY
* Image i = new Image(device, boundsRectangle); * GC gc = new GC(i); * gc.drawRectangle(0, 0, 50, 50); * gc.dispose(); **
* Note: Some platforms may have a limitation on the size * of image that can be created (size depends on width, height, * and depth). For example, Windows 95, 98, and ME do not allow * images larger than 16M. *
* * @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 IllegalArgumentExceptionImageData
.
*
* @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 SWT.ICON
, from the two given ImageData
* objects. The two images must be the same size. Pixel transparency
* in either image will be ignored.
* * 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. *
* * @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
* 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
* ImageLoader.load()
.
*
* This constructor may be used to load a resource as follows: *
** static Image loadImage (Display display, Class clazz, String string) { * InputStream stream = clazz.getResourceAsStream (string); * if (stream == null) return null; * Image image = null; * try { * image = new Image (display, stream); * } catch (SWTException ex) { * } finally { * try { * stream.close (); * } catch (IOException ex) {} * } * return image; * } ** * @param device the device on which to create the image * @param stream the input stream to load the image from * * @exception IllegalArgumentException
* 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 IllegalArgumentException
true
if the object is the same as this object and false
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 &&
transparentPixel == image.transparentPixel;
}
/**
* Returns the color to which to map the transparent pixel, or null if
* the receiver has no transparent pixel.
* * 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(). *
* * @return the background color of the image, or null if there is no transparency in the image * * @exception SWTException
ImageData
based on the receiver
* Modifications made to this ImageData
will not
* affect the Image.
*
* @return an ImageData
containing the image's data and attributes
*
* @exception SWTException
* IMPORTANT: This method is not part of the public
* API for Image
. 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.
*
SWT.BITMAP
or SWT.ICON
)
* @param handle the OS handle for the image
* @param data the OS data for the image
*
* @private
*/
public static Image carbon_new(Device device, int type, int handle, int data) {
Image image = new Image(device);
image.type = type;
image.handle = handle;
image.data = data;
return image;
}
/**
* Returns an integer hash code for the receiver. Any two
* objects that return true
when passed to
* equals
must return the same value for this
* method.
*
* @return the receiver's hash
*
* @see #equals
*/
public int hashCode () {
return handle;
}
void init(int width, int height) {
if (width <= 0 || height <= 0) {
SWT.error (SWT.ERROR_INVALID_ARGUMENT);
}
this.type = SWT.BITMAP;
/* Create the image */
int bpr = width * 4;
int dataSize = height * bpr;
data = OS.NewPtr(dataSize);
if (data == 0) SWT.error(SWT.ERROR_NO_HANDLES);
int provider = OS.CGDataProviderCreateWithData(0, data, dataSize, device.releaseProc);
if (provider == 0) {
OS.DisposePtr(data);
SWT.error(SWT.ERROR_NO_HANDLES);
}
int colorspace = device.colorspace;
handle = OS.CGImageCreate(width, height, 8, 32, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst, provider, null, true, 0);
OS.CGDataProviderRelease(provider);
if (handle == 0) {
OS.DisposePtr(data);
SWT.error(SWT.ERROR_NO_HANDLES);
}
/* Fill the image with white */
int bpc = OS.CGImageGetBitsPerComponent(handle);
int context = OS.CGBitmapContextCreate(this.data, width, height, bpc, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst);
if (context == 0) {
OS.CGImageRelease(handle);
OS.DisposePtr(data);
SWT.error(SWT.ERROR_NO_HANDLES);
}
CGRect rect = new CGRect();
rect.width = width; rect.height = height;
OS.CGContextSetRGBFillColor(context, 1, 1, 1, 1);
OS.CGContextFillRect(context, rect);
OS.CGContextRelease(context);
}
void init(ImageData image) {
if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
int width = image.width;
int height = image.height;
PaletteData palette = image.palette;
if (!(((image.depth == 1 || image.depth == 2 || image.depth == 4 || image.depth == 8) && !palette.isDirect) ||
((image.depth == 8) || (image.depth == 16 || image.depth == 24 || image.depth == 32) && palette.isDirect)))
SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
/* Create the image */
int dataSize = width * height * 4;
data = OS.NewPtr(dataSize);
if (data == 0) SWT.error(SWT.ERROR_NO_HANDLES);
int provider = OS.CGDataProviderCreateWithData(0, data, dataSize, device.releaseProc);
if (provider == 0) {
OS.DisposePtr(data);
SWT.error(SWT.ERROR_NO_HANDLES);
}
int colorspace = device.colorspace;
int transparency = image.getTransparencyType();
int alphaInfo = transparency == SWT.TRANSPARENCY_NONE && image.alpha == -1 ? OS.kCGImageAlphaNoneSkipFirst : OS.kCGImageAlphaFirst;
handle = OS.CGImageCreate(width, height, 8, 32, width * 4, colorspace, alphaInfo, provider, null, true, 0);
OS.CGDataProviderRelease(provider);
if (handle == 0) {
OS.DisposePtr(data);
SWT.error(SWT.ERROR_NO_HANDLES);
}
/* Initialize data */
int bpr = width * 4;
byte[] buffer = new byte[dataSize];
if (palette.isDirect) {
ImageData.blit(ImageData.BLIT_SRC,
image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, palette.redMask, palette.greenMask, palette.blueMask,
ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
buffer, 32, bpr, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
false, false);
} else {
RGB[] rgbs = palette.getRGBs();
int length = rgbs.length;
byte[] srcReds = new byte[length];
byte[] srcGreens = new byte[length];
byte[] srcBlues = new byte[length];
for (int i = 0; i < rgbs.length; i++) {
RGB rgb = rgbs[i];
if (rgb == null) continue;
srcReds[i] = (byte)rgb.red;
srcGreens[i] = (byte)rgb.green;
srcBlues[i] = (byte)rgb.blue;
}
ImageData.blit(ImageData.BLIT_SRC,
image.data, image.depth, image.bytesPerLine, image.getByteOrder(), 0, 0, width, height, srcReds, srcGreens, srcBlues,
ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
buffer, 32, bpr, ImageData.MSB_FIRST, 0, 0, width, height, 0xFF0000, 0xFF00, 0xFF,
false, false);
}
/* Initialize transparency */
if (transparency == SWT.TRANSPARENCY_MASK || image.transparentPixel != -1) {
this.type = image.transparentPixel != -1 ? SWT.BITMAP : SWT.ICON;
if (image.transparentPixel != -1) {
int transRed = 0, transGreen = 0, transBlue = 0;
if (palette.isDirect) {
RGB rgb = palette.getRGB(image.transparentPixel);
transRed = rgb.red;
transGreen = rgb.green;
transBlue = rgb.blue;
} else {
RGB[] rgbs = palette.getRGBs();
if (image.transparentPixel < rgbs.length) {
RGB rgb = rgbs[image.transparentPixel];
transRed = rgb.red;
transGreen = rgb.green;
transBlue = rgb.blue;
}
}
transparentPixel = transRed << 16 | transGreen << 8 | transBlue;
}
ImageData maskImage = image.getTransparencyMask();
byte[] maskData = maskImage.data;
int maskBpl = maskImage.bytesPerLine;
int offset = 0, maskOffset = 0;
for (int y = 0; yImage
. 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.
*
*
* @param data the platform specific GC data
* @return the platform specific GC handle
*/
public int internal_new_GC (GCData data) {
if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
if (type != SWT.BITMAP || memGC != null) {
SWT.error(SWT.ERROR_INVALID_ARGUMENT);
}
int width = OS.CGImageGetWidth(handle);
int height = OS.CGImageGetHeight(handle);
int bpc = OS.CGImageGetBitsPerComponent(handle);
int bpr = OS.CGImageGetBytesPerRow(handle);
int colorspace = OS.CGImageGetColorSpace(handle);
int context = OS.CGBitmapContextCreate(this.data, width, height, bpc, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst);
if (context == 0) SWT.error(SWT.ERROR_NO_HANDLES);
OS.CGContextScaleCTM(context, 1, -1);
OS.CGContextTranslateCTM(context, 0, -height);
if (data != null) {
int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
if ((data.style & mask) == 0) {
data.style |= SWT.LEFT_TO_RIGHT;
}
data.device = device;
data.background = device.COLOR_WHITE.handle;
data.foreground = device.COLOR_BLACK.handle;
data.font = device.systemFont;
data.image = this;
}
return context;
}
/**
* Invokes platform specific functionality to dispose a GC handle.
*
* IMPORTANT: This method is not part of the public
* API for Image
. 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.
*
true
if the image has been disposed,
* and false
otherwise.
*
* 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 true
when the image is disposed and false
otherwise
*/
public boolean isDisposed() {
return handle == 0;
}
/**
* Sets the color to which to map the transparent pixel.
*
* 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. This method specifies the color that will be used in
* these cases. For example:
*
* Button b = new Button(); * image.setBackground(b.getBackground()); * b.setImage(image); **
* 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. *
* This method has no effect if the receiver does not have a transparent * pixel value. *
* * @param color the color to use when a transparent pixel is specified * * @exception IllegalArgumentException