/******************************************************************************* * Copyright (c) 2005 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.bpel.common.ui; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Device; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Display; /** * General color utilities. */ public final class ColorUtils { /** * Gets a different color shade by changing its brightness * with the provided variation. */ public static Color getShade(Color original, float brightnessVariation, Display display) { brightnessVariation = isInvertedColorScheme() ? -brightnessVariation : brightnessVariation; return new Color(display, getShadeRGB(original.getRGB(), brightnessVariation)); } /** * Gets a different color shade by changing its brightness * with the provided variation. */ public static RGB getShadeRGB(RGB original, float brightnessVariation) { // System.out.println("started " + original); brightnessVariation = isInvertedColorScheme() ? -brightnessVariation : brightnessVariation; float[] hsb = RGBtoHSB(original.red, original.green, original.blue, null); hsb[2] += brightnessVariation; int rgb = HSBtoRGB(hsb[0], hsb[1], hsb[2]); // System.out.println(new RGB(getRed(rgb), getGreen(rgb), getBlue(rgb))); return new RGB(getRed(rgb), getGreen(rgb), getBlue(rgb)); } /** * Returns an array of gradient colors from source to destination. * The source and destination colors are not included in the array. */ public static Color[] getColorShades(Color source, Color destination, int n, Display display) { float interval = getBrightnessInterval(source.getRGB(), destination.getRGB()); interval = interval / (n+2); Color[] result = new Color[n]; Color base = source; for (int i = 0; i < result.length; i++) { result[i] = getShade(base, interval, display); base = result[i]; } return result; } /** * Returns an array of gradient colors from source to destination. * The source and destination colors are not included in the array. */ public static float getBrightnessInterval(RGB source, RGB destination) { float[] sourceHSB = RGBtoHSB(source.red, source.green, source.blue, null); float[] destinationHSB = RGBtoHSB(destination.red, destination.green, destination.blue, null); return (destinationHSB[2] - sourceHSB[2]); } /** * Returns an array of gradient colors from source to middle and from middle to destination. * The middle color is included but the source and destination are not. */ public static Color[] getColorShades(Color source, Color middle, Color destination, int n, Display display) { Color[] result = new Color[n+1]; Color[] temp = getColorShades(source, middle, (n/2), display); System.arraycopy(temp, 0, result, 0, temp.length); int pos = temp.length; result[pos] = new Color(display, middle.getRGB()); temp = getColorShades(middle, destination, (n - temp.length), display); System.arraycopy(temp, 0, result, (pos+1), temp.length); return result; } /** * Takes the source color and calculates the brightness interval with each * color of the shades array. Then creates a new color array based on the * destination color and the brightness intervals. */ public static RGB[] getColorShades(RGB source, RGB[] shades, RGB destination) { RGB[] result = new RGB[shades.length]; for (int i = 0; i < shades.length; i++) { RGB shade = shades[i]; float interval = getBrightnessInterval(source, shade); result[i] = getShadeRGB(destination, interval); } return result; } /** * Converts the specified HSB values to a RBG value. * * @version initial * * @param hue the hue component * @param saturation the saturation component * @param brightness the brightness component * * @return an <code>int</code> which is the converted RGB value */ public static int HSBtoRGB(float hue, float saturation, float brightness) { float s = saturation; float v = brightness; int x = Math.round(v * 255); if (s == 0) { return 0xff000000 | (x << 16) | (x << 8) | x; } else { float h; if (hue == 1.0f) h = 0f; else h = (hue - (float)Math.floor(hue)) * 6.0f; int i = (int)Math.floor(h); float f = h - i; int p = Math.round(255 * (v * (1 - s))); int q = Math.round(255 * (v * (1 - (s * f)))); int t = Math.round(255 * (v * (1 - (s * (1 - f))))); switch(i){ case 0: return 0xff000000 | (x << 16) | (t << 8) | p; case 1: return 0xff000000 | (q << 16) | (x << 8) | p; case 2: return 0xff000000 | (p << 16) | (x << 8) | t; case 3: return 0xff000000 | (p << 16) | (q << 8) | x; case 4: return 0xff000000 | (t << 16) | (p << 8) | x; case 5: return 0xff000000 | (x << 16) | (p << 8) | q; default: return 0; } } } /** * Fill and return the specified array with the specified RGB values * converted to HSB. Create, fill and return a new array if <code>null</code> * is passed in. * <p> * Color components must be in the range (0 - 255). * * @version initial * * @param red the red component * @param green the green component * @param blue the blue component * @param hsb the return value or <code>null</code> * * @return an <code>float[]</code> containing the converted HSB values * * @throws IllegalArgumentException if any of the components are invalid */ public static float[] RGBtoHSB(int red, int green, int blue, float hsb[]) { if ((red < 0 || red > 255) || (green < 0 || green > 255) || (blue < 0 || blue > 255)) throw new IllegalArgumentException(); float r = red / 255f; float g = green / 255f; float b = blue / 255f; float h = 0; // hue float s; // saturation float v; // brightnees float max = Math.max(r, Math.max(g, b)); float min = Math.min(r, Math.min(g, b)); // Calculate brightness v = max; // Calculate saturation if (max != 0) s = (max - min)/max; else s = 0; // Calculate hue if (s != 0) { float delta = max - min; if (r == max) h = (g - b)/delta; else if (g == max) h = 2 + (b - r)/delta; else if (b == max) h = 4 + (r - g)/delta; h = h * 60f; if (h < 0) h = h + 360f; h /= 360f; } // Fill return value if (hsb == null) return new float[]{h, s, v}; else { hsb[0] = h; hsb[1] = s; hsb[2] = v; return hsb; } } /** * Answers the blue component of the receiver. * * @version initial * * @return an <code>int</code> which is the blue component of the receiver * in the range (0 - 255) * */ private static final int getBlue(int rgb) { return rgb & 0xff; } /** * Answers the green component of the receiver. * * @version initial * * @return an <code>int</code> which is the green component of the receiver * in the range (0 - 255) */ private static final int getGreen(int rgb) { return (rgb & 0xff00) >> 8; } /** * Answers the red component of the receiver. * * @version initial * * @return an <code>int</code> which is the red component of the receiver * in the range (0 - 255) */ private static final int getRed(int rgb) { return (rgb & 0xff0000) >> 16; } /** * Replaces the given color in the image data. */ public static void replaceColor(ImageData data, RGB from, RGB to) { for (int x = 0; x < data.width; x++) { for (int y = 0; y < data.height; y++) { int pixel = data.getPixel(x, y); RGB rgb = data.palette.getRGB(pixel); if (rgb.equals(from)) { pixel = data.palette.getPixel(to); } data.setPixel(x, y, pixel); } } } /** * scales the colors to be relative to the background and foreground colors (used to handle * high contrast mode) * **/ public static Color getRelativeColor(Device device, int r, int g, int b) { Color baseForeground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_FOREGROUND); Color baseBackground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND); int fr = baseForeground.getRed(); int fg = baseForeground.getGreen(); int fb = baseForeground.getBlue(); int br = baseBackground.getRed(); int bg = baseBackground.getGreen(); int bb = baseBackground.getBlue(); int nr = (int) (fr + ((float)r * (br-fr) / 255)); int ng = (int) (fg + ((float)g * (bg-fg) / 255)); int nb = (int) (fb + ((float)b * (bb-fb) / 255)); // safety check, make sure all colors are in the correct range (in case we change the calculation above nr = Math.max(0, nr); nr = Math.min(255, nr); ng = Math.max(0, ng); ng = Math.min(255, ng); nb = Math.max(0, nb); nb = Math.min(255, nb); return new Color(null, nr, ng, nb); } /** * Scales the colors to be relative to the background and foreground colors (used to handle * high contrast mode) */ public static RGB getRelativeRGB(int r, int g, int b) { Color baseForeground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_FOREGROUND); Color baseBackground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND); int fr = baseForeground.getRed(); int fg = baseForeground.getGreen(); int fb = baseForeground.getBlue(); int br = baseBackground.getRed(); int bg = baseBackground.getGreen(); int bb = baseBackground.getBlue(); int nr = (int) (fr + ((float)r * (br-fr) / 255)); int ng = (int) (fg + ((float)g * (bg-fg) / 255)); int nb = (int) (fb + ((float)b * (bb-fb) / 255)); // safety check, make sure all colors are in the correct range (in case we change the calculation above nr = Math.max(0, nr); nr = Math.min(255, nr); ng = Math.max(0, ng); ng = Math.min(255, ng); nb = Math.max(0, nb); nb = Math.min(255, nb); return new RGB(nr, ng, nb); } public static Color getRelativeColor(Color c) { Color cr = getRelativeColor(null, c.getRed(), c.getGreen(), c.getBlue()); c.dispose(); return cr; } public static Color getRelativeColorFromSystem(Color c) { return getRelativeColor(null, c.getRed(), c.getGreen(), c.getBlue()); } public static boolean isInvertedColorScheme() { Color baseForeground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_FOREGROUND); Color baseBackground = Display.getCurrent().getSystemColor(SWT.COLOR_LIST_BACKGROUND); // normally, the foreground color is dark, compare the sums to see which one is "lighter" if ((baseForeground.getRed() + baseForeground.getBlue() + baseForeground.getGreen()) > (baseBackground.getRed() + baseBackground.getBlue() + baseBackground.getGreen())) { return true; } return false; } public static RGB getLightShade(RGB rgb, int numerator, int denominator) { int light = 255 * numerator; int red = (rgb.red + light) / denominator; int green = (rgb.green + light) / denominator; int blue = (rgb.blue + light) / denominator; return new RGB(red, green, blue); } }