/******************************************************************************* * 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.ui.internal.decorators; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.RGB; /** * DecorationImageBuilder is a utility class for merging images without data * loss. * * @since 3.3 * */ class DecorationImageBuilder { private static final int TOP_LEFT = LightweightDecoratorDefinition.TOP_LEFT; private static final int TOP_RIGHT = LightweightDecoratorDefinition.TOP_RIGHT; private static final int BOTTOM_LEFT = LightweightDecoratorDefinition.BOTTOM_LEFT; private static final int BOTTOM_RIGHT = LightweightDecoratorDefinition.BOTTOM_RIGHT; private static final int UNDERLAY = LightweightDecoratorDefinition.UNDERLAY; private static final PaletteData ALPHA_PALETTE, BW_PALETTE; static { RGB[] rgbs = new RGB[256]; for (int i = 0; i < rgbs.length; i++) { rgbs[i] = new RGB(i, i, i); } ALPHA_PALETTE = new PaletteData(rgbs); BW_PALETTE = new PaletteData(new RGB[] { new RGB(0, 0, 0), new RGB(255, 255, 255) }); } private static int getTransparencyDepth(ImageData data) { if (data.maskData != null && data.depth == 32) { for (int i = 0; i < data.data.length; i += 4) { if (data.data[i] != 0) return 8; } } if (data.maskData != null || data.transparentPixel != -1) return 1; if (data.alpha != -1 || data.alphaData != null) return 8; return 0; } private static ImageData getTransparency(ImageData data, int transparencyDepth) { if (data == null) return null; if (transparencyDepth == 1) return data.getTransparencyMask(); ImageData mask = null; if (data.maskData != null && data.depth == 32) { ImageData m = data.getTransparencyMask(); mask = new ImageData(data.width, data.height, 8, ALPHA_PALETTE, data.width, new byte[data.width * data.height]); for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int alpha = data.getPixel(x, y) & 0xFF; if (alpha == 0) { if (m.getPixel(x, y) != 0) alpha = 255; } mask.setPixel(x, y, alpha); } } } else if (data.maskData != null || data.transparentPixel != -1) { ImageData m = data.getTransparencyMask(); mask = new ImageData(data.width, data.height, 8, ALPHA_PALETTE, data.width, new byte[data.width * data.height]); for (int y = 0; y < mask.height; y++) { for (int x = 0; x < mask.width; x++) { mask.setPixel(x, y, m.getPixel(x, y) != 0 ? (byte) 255 : 0); } } } else if (data.alpha != -1) { mask = new ImageData(data.width, data.height, 8, ALPHA_PALETTE, data.width, new byte[data.width * data.height]); for (int i = 0; i < mask.data.length; i++) { mask.data[i] = (byte) data.alpha; } } else if (data.alphaData != null) { mask = new ImageData(data.width, data.height, 8, ALPHA_PALETTE, data.width, data.alphaData); } else { mask = new ImageData(data.width, data.height, 8, ALPHA_PALETTE, data.width, new byte[data.width * data.height]); for (int i = 0; i < mask.data.length; i++) { mask.data[i] = (byte) 255; } } return mask; } private static void composite(ImageData dst, ImageData src, int xOffset, int yOffset) { if (dst.depth == 1) { for (int y = 0, dstY = y + yOffset; y < src.height; y++, dstY++) { for (int x = 0, dstX = x + xOffset; x < src.width; x++, dstX++) { if (0 <= dstX && dstX < dst.width && 0 <= dstY && dstY < dst.height) { if (src.getPixel(x, y) != 0) { dst.setPixel(dstX, dstY, 1); } } } } } else if (dst.depth == 8) { for (int y = 0, dstY = y + yOffset; y < src.height; y++, dstY++) { for (int x = 0, dstX = x + xOffset; x < src.width; x++, dstX++) { if (0 <= dstX && dstX < dst.width && 0 <= dstY && dstY < dst.height) { int srcAlpha = src.getPixel(x, y); int dstAlpha = dst.getPixel(dstX, dstY); dstAlpha += (srcAlpha - dstAlpha) * srcAlpha / 255; dst.setPixel(dstX, dstY, dstAlpha); } } } } } /** * Create a composite image by underlaying and overlaying the base image. * @param device * @param base * @param overlay * @return Image */ static Image compositeImage(Device device, ImageData base, ImageData[] overlay) { if (base == null) return null; Image image = new Image(device, new ImageData(base.width, base.height, 24, new PaletteData(0xff, 0xff00, 0xff00000))); GC gc = new GC(image); ImageData src; int maskDepth = 0, baseMaskDepth = 0; ImageData underlay = src = overlay.length > UNDERLAY ? overlay[UNDERLAY] : null; if (src != null) { maskDepth = Math.max(maskDepth, getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, 0, 0); img.dispose(); } src = base; if (base != null) { maskDepth = Math.max(maskDepth, baseMaskDepth = getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, 0, 0); img.dispose(); } ImageData topLeft = src = overlay[TOP_LEFT]; if (src != null) { maskDepth = Math.max(maskDepth, getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, 0, 0); img.dispose(); } ImageData topRight = src = overlay[TOP_RIGHT]; if (src != null) { maskDepth = Math.max(maskDepth, getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, base.width - src.width, 0); img.dispose(); } ImageData bottomLeft = src = overlay[BOTTOM_LEFT]; if (src != null) { maskDepth = Math.max(maskDepth, getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, 0, base.height - src.height); img.dispose(); } ImageData bottomRight = src = overlay[BOTTOM_RIGHT]; if (src != null) { maskDepth = Math.max(maskDepth, getTransparencyDepth(src)); Image img = new Image(device, src); gc.drawImage(img, base.width - src.width, base.height - src.height); img.dispose(); } gc.dispose(); if (baseMaskDepth > 0) { ImageData newData = image.getImageData(); image.dispose(); ImageData mask = null; switch (maskDepth) { case 1: mask = new ImageData(base.width, base.height, maskDepth, BW_PALETTE); break; case 8: mask = new ImageData(base.width, base.height, maskDepth, ALPHA_PALETTE, base.width, new byte[base.width * base.height]); break; } src = getTransparency(underlay, maskDepth); if (src != null) composite(mask, src, 0, 0); src = getTransparency(base, maskDepth); if (src != null) composite(mask, src, 0, 0); src = getTransparency(topLeft, maskDepth); if (src != null) composite(mask, src, 0, 0); src = getTransparency(topRight, maskDepth); if (src != null) composite(mask, src, mask.width - src.width, 0); src = getTransparency(bottomLeft, maskDepth); if (src != null) composite(mask, src, 0, mask.height - src.height); src = getTransparency(bottomRight, maskDepth); if (src != null) composite(mask, src, mask.width - src.width, mask.height - src.height); switch (maskDepth) { case 1: newData.maskData = mask.data; newData.maskPad = mask.scanlinePad; break; case 8: newData.alphaData = mask.data; break; } image = new Image(device, newData); } return image; } }