0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.swt.graphics;
0011:
0012: import org.eclipse.swt.internal.carbon.*;
0013: import org.eclipse.swt.*;
0014: import java.io.*;
0015:
0016: /**
0017: * Instances of this class are graphics which have been prepared
0018: * for display on a specific device. That is, they are ready
0019: * to paint using methods such as <code>GC.drawImage()</code>
0020: * and display on widgets with, for example, <code>Button.setImage()</code>.
0021: * <p>
0022: * If loaded from a file format that supports it, an
0023: * <code>Image</code> may have transparency, meaning that certain
0024: * pixels are specified as being transparent when drawn. Examples
0025: * of file formats that support transparency are GIF and PNG.
0026: * </p><p>
0027: * There are two primary ways to use <code>Images</code>.
0028: * The first is to load a graphic file from disk and create an
0029: * <code>Image</code> from it. This is done using an <code>Image</code>
0030: * constructor, for example:
0031: * <pre>
0032: * Image i = new Image(device, "C:\\graphic.bmp");
0033: * </pre>
0034: * A graphic file may contain a color table specifying which
0035: * colors the image was intended to possess. In the above example,
0036: * these colors will be mapped to the closest available color in
0037: * SWT. It is possible to get more control over the mapping of
0038: * colors as the image is being created, using code of the form:
0039: * <pre>
0040: * ImageData data = new ImageData("C:\\graphic.bmp");
0041: * RGB[] rgbs = data.getRGBs();
0042: * // At this point, rgbs contains specifications of all
0043: * // the colors contained within this image. You may
0044: * // allocate as many of these colors as you wish by
0045: * // using the Color constructor Color(RGB), then
0046: * // create the image:
0047: * Image i = new Image(device, data);
0048: * </pre>
0049: * <p>
0050: * Applications which require even greater control over the image
0051: * loading process should use the support provided in class
0052: * <code>ImageLoader</code>.
0053: * </p><p>
0054: * Application code must explicitly invoke the <code>Image.dispose()</code>
0055: * method to release the operating system resources managed by each instance
0056: * when those instances are no longer required.
0057: * </p>
0058: *
0059: * @see Color
0060: * @see ImageData
0061: * @see ImageLoader
0062: */
0063: public final class Image extends Resource implements Drawable {
0064:
0065: /**
0066: * specifies whether the receiver is a bitmap or an icon
0067: * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
0068: * <p>
0069: * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
0070: * public API. It is marked public only so that it can be shared
0071: * within the packages provided by SWT. It is not available on all
0072: * platforms and should never be accessed from application code.
0073: * </p>
0074: */
0075: public int type;
0076:
0077: /**
0078: * the handle to the OS image resource
0079: * (Warning: This field is platform dependent)
0080: * <p>
0081: * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
0082: * public API. It is marked public only so that it can be shared
0083: * within the packages provided by SWT. It is not available on all
0084: * platforms and should never be accessed from application code.
0085: * </p>
0086: */
0087: public int handle;
0088:
0089: /**
0090: * The data to the OS image resource.
0091: * (Warning: This field is platform dependent)
0092: * <p>
0093: * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
0094: * public API. It is marked public only so that it can be shared
0095: * within the packages provided by SWT. It is not available on all
0096: * platforms and should never be accessed from application code.
0097: * </p>
0098: */
0099: public int data;
0100:
0101: /**
0102: * specifies the transparent pixel
0103: */
0104: int transparentPixel = -1;
0105:
0106: /**
0107: * The GC the image is currently selected in.
0108: */
0109: GC memGC;
0110:
0111: /**
0112: * The alpha data of the image.
0113: */
0114: byte[] alphaData;
0115:
0116: /**
0117: * The global alpha value to be used for every pixel.
0118: */
0119: int alpha = -1;
0120:
0121: /**
0122: * The width of the image.
0123: */
0124: int width = -1;
0125:
0126: /**
0127: * The height of the image.
0128: */
0129: int height = -1;
0130:
0131: /**
0132: * Specifies the default scanline padding.
0133: */
0134: static final int DEFAULT_SCANLINE_PAD = 4;
0135:
0136: Image() {
0137: }
0138:
0139: /**
0140: * Constructs an empty instance of this class with the
0141: * specified width and height. The result may be drawn upon
0142: * by creating a GC and using any of its drawing operations,
0143: * as shown in the following example:
0144: * <pre>
0145: * Image i = new Image(device, width, height);
0146: * GC gc = new GC(i);
0147: * gc.drawRectangle(0, 0, 50, 50);
0148: * gc.dispose();
0149: * </pre>
0150: * <p>
0151: * Note: Some platforms may have a limitation on the size
0152: * of image that can be created (size depends on width, height,
0153: * and depth). For example, Windows 95, 98, and ME do not allow
0154: * images larger than 16M.
0155: * </p>
0156: *
0157: * @param device the device on which to create the image
0158: * @param width the width of the new image
0159: * @param height the height of the new image
0160: *
0161: * @exception IllegalArgumentException <ul>
0162: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0163: * <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
0164: * </ul>
0165: * @exception SWTError <ul>
0166: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0167: * </ul>
0168: */
0169: public Image(Device device, int width, int height) {
0170: if (device == null)
0171: device = Device.getDevice();
0172: if (device == null)
0173: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0174: init(device, width, height);
0175: }
0176:
0177: /**
0178: * Constructs a new instance of this class based on the
0179: * provided image, with an appearance that varies depending
0180: * on the value of the flag. The possible flag values are:
0181: * <dl>
0182: * <dt><b>IMAGE_COPY</b></dt>
0183: * <dd>the result is an identical copy of srcImage</dd>
0184: * <dt><b>IMAGE_DISABLE</b></dt>
0185: * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
0186: * <dt><b>IMAGE_GRAY</b></dt>
0187: * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
0188: * </dl>
0189: *
0190: * @param device the device on which to create the image
0191: * @param srcImage the image to use as the source
0192: * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
0193: *
0194: * @exception IllegalArgumentException <ul>
0195: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0196: * <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
0197: * <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>
0198: * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
0199: * </ul>
0200: * @exception SWTException <ul>
0201: * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
0202: * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
0203: * </ul>
0204: * @exception SWTError <ul>
0205: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0206: * </ul>
0207: */
0208: public Image(Device device, Image srcImage, int flag) {
0209: if (device == null)
0210: device = Device.getDevice();
0211: if (device == null)
0212: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0213: if (srcImage == null)
0214: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0215: if (srcImage.isDisposed())
0216: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
0217: switch (flag) {
0218: case SWT.IMAGE_COPY:
0219: case SWT.IMAGE_DISABLE:
0220: case SWT.IMAGE_GRAY:
0221: break;
0222: default:
0223: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
0224: }
0225: this .device = device;
0226: this .type = srcImage.type;
0227:
0228: /* Get source image size */
0229: int width = OS.CGImageGetWidth(srcImage.handle);
0230: int height = OS.CGImageGetHeight(srcImage.handle);
0231: int bpr = OS.CGImageGetBytesPerRow(srcImage.handle);
0232: int bpc = OS.CGImageGetBitsPerComponent(srcImage.handle);
0233: int bpp = OS.CGImageGetBitsPerPixel(srcImage.handle);
0234: int colorspace = OS.CGImageGetColorSpace(srcImage.handle);
0235: int alphaInfo = OS.kCGImageAlphaNoneSkipFirst;
0236:
0237: /* Copy transparent pixel and alpha data when necessary */
0238: alphaInfo = OS.CGImageGetAlphaInfo(srcImage.handle);
0239: transparentPixel = srcImage.transparentPixel;
0240: alpha = srcImage.alpha;
0241: if (srcImage.alphaData != null) {
0242: alphaData = new byte[srcImage.alphaData.length];
0243: System.arraycopy(srcImage.alphaData, 0, alphaData, 0,
0244: alphaData.length);
0245: }
0246:
0247: /* Create the image */
0248: int dataSize = height * bpr;
0249: data = OS.NewPtr(dataSize);
0250: if (data == 0)
0251: SWT.error(SWT.ERROR_NO_HANDLES);
0252: int provider = OS.CGDataProviderCreateWithData(0, data,
0253: dataSize, device.releaseProc);
0254: if (provider == 0) {
0255: OS.DisposePtr(data);
0256: SWT.error(SWT.ERROR_NO_HANDLES);
0257: }
0258: handle = OS.CGImageCreate(width, height, bpc, bpp, bpr,
0259: colorspace, alphaInfo, provider, null, true, 0);
0260: OS.CGDataProviderRelease(provider);
0261: if (handle == 0) {
0262: OS.DisposePtr(data);
0263: SWT.error(SWT.ERROR_NO_HANDLES);
0264: }
0265:
0266: OS.memmove(data, srcImage.data, dataSize);
0267: if (flag == SWT.IMAGE_COPY)
0268: return;
0269:
0270: /* Apply transformation */
0271: switch (flag) {
0272: case SWT.IMAGE_DISABLE: {
0273: Color zeroColor = device
0274: .getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW);
0275: RGB zeroRGB = zeroColor.getRGB();
0276: byte zeroRed = (byte) zeroRGB.red;
0277: byte zeroGreen = (byte) zeroRGB.green;
0278: byte zeroBlue = (byte) zeroRGB.blue;
0279: Color oneColor = device
0280: .getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
0281: RGB oneRGB = oneColor.getRGB();
0282: byte oneRed = (byte) oneRGB.red;
0283: byte oneGreen = (byte) oneRGB.green;
0284: byte oneBlue = (byte) oneRGB.blue;
0285: byte[] line = new byte[bpr];
0286: for (int y = 0; y < height; y++) {
0287: OS.memmove(line, data + (y * bpr), bpr);
0288: int offset = 0;
0289: for (int x = 0; x < width; x++) {
0290: int red = line[offset + 1] & 0xFF;
0291: int green = line[offset + 2] & 0xFF;
0292: int blue = line[offset + 3] & 0xFF;
0293: int intensity = red * red + green * green + blue
0294: * blue;
0295: if (intensity < 98304) {
0296: line[offset + 1] = zeroRed;
0297: line[offset + 2] = zeroGreen;
0298: line[offset + 3] = zeroBlue;
0299: } else {
0300: line[offset + 1] = oneRed;
0301: line[offset + 2] = oneGreen;
0302: line[offset + 3] = oneBlue;
0303: }
0304: offset += 4;
0305: }
0306: OS.memmove(data + (y * bpr), line, bpr);
0307: }
0308: break;
0309: }
0310: case SWT.IMAGE_GRAY: {
0311: byte[] line = new byte[bpr];
0312: for (int y = 0; y < height; y++) {
0313: OS.memmove(line, data + (y * bpr), bpr);
0314: int offset = 0;
0315: for (int x = 0; x < width; x++) {
0316: int red = line[offset + 1] & 0xFF;
0317: int green = line[offset + 2] & 0xFF;
0318: int blue = line[offset + 3] & 0xFF;
0319: byte intensity = (byte) ((red + red + green + green
0320: + green + green + green + blue) >> 3);
0321: line[offset + 1] = line[offset + 2] = line[offset + 3] = intensity;
0322: offset += 4;
0323: }
0324: OS.memmove(data + (y * bpr), line, bpr);
0325: }
0326: break;
0327: }
0328: }
0329: }
0330:
0331: /**
0332: * Constructs an empty instance of this class with the
0333: * width and height of the specified rectangle. The result
0334: * may be drawn upon by creating a GC and using any of its
0335: * drawing operations, as shown in the following example:
0336: * <pre>
0337: * Image i = new Image(device, boundsRectangle);
0338: * GC gc = new GC(i);
0339: * gc.drawRectangle(0, 0, 50, 50);
0340: * gc.dispose();
0341: * </pre>
0342: * <p>
0343: * Note: Some platforms may have a limitation on the size
0344: * of image that can be created (size depends on width, height,
0345: * and depth). For example, Windows 95, 98, and ME do not allow
0346: * images larger than 16M.
0347: * </p>
0348: *
0349: * @param device the device on which to create the image
0350: * @param bounds a rectangle specifying the image's width and height (must not be null)
0351: *
0352: * @exception IllegalArgumentException <ul>
0353: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0354: * <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
0355: * <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
0356: * </ul>
0357: * @exception SWTError <ul>
0358: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0359: * </ul>
0360: */
0361: public Image(Device device, Rectangle bounds) {
0362: if (device == null)
0363: device = Device.getDevice();
0364: if (device == null)
0365: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0366: if (bounds == null)
0367: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0368: init(device, bounds.width, bounds.height);
0369: }
0370:
0371: /**
0372: * Constructs an instance of this class from the given
0373: * <code>ImageData</code>.
0374: *
0375: * @param device the device on which to create the image
0376: * @param data the image data to create the image from (must not be null)
0377: *
0378: * @exception IllegalArgumentException <ul>
0379: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0380: * <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
0381: * </ul>
0382: * @exception SWTException <ul>
0383: * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
0384: * </ul>
0385: * @exception SWTError <ul>
0386: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0387: * </ul>
0388: */
0389: public Image(Device device, ImageData data) {
0390: if (device == null)
0391: device = Device.getDevice();
0392: if (device == null)
0393: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0394: init(device, data);
0395: }
0396:
0397: /**
0398: * Constructs an instance of this class, whose type is
0399: * <code>SWT.ICON</code>, from the two given <code>ImageData</code>
0400: * objects. The two images must be the same size. Pixel transparency
0401: * in either image will be ignored.
0402: * <p>
0403: * The mask image should contain white wherever the icon is to be visible,
0404: * and black wherever the icon is to be transparent. In addition,
0405: * the source image should contain black wherever the icon is to be
0406: * transparent.
0407: * </p>
0408: *
0409: * @param device the device on which to create the icon
0410: * @param source the color data for the icon
0411: * @param mask the mask data for the icon
0412: *
0413: * @exception IllegalArgumentException <ul>
0414: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0415: * <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li>
0416: * <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li>
0417: * </ul>
0418: * @exception SWTError <ul>
0419: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0420: * </ul>
0421: */
0422: public Image(Device device, ImageData source, ImageData mask) {
0423: if (device == null)
0424: device = Device.getDevice();
0425: if (source == null)
0426: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0427: if (mask == null)
0428: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0429: if (source.width != mask.width || source.height != mask.height) {
0430: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
0431: }
0432: mask = ImageData.convertMask(mask);
0433: ImageData image = new ImageData(source.width, source.height,
0434: source.depth, source.palette, source.scanlinePad,
0435: source.data);
0436: image.maskPad = mask.scanlinePad;
0437: image.maskData = mask.data;
0438: init(device, image);
0439: }
0440:
0441: /**
0442: * Constructs an instance of this class by loading its representation
0443: * from the specified input stream. Throws an error if an error
0444: * occurs while loading the image, or if the result is an image
0445: * of an unsupported type. Application code is still responsible
0446: * for closing the input stream.
0447: * <p>
0448: * This constructor is provided for convenience when loading a single
0449: * image only. If the stream contains multiple images, only the first
0450: * one will be loaded. To load multiple images, use
0451: * <code>ImageLoader.load()</code>.
0452: * </p><p>
0453: * This constructor may be used to load a resource as follows:
0454: * </p>
0455: * <pre>
0456: * static Image loadImage (Display display, Class clazz, String string) {
0457: * InputStream stream = clazz.getResourceAsStream (string);
0458: * if (stream == null) return null;
0459: * Image image = null;
0460: * try {
0461: * image = new Image (display, stream);
0462: * } catch (SWTException ex) {
0463: * } finally {
0464: * try {
0465: * stream.close ();
0466: * } catch (IOException ex) {}
0467: * }
0468: * return image;
0469: * }
0470: * </pre>
0471: *
0472: * @param device the device on which to create the image
0473: * @param stream the input stream to load the image from
0474: *
0475: * @exception IllegalArgumentException <ul>
0476: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0477: * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
0478: * </ul>
0479: * @exception SWTException <ul>
0480: * <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
0481: * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
0482: * <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
0483: * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
0484: * </ul>
0485: * @exception SWTError <ul>
0486: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0487: * </ul>
0488: */
0489: public Image(Device device, InputStream stream) {
0490: if (device == null)
0491: device = Device.getDevice();
0492: if (device == null)
0493: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0494: init(device, new ImageData(stream));
0495: }
0496:
0497: /**
0498: * Constructs an instance of this class by loading its representation
0499: * from the file with the specified name. Throws an error if an error
0500: * occurs while loading the image, or if the result is an image
0501: * of an unsupported type.
0502: * <p>
0503: * This constructor is provided for convenience when loading
0504: * a single image only. If the specified file contains
0505: * multiple images, only the first one will be used.
0506: *
0507: * @param device the device on which to create the image
0508: * @param filename the name of the file to load the image from
0509: *
0510: * @exception IllegalArgumentException <ul>
0511: * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
0512: * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
0513: * </ul>
0514: * @exception SWTException <ul>
0515: * <li>ERROR_IO - if an IO error occurs while reading from the file</li>
0516: * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
0517: * <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
0518: * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
0519: * </ul>
0520: * @exception SWTError <ul>
0521: * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
0522: * </ul>
0523: */
0524: public Image(Device device, String filename) {
0525: if (device == null)
0526: device = Device.getDevice();
0527: if (device == null)
0528: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0529: init(device, new ImageData(filename));
0530: }
0531:
0532: void createAlpha() {
0533: if (transparentPixel == -1 && alpha == -1 && alphaData == null)
0534: return;
0535: int height = OS.CGImageGetHeight(handle);
0536: int bpr = OS.CGImageGetBytesPerRow(handle);
0537: int dataSize = height * bpr;
0538: byte[] srcData = new byte[dataSize];
0539: OS.memmove(srcData, data, dataSize);
0540: if (transparentPixel != -1) {
0541: for (int i = 0; i < dataSize; i += 4) {
0542: int pixel = ((srcData[i + 1] & 0xFF) << 16)
0543: | ((srcData[i + 2] & 0xFF) << 8)
0544: | (srcData[i + 3] & 0xFF);
0545: srcData[i] = (byte) (pixel == transparentPixel ? 0
0546: : 0xFF);
0547: }
0548: } else if (alpha != -1) {
0549: byte a = (byte) this .alpha;
0550: for (int i = 0; i < dataSize; i += 4) {
0551: srcData[i] = a;
0552: }
0553: } else {
0554: int width = OS.CGImageGetWidth(handle);
0555: int offset = 0, alphaOffset = 0;
0556: for (int y = 0; y < height; y++) {
0557: for (int x = 0; x < width; x++) {
0558: srcData[offset] = alphaData[alphaOffset];
0559: offset += 4;
0560: alphaOffset += 1;
0561: }
0562: }
0563: }
0564: OS.memmove(data, srcData, dataSize);
0565: }
0566:
0567: /**
0568: * Disposes of the operating system resources associated with
0569: * the image. Applications must dispose of all images which
0570: * they allocate.
0571: */
0572: public void dispose() {
0573: if (handle == 0)
0574: return;
0575: if (device.isDisposed())
0576: return;
0577: if (memGC != null)
0578: memGC.dispose();
0579: OS.CGImageRelease(handle);
0580: device = null;
0581: data = handle = 0;
0582: memGC = null;
0583: }
0584:
0585: /**
0586: * Compares the argument to the receiver, and returns true
0587: * if they represent the <em>same</em> object using a class
0588: * specific comparison.
0589: *
0590: * @param object the object to compare with this object
0591: * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
0592: *
0593: * @see #hashCode
0594: */
0595: public boolean equals(Object object) {
0596: if (object == this )
0597: return true;
0598: if (!(object instanceof Image))
0599: return false;
0600: Image image = (Image) object;
0601: return device == image.device && handle == image.handle
0602: && transparentPixel == image.transparentPixel;
0603: }
0604:
0605: /**
0606: * Returns the color to which to map the transparent pixel, or null if
0607: * the receiver has no transparent pixel.
0608: * <p>
0609: * There are certain uses of Images that do not support transparency
0610: * (for example, setting an image into a button or label). In these cases,
0611: * it may be desired to simulate transparency by using the background
0612: * color of the widget to paint the transparent pixels of the image.
0613: * Use this method to check which color will be used in these cases
0614: * in place of transparency. This value may be set with setBackground().
0615: * <p>
0616: *
0617: * @return the background color of the image, or null if there is no transparency in the image
0618: *
0619: * @exception SWTException <ul>
0620: * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
0621: * </ul>
0622: */
0623: public Color getBackground() {
0624: if (isDisposed())
0625: SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
0626: if (transparentPixel == -1)
0627: return null;
0628: int red = (transparentPixel >> 16) & 0xFF;
0629: int green = (transparentPixel >> 8) & 0xFF;
0630: int blue = (transparentPixel >> 0) & 0xFF;
0631: return Color.carbon_new(device, new float[] { red / 255f,
0632: green / 255f, blue / 255f, 1 });
0633: }
0634:
0635: /**
0636: * Returns the bounds of the receiver. The rectangle will always
0637: * have x and y values of 0, and the width and height of the
0638: * image.
0639: *
0640: * @return a rectangle specifying the image's bounds
0641: *
0642: * @exception SWTException <ul>
0643: * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
0644: * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
0645: * </ul>
0646: */
0647: public Rectangle getBounds() {
0648: if (isDisposed())
0649: SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
0650: if (width != -1 && height != -1) {
0651: return new Rectangle(0, 0, width, height);
0652: }
0653: return new Rectangle(0, 0, width = OS.CGImageGetWidth(handle),
0654: height = OS.CGImageGetHeight(handle));
0655: }
0656:
0657: /**
0658: * Returns an <code>ImageData</code> based on the receiver
0659: * Modifications made to this <code>ImageData</code> will not
0660: * affect the Image.
0661: *
0662: * @return an <code>ImageData</code> containing the image's data and attributes
0663: *
0664: * @exception SWTException <ul>
0665: * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
0666: * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
0667: * </ul>
0668: *
0669: * @see ImageData
0670: */
0671: public ImageData getImageData() {
0672: if (isDisposed())
0673: SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
0674:
0675: int width = OS.CGImageGetWidth(handle);
0676: int height = OS.CGImageGetHeight(handle);
0677: int bpr = OS.CGImageGetBytesPerRow(handle);
0678: int bpp = OS.CGImageGetBitsPerPixel(handle);
0679: int dataSize = height * bpr;
0680: byte[] srcData = new byte[dataSize];
0681: OS.memmove(srcData, data, dataSize);
0682:
0683: PaletteData palette = new PaletteData(0xFF0000, 0xFF00, 0xFF);
0684: ImageData data = new ImageData(width, height, bpp, palette);
0685: data.data = srcData;
0686: data.bytesPerLine = bpr;
0687:
0688: data.transparentPixel = transparentPixel;
0689: if (transparentPixel == -1 && type == SWT.ICON) {
0690: /* Get the icon mask data */
0691: int maskPad = 2;
0692: int maskBpl = (((width + 7) / 8) + (maskPad - 1)) / maskPad
0693: * maskPad;
0694: byte[] maskData = new byte[height * maskBpl];
0695: int offset = 0, maskOffset = 0;
0696: for (int y = 0; y < height; y++) {
0697: for (int x = 0; x < width; x++) {
0698: if (srcData[offset] != 0) {
0699: maskData[maskOffset + (x >> 3)] |= (1 << (7 - (x & 0x7)));
0700: } else {
0701: maskData[maskOffset + (x >> 3)] &= ~(1 << (7 - (x & 0x7)));
0702: }
0703: offset += 4;
0704: }
0705: maskOffset += maskBpl;
0706: }
0707: data.maskData = maskData;
0708: data.maskPad = maskPad;
0709: }
0710: for (int i = 0; i < srcData.length; i += 4) {
0711: srcData[i] = 0;
0712: }
0713: data.alpha = alpha;
0714: if (alpha == -1 && alphaData != null) {
0715: data.alphaData = new byte[alphaData.length];
0716: System.arraycopy(alphaData, 0, data.alphaData, 0,
0717: alphaData.length);
0718: }
0719: return data;
0720: }
0721:
0722: /**
0723: * Invokes platform specific functionality to allocate a new image.
0724: * <p>
0725: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0726: * API for <code>Image</code>. It is marked public only so that it
0727: * can be shared within the packages provided by SWT. It is not
0728: * available on all platforms, and should never be called from
0729: * application code.
0730: * </p>
0731: *
0732: * @param device the device on which to allocate the color
0733: * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>)
0734: * @param handle the OS handle for the image
0735: * @param data the OS data for the image
0736: *
0737: * @private
0738: */
0739: public static Image carbon_new(Device device, int type, int handle,
0740: int data) {
0741: if (device == null)
0742: device = Device.getDevice();
0743: Image image = new Image();
0744: image.type = type;
0745: image.handle = handle;
0746: image.data = data;
0747: image.device = device;
0748: return image;
0749: }
0750:
0751: /**
0752: * Returns an integer hash code for the receiver. Any two
0753: * objects that return <code>true</code> when passed to
0754: * <code>equals</code> must return the same value for this
0755: * method.
0756: *
0757: * @return the receiver's hash
0758: *
0759: * @see #equals
0760: */
0761: public int hashCode() {
0762: return handle;
0763: }
0764:
0765: void init(Device device, int width, int height) {
0766: if (width <= 0 || height <= 0) {
0767: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
0768: }
0769: this .device = device;
0770: this .type = SWT.BITMAP;
0771:
0772: /* Create the image */
0773: int bpr = width * 4;
0774: int dataSize = height * bpr;
0775: data = OS.NewPtr(dataSize);
0776: if (data == 0)
0777: SWT.error(SWT.ERROR_NO_HANDLES);
0778: int provider = OS.CGDataProviderCreateWithData(0, data,
0779: dataSize, device.releaseProc);
0780: if (provider == 0) {
0781: OS.DisposePtr(data);
0782: SWT.error(SWT.ERROR_NO_HANDLES);
0783: }
0784: int colorspace = device.colorspace;
0785: handle = OS.CGImageCreate(width, height, 8, 32, bpr,
0786: colorspace, OS.kCGImageAlphaNoneSkipFirst, provider,
0787: null, true, 0);
0788: OS.CGDataProviderRelease(provider);
0789: if (handle == 0) {
0790: OS.DisposePtr(data);
0791: SWT.error(SWT.ERROR_NO_HANDLES);
0792: }
0793:
0794: /* Fill the image with white */
0795: int bpc = OS.CGImageGetBitsPerComponent(handle);
0796: int context = OS.CGBitmapContextCreate(this .data, width,
0797: height, bpc, bpr, colorspace,
0798: OS.kCGImageAlphaNoneSkipFirst);
0799: if (context == 0) {
0800: OS.CGImageRelease(handle);
0801: OS.DisposePtr(data);
0802: SWT.error(SWT.ERROR_NO_HANDLES);
0803: }
0804: CGRect rect = new CGRect();
0805: rect.width = width;
0806: rect.height = height;
0807: OS.CGContextSetRGBFillColor(context, 1, 1, 1, 1);
0808: OS.CGContextFillRect(context, rect);
0809: OS.CGContextRelease(context);
0810: }
0811:
0812: void init(Device device, ImageData image) {
0813: if (image == null)
0814: SWT.error(SWT.ERROR_NULL_ARGUMENT);
0815: this .device = device;
0816: int width = image.width;
0817: int height = image.height;
0818: PaletteData palette = image.palette;
0819: if (!(((image.depth == 1 || image.depth == 2
0820: || image.depth == 4 || image.depth == 8) && !palette.isDirect) || ((image.depth == 8) || (image.depth == 16
0821: || image.depth == 24 || image.depth == 32)
0822: && palette.isDirect)))
0823: SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
0824:
0825: /* Create the image */
0826: int dataSize = width * height * 4;
0827: data = OS.NewPtr(dataSize);
0828: if (data == 0)
0829: SWT.error(SWT.ERROR_NO_HANDLES);
0830: int provider = OS.CGDataProviderCreateWithData(0, data,
0831: dataSize, device.releaseProc);
0832: if (provider == 0) {
0833: OS.DisposePtr(data);
0834: SWT.error(SWT.ERROR_NO_HANDLES);
0835: }
0836: int colorspace = device.colorspace;
0837: int transparency = image.getTransparencyType();
0838: int alphaInfo = transparency == SWT.TRANSPARENCY_NONE
0839: && image.alpha == -1 ? OS.kCGImageAlphaNoneSkipFirst
0840: : OS.kCGImageAlphaFirst;
0841: handle = OS.CGImageCreate(width, height, 8, 32, width * 4,
0842: colorspace, alphaInfo, provider, null, true, 0);
0843: OS.CGDataProviderRelease(provider);
0844: if (handle == 0) {
0845: OS.DisposePtr(data);
0846: SWT.error(SWT.ERROR_NO_HANDLES);
0847: }
0848:
0849: /* Initialize data */
0850: int bpr = width * 4;
0851: byte[] buffer = new byte[dataSize];
0852: if (palette.isDirect) {
0853: ImageData
0854: .blit(ImageData.BLIT_SRC, image.data, image.depth,
0855: image.bytesPerLine, image.getByteOrder(),
0856: 0, 0, width, height, palette.redMask,
0857: palette.greenMask, palette.blueMask,
0858: ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
0859: buffer, 32, bpr, ImageData.MSB_FIRST, 0, 0,
0860: width, height, 0xFF0000, 0xFF00, 0xFF,
0861: false, false);
0862: } else {
0863: RGB[] rgbs = palette.getRGBs();
0864: int length = rgbs.length;
0865: byte[] srcReds = new byte[length];
0866: byte[] srcGreens = new byte[length];
0867: byte[] srcBlues = new byte[length];
0868: for (int i = 0; i < rgbs.length; i++) {
0869: RGB rgb = rgbs[i];
0870: if (rgb == null)
0871: continue;
0872: srcReds[i] = (byte) rgb.red;
0873: srcGreens[i] = (byte) rgb.green;
0874: srcBlues[i] = (byte) rgb.blue;
0875: }
0876: ImageData.blit(ImageData.BLIT_SRC, image.data, image.depth,
0877: image.bytesPerLine, image.getByteOrder(), 0, 0,
0878: width, height, srcReds, srcGreens, srcBlues,
0879: ImageData.ALPHA_OPAQUE, null, 0, 0, 0, buffer, 32,
0880: bpr, ImageData.MSB_FIRST, 0, 0, width, height,
0881: 0xFF0000, 0xFF00, 0xFF, false, false);
0882: }
0883:
0884: /* Initialize transparency */
0885: if (transparency == SWT.TRANSPARENCY_MASK
0886: || image.transparentPixel != -1) {
0887: this .type = image.transparentPixel != -1 ? SWT.BITMAP
0888: : SWT.ICON;
0889: if (image.transparentPixel != -1) {
0890: int transRed = 0, transGreen = 0, transBlue = 0;
0891: if (palette.isDirect) {
0892: RGB rgb = palette.getRGB(image.transparentPixel);
0893: transRed = rgb.red;
0894: transGreen = rgb.green;
0895: transBlue = rgb.blue;
0896: } else {
0897: RGB[] rgbs = palette.getRGBs();
0898: if (image.transparentPixel < rgbs.length) {
0899: RGB rgb = rgbs[image.transparentPixel];
0900: transRed = rgb.red;
0901: transGreen = rgb.green;
0902: transBlue = rgb.blue;
0903: }
0904: }
0905: transparentPixel = transRed << 16 | transGreen << 8
0906: | transBlue;
0907: }
0908: ImageData maskImage = image.getTransparencyMask();
0909: byte[] maskData = maskImage.data;
0910: int maskBpl = maskImage.bytesPerLine;
0911: int offset = 0, maskOffset = 0;
0912: for (int y = 0; y < height; y++) {
0913: for (int x = 0; x < width; x++) {
0914: buffer[offset] = ((maskData[maskOffset + (x >> 3)]) & (1 << (7 - (x & 0x7)))) != 0 ? (byte) 0xff
0915: : 0;
0916: offset += 4;
0917: }
0918: maskOffset += maskBpl;
0919: }
0920: } else {
0921: this .type = SWT.BITMAP;
0922: if (image.alpha != -1) {
0923: this .alpha = image.alpha;
0924: byte a = (byte) this .alpha;
0925: for (int dataIndex = 0; dataIndex < buffer.length; dataIndex += 4) {
0926: buffer[dataIndex] = a;
0927: }
0928: } else if (image.alphaData != null) {
0929: this .alphaData = new byte[image.alphaData.length];
0930: System.arraycopy(image.alphaData, 0, this .alphaData, 0,
0931: alphaData.length);
0932: int offset = 0, alphaOffset = 0;
0933: for (int y = 0; y < height; y++) {
0934: for (int x = 0; x < width; x++) {
0935: buffer[offset] = alphaData[alphaOffset];
0936: offset += 4;
0937: alphaOffset += 1;
0938: }
0939: }
0940: }
0941: }
0942:
0943: OS.memmove(data, buffer, dataSize);
0944: }
0945:
0946: /**
0947: * Invokes platform specific functionality to allocate a new GC handle.
0948: * <p>
0949: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0950: * API for <code>Image</code>. It is marked public only so that it
0951: * can be shared within the packages provided by SWT. It is not
0952: * available on all platforms, and should never be called from
0953: * application code.
0954: * </p>
0955: *
0956: * @param data the platform specific GC data
0957: * @return the platform specific GC handle
0958: */
0959: public int internal_new_GC(GCData data) {
0960: if (handle == 0)
0961: SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
0962: if (type != SWT.BITMAP || memGC != null) {
0963: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
0964: }
0965: int width = OS.CGImageGetWidth(handle);
0966: int height = OS.CGImageGetHeight(handle);
0967: int bpc = OS.CGImageGetBitsPerComponent(handle);
0968: int bpr = OS.CGImageGetBytesPerRow(handle);
0969: int colorspace = OS.CGImageGetColorSpace(handle);
0970: int context = OS.CGBitmapContextCreate(this .data, width,
0971: height, bpc, bpr, colorspace,
0972: OS.kCGImageAlphaNoneSkipFirst);
0973: if (context == 0)
0974: SWT.error(SWT.ERROR_NO_HANDLES);
0975: OS.CGContextScaleCTM(context, 1, -1);
0976: OS.CGContextTranslateCTM(context, 0, -height);
0977: if (data != null) {
0978: int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
0979: if ((data.style & mask) == 0) {
0980: data.style |= SWT.LEFT_TO_RIGHT;
0981: }
0982: data.device = device;
0983: data.background = device.COLOR_WHITE.handle;
0984: data.foreground = device.COLOR_BLACK.handle;
0985: data.font = device.systemFont;
0986: data.image = this ;
0987: }
0988: return context;
0989: }
0990:
0991: /**
0992: * Invokes platform specific functionality to dispose a GC handle.
0993: * <p>
0994: * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
0995: * API for <code>Image</code>. It is marked public only so that it
0996: * can be shared within the packages provided by SWT. It is not
0997: * available on all platforms, and should never be called from
0998: * application code.
0999: * </p>
1000: *
1001: * @param hDC the platform specific GC handle
1002: * @param data the platform specific GC data
1003: */
1004: public void internal_dispose_GC(int context, GCData data) {
1005: OS.CGContextRelease(context);
1006: }
1007:
1008: /**
1009: * Returns <code>true</code> if the image has been disposed,
1010: * and <code>false</code> otherwise.
1011: * <p>
1012: * This method gets the dispose state for the image.
1013: * When an image has been disposed, it is an error to
1014: * invoke any other method using the image.
1015: *
1016: * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
1017: */
1018: public boolean isDisposed() {
1019: return handle == 0;
1020: }
1021:
1022: /**
1023: * Sets the color to which to map the transparent pixel.
1024: * <p>
1025: * There are certain uses of <code>Images</code> that do not support
1026: * transparency (for example, setting an image into a button or label).
1027: * In these cases, it may be desired to simulate transparency by using
1028: * the background color of the widget to paint the transparent pixels
1029: * of the image. This method specifies the color that will be used in
1030: * these cases. For example:
1031: * <pre>
1032: * Button b = new Button();
1033: * image.setBackground(b.getBackground());
1034: * b.setImage(image);
1035: * </pre>
1036: * </p><p>
1037: * The image may be modified by this operation (in effect, the
1038: * transparent regions may be filled with the supplied color). Hence
1039: * this operation is not reversible and it is not legal to call
1040: * this function twice or with a null argument.
1041: * </p><p>
1042: * This method has no effect if the receiver does not have a transparent
1043: * pixel value.
1044: * </p>
1045: *
1046: * @param color the color to use when a transparent pixel is specified
1047: *
1048: * @exception IllegalArgumentException <ul>
1049: * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
1050: * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
1051: * </ul>
1052: * @exception SWTException <ul>
1053: * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1054: * </ul>
1055: */
1056: public void setBackground(Color color) {
1057: if (isDisposed())
1058: SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1059: if (color == null)
1060: SWT.error(SWT.ERROR_NULL_ARGUMENT);
1061: if (color.isDisposed())
1062: SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1063: if (transparentPixel == -1)
1064: return;
1065: byte red = (byte) ((transparentPixel >> 16) & 0xFF);
1066: byte green = (byte) ((transparentPixel >> 8) & 0xFF);
1067: byte blue = (byte) ((transparentPixel >> 0) & 0xFF);
1068: byte newRed = (byte) ((int) (color.handle[0] * 255) & 0xFF);
1069: byte newGreen = (byte) ((int) (color.handle[1] * 255) & 0xFF);
1070: byte newBlue = (byte) ((int) (color.handle[2] * 255) & 0xFF);
1071: int height = OS.CGImageGetHeight(handle);
1072: int bpl = OS.CGImageGetBytesPerRow(handle);
1073: byte[] line = new byte[bpl];
1074: for (int i = 0, offset = 0; i < height; i++, offset += bpl) {
1075: OS.memmove(line, data + offset, bpl);
1076: for (int j = 0; j < line.length; j += 4) {
1077: if (line[j + 1] == red && line[j + 2] == green
1078: && line[j + 3] == blue) {
1079: line[j + 1] = newRed;
1080: line[j + 2] = newGreen;
1081: line[j + 3] = newBlue;
1082: }
1083: }
1084: OS.memmove(data + offset, line, bpl);
1085: }
1086: transparentPixel = (newRed & 0xFF) << 16
1087: | (newGreen & 0xFF) << 8 | (newBlue & 0xFF);
1088: }
1089:
1090: /**
1091: * Returns a string containing a concise, human-readable
1092: * description of the receiver.
1093: *
1094: * @return a string representation of the receiver
1095: */
1096: public String toString() {
1097: if (isDisposed())
1098: return "Image {*DISPOSED*}";
1099: return "Image {" + handle + "}";
1100: }
1101:
1102: }
|