001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jface.resource;
011:
012: import org.eclipse.swt.graphics.ImageData;
013: import org.eclipse.swt.graphics.PaletteData;
014: import org.eclipse.swt.graphics.Point;
015: import org.eclipse.swt.graphics.RGB;
016:
017: /**
018: * Abstract base class for image descriptors that synthesize an image from other
019: * images in order to simulate the effect of custom drawing. For example, this
020: * could be used to superimpose a red bar dexter symbol across an image to
021: * indicate that something was disallowed.
022: * <p>
023: * Subclasses must implement the <code>getSize</code> and <code>fill</code>
024: * methods. Little or no work happens until the image descriptor's image is
025: * actually requested by a call to <code>createImage</code> (or to
026: * <code>getImageData</code> directly).
027: * </p>
028: */
029: public abstract class CompositeImageDescriptor extends ImageDescriptor {
030:
031: /**
032: * The image data for this composite image.
033: */
034: private ImageData imageData;
035:
036: /**
037: * Constructs an uninitialized composite image.
038: */
039: protected CompositeImageDescriptor() {
040: }
041:
042: /**
043: * Draw the composite images.
044: * <p>
045: * Subclasses must implement this framework method to paint images within
046: * the given bounds using one or more calls to the <code>drawImage</code>
047: * framework method.
048: * </p>
049: *
050: * @param width
051: * the width
052: * @param height
053: * the height
054: */
055: protected abstract void drawCompositeImage(int width, int height);
056:
057: /**
058: * Draws the given source image data into this composite image at the given
059: * position.
060: * <p>
061: * Call this internal framework method to superimpose another image atop
062: * this composite image.
063: * </p>
064: *
065: * @param src
066: * the source image data
067: * @param ox
068: * the x position
069: * @param oy
070: * the y position
071: */
072: final protected void drawImage(ImageData src, int ox, int oy) {
073: ImageData dst = imageData;
074: PaletteData srcPalette = src.palette;
075: ImageData srcMask = null;
076: int alphaMask = 0, alphaShift = 0;
077: if (src.maskData != null) {
078: srcMask = src.getTransparencyMask();
079: if (src.depth == 32) {
080: alphaMask = ~(srcPalette.redMask | srcPalette.greenMask | srcPalette.blueMask);
081: while (alphaMask != 0
082: && ((alphaMask >>> alphaShift) & 1) == 0)
083: alphaShift++;
084: }
085: }
086: for (int srcY = 0, dstY = srcY + oy; srcY < src.height; srcY++, dstY++) {
087: for (int srcX = 0, dstX = srcX + ox; srcX < src.width; srcX++, dstX++) {
088: if (!(0 <= dstX && dstX < dst.width && 0 <= dstY && dstY < dst.height))
089: continue;
090: int srcPixel = src.getPixel(srcX, srcY);
091: int srcAlpha = 255;
092: if (src.maskData != null) {
093: if (src.depth == 32) {
094: srcAlpha = (srcPixel & alphaMask) >>> alphaShift;
095: if (srcAlpha == 0) {
096: srcAlpha = srcMask.getPixel(srcX, srcY) != 0 ? 255
097: : 0;
098: }
099: } else {
100: if (srcMask.getPixel(srcX, srcY) == 0)
101: srcAlpha = 0;
102: }
103: } else if (src.transparentPixel != -1) {
104: if (src.transparentPixel == srcPixel)
105: srcAlpha = 0;
106: } else if (src.alpha != -1) {
107: srcAlpha = src.alpha;
108: } else if (src.alphaData != null) {
109: srcAlpha = src.getAlpha(srcX, srcY);
110: }
111: if (srcAlpha == 0)
112: continue;
113: int srcRed, srcGreen, srcBlue;
114: if (srcPalette.isDirect) {
115: srcRed = srcPixel & srcPalette.redMask;
116: srcRed = (srcPalette.redShift < 0) ? srcRed >>> -srcPalette.redShift
117: : srcRed << srcPalette.redShift;
118: srcGreen = srcPixel & srcPalette.greenMask;
119: srcGreen = (srcPalette.greenShift < 0) ? srcGreen >>> -srcPalette.greenShift
120: : srcGreen << srcPalette.greenShift;
121: srcBlue = srcPixel & srcPalette.blueMask;
122: srcBlue = (srcPalette.blueShift < 0) ? srcBlue >>> -srcPalette.blueShift
123: : srcBlue << srcPalette.blueShift;
124: } else {
125: RGB rgb = srcPalette.getRGB(srcPixel);
126: srcRed = rgb.red;
127: srcGreen = rgb.green;
128: srcBlue = rgb.blue;
129: }
130: int dstRed, dstGreen, dstBlue, dstAlpha;
131: if (srcAlpha == 255) {
132: dstRed = srcRed;
133: dstGreen = srcGreen;
134: dstBlue = srcBlue;
135: dstAlpha = srcAlpha;
136: } else {
137: int dstPixel = dst.getPixel(dstX, dstY);
138: dstAlpha = dst.getAlpha(dstX, dstY);
139: dstRed = (dstPixel & 0xFF) >>> 0;
140: dstGreen = (dstPixel & 0xFF00) >>> 8;
141: dstBlue = (dstPixel & 0xFF0000) >>> 16;
142: dstRed += (srcRed - dstRed) * srcAlpha / 255;
143: dstGreen += (srcGreen - dstGreen) * srcAlpha / 255;
144: dstBlue += (srcBlue - dstBlue) * srcAlpha / 255;
145: dstAlpha += (srcAlpha - dstAlpha) * srcAlpha / 255;
146: }
147: dst.setPixel(dstX, dstY, ((dstRed & 0xFF) << 0)
148: | ((dstGreen & 0xFF) << 8)
149: | ((dstBlue & 0xFF) << 16));
150: dst.setAlpha(dstX, dstY, dstAlpha);
151: }
152: }
153: }
154:
155: /*
156: * (non-Javadoc) Method declared on ImageDesciptor.
157: */
158: public ImageData getImageData() {
159: Point size = getSize();
160:
161: /* Create a 24 bit image data with alpha channel */
162: imageData = new ImageData(size.x, size.y, 24, new PaletteData(
163: 0xFF, 0xFF00, 0xFF0000));
164: imageData.alphaData = new byte[imageData.width
165: * imageData.height];
166:
167: drawCompositeImage(size.x, size.y);
168:
169: /* Detect minimum transparency */
170: boolean transparency = false;
171: byte[] alphaData = imageData.alphaData;
172: for (int i = 0; i < alphaData.length; i++) {
173: int alpha = alphaData[i] & 0xFF;
174: if (!(alpha == 0 || alpha == 255)) {
175: /* Full alpha channel transparency */
176: return imageData;
177: }
178: if (!transparency && alpha == 0)
179: transparency = true;
180: }
181: if (transparency) {
182: /* Reduce to 1-bit alpha channel transparency */
183: PaletteData palette = new PaletteData(new RGB[] {
184: new RGB(0, 0, 0), new RGB(255, 255, 255) });
185: ImageData mask = new ImageData(imageData.width,
186: imageData.height, 1, palette);
187: for (int y = 0; y < mask.height; y++) {
188: for (int x = 0; x < mask.width; x++) {
189: mask.setPixel(x, y,
190: imageData.getAlpha(x, y) == 255 ? 1 : 0);
191: }
192: }
193: } else {
194: /* no transparency */
195: imageData.alphaData = null;
196: }
197: return imageData;
198: }
199:
200: /**
201: * Return the transparent pixel for the receiver.
202: * <strong>NOTE</strong> This value is not currently in use in the
203: * default implementation.
204: * @return int
205: * @since 3.3
206: */
207: protected int getTransparentPixel() {
208: return 0;
209: }
210:
211: /**
212: * Return the size of this composite image.
213: * <p>
214: * Subclasses must implement this framework method.
215: * </p>
216: *
217: * @return the x and y size of the image expressed as a point object
218: */
219: protected abstract Point getSize();
220:
221: /**
222: * @param imageData The imageData to set.
223: * @since 3.3
224: */
225: protected void setImageData(ImageData imageData) {
226: this.imageData = imageData;
227: }
228: }
|