/* * @(#)ColorUtil.java * * Copyright (c) 2010 The authors and contributors of JHotDraw. * * You may not use, copy or modify this file, except in compliance with the * accompanying license terms. */ package org.jhotdraw.color; import java.awt.Color; import java.awt.color.ColorSpace; import java.awt.color.ICC_ColorSpace; import java.awt.color.ICC_Profile; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.text.ParseException; import org.jhotdraw.text.ColorToolTipTextFormatter; /** * A utility class for {@code Color} and {@code ColorSpace} objects. * * @author Werner Randelshofer * @version $Id$ */ public class ColorUtil { private static ColorToolTipTextFormatter formatter; private static final ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB); /** * Prevent instance creation. */ private ColorUtil() { } /** * Returns the color components in the specified color space from a * {@code Color} object. */ public static float[] fromColor(ColorSpace colorSpace, Color c) { if (isEqual(c.getColorSpace(), colorSpace)) { float[] components = c.getComponents(null); return components; } else { return c.getComponents(colorSpace, null); } } /** * Returns a color object from color components in the specified color * space. */ public static Color toColor(ColorSpace colorSpace, float... components) { return new CompositeColor(colorSpace, components, 1f); } /** * Returns the color components in the specified color space from an rgb * value. */ public static float[] fromRGB(ColorSpace colorSpace, int rgb) { return fromRGB(colorSpace, (rgb >>> 16) & 0xff, (rgb >>> 8) & 0xff, rgb & 0xff); } /** * Returns the color components in the specified color space from RGB * values. */ public static float[] fromRGB(ColorSpace colorSpace, int r, int g, int b) { return colorSpace.fromRGB(new float[]{r / 255f, g / 255f, b / 255f}); } /** * Returns an rgb value from color components in the specified color space. */ public static int toRGB24(ColorSpace colorSpace, float... components) { return CStoRGB24(colorSpace, components, new float[3]); } public static int CStoRGB24(ColorSpace colorSpace, float[] components, float[] rgb) { CStoRGB(colorSpace, components, rgb); // If the color is not displayable in RGB, we return transparent black. if (rgb[0] < 0f || rgb[1] < 0f || rgb[2] < 0f || rgb[0] > 1f || rgb[1] > 1f || rgb[2] > 1f) { return 0; } return 0xff000000 | ((int) (rgb[0] * 255f) << 16) | ((int) (rgb[1] * 255f) << 8) | (int) (rgb[2] * 255f); } /** * Returns a tool tip text for the specified color with information in the * color space of the color. */ public static String toToolTipText(Color c) { if (formatter == null) { formatter = new ColorToolTipTextFormatter(); } try { return formatter.valueToString(c); } catch (ParseException ex) { InternalError error = new InternalError("Unable to generate tool tip text from color " + c); error.initCause(ex); throw error; } } /** * Returns true, if the two color spaces are equal. */ public static boolean isEqual(ColorSpace a, ColorSpace b) { if ((a instanceof ICC_ColorSpace) && (b instanceof ICC_ColorSpace)) { ICC_ColorSpace aicc = (ICC_ColorSpace) a; ICC_ColorSpace bicc = (ICC_ColorSpace) b; ICC_Profile ap = aicc.getProfile(); ICC_Profile bp = bicc.getProfile(); return ap.equals(bp); } else { return a.equals(b); } } /** * Returns the name of the color space. If the color space is an * {@code ICC_ColorSpace} the name is retrieved from the "desc" data element * of the color profile. * * @param a A ColorSpace. * @return The name. */ public static String getName(ColorSpace a) { if (a instanceof NamedColorSpace) { return ((NamedColorSpace) a).getName(); } if ((a instanceof ICC_ColorSpace)) { ICC_ColorSpace icc = (ICC_ColorSpace) a; ICC_Profile p = icc.getProfile(); // Get the name from the profile description tag byte[] desc = p.getData(0x64657363); if (desc != null) { DataInputStream in = new DataInputStream(new ByteArrayInputStream(desc)); try { int magic = in.readInt(); int reserved = in.readInt(); if (magic != 0x64657363) { throw new IOException("Illegal magic:" + Integer.toHexString(magic)); } if (reserved != 0x0) { throw new IOException("Illegal reserved:" + Integer.toHexString(reserved)); } long nameLength = in.readInt() & 0xffffffffL; StringBuilder buf = new StringBuilder(); for (int i = 0; i < nameLength - 1; i++) { buf.append((char) in.readUnsignedByte()); } return buf.toString(); } catch (IOException e) { // fall back e.printStackTrace(); } } } if (a instanceof ICC_ColorSpace) { // Fall back if no description is available StringBuilder buf = new StringBuilder(); for (int i = 0; i < a.getNumComponents(); i++) { if (buf.length() > 0) { buf.append("-"); } buf.append(a.getName(i)); } return buf.toString(); } else { return a.getClass().getSimpleName(); } } /** * Blackens the specified color by casting a black shadow of the specified * amount on the color. */ public static Color shadow(Color c, int amount) { return new Color( Math.max(0, c.getRed() - amount), Math.max(0, c.getGreen() - amount), Math.max(0, c.getBlue() - amount), c.getAlpha()); } /** * Faster toRGB method which uses the provided output array. */ public static void CStoRGB(ColorSpace cs, float[] colorvalue, float[] rgb) { if (cs.isCS_sRGB()) { System.arraycopy(colorvalue,0,rgb,0,3); } else if (cs instanceof NamedColorSpace) { CStoRGB((NamedColorSpace) cs, colorvalue, rgb); } else { float[] tmp = cs.toRGB(colorvalue); System.arraycopy(tmp, 0, rgb, 0, tmp.length); } } /** * Faster fromRGB method which uses the provided output array. */ public static float[] CSfromRGB(ColorSpace cs, float[] rgb, float[] colorvalue) { if (cs instanceof NamedColorSpace) { CSfromRGB((NamedColorSpace) cs, rgb, colorvalue); } else { float[] tmp = cs.fromRGB(rgb); System.arraycopy(tmp, 0, colorvalue, 0, tmp.length); } return colorvalue; } /** * Faster toCIEXYZ method which uses the provided output array. */ public static float[] CStoCIEXYZ(ColorSpace cs, float[] colorvalue, float[] xyz) { if (cs instanceof NamedColorSpace) { CStoCIEXYZ((NamedColorSpace) cs, colorvalue, xyz); } else { float[] tmp = cs.toCIEXYZ(colorvalue); System.arraycopy(tmp, 0, xyz, 0, tmp.length); } return xyz; } /** * Faster fromCIEXYZ method which uses the provided output array. */ public static float[] CSfromCIEXYZ(ColorSpace cs, float[] xyz, float[] colorvalue) { if (cs instanceof NamedColorSpace) { CSfromCIEXYZ((NamedColorSpace) cs, xyz, colorvalue); } else { float[] tmp = cs.toRGB(xyz); System.arraycopy(tmp, 0, colorvalue, 0, tmp.length); } return colorvalue; } /** * Faster toRGB method which uses the provided output array. */ public static float[] CStoRGB(NamedColorSpace cs, float[] colorvalue, float[] rgb) { cs.toRGB(colorvalue, rgb); return rgb; } /** * Faster CIEXYZtoRGB method which uses the provided output array. */ public static float[] CIEXYZtoRGB(float[] xyz, float[] rgb) { float[] tmp = sRGB.fromCIEXYZ(xyz); System.arraycopy(tmp, 0, rgb, 0, 3); return rgb; } /** * Faster RGBtoCIEXYZ method which uses the provided output array. */ public static float[] RGBtoCIEXYZ(float[] rgb, float[] xyz) { float[] tmp = sRGB.toCIEXYZ(rgb); System.arraycopy(tmp, 0, xyz, 0, 3); return xyz; } /** * Faster fromRGB method which uses the provided output array. */ public static void CSfromRGB(NamedColorSpace cs, float[] rgb, float[] colorvalue) { cs.fromRGB(rgb, colorvalue); } /** * Faster toCIEXYZ method which uses the provided output array. */ public static void CStoCIEXYZ(NamedColorSpace cs, float[] colorvalue, float[] xyz) { cs.toCIEXYZ(colorvalue, xyz); } /** * Faster fromCIEXYZ method which uses the provided output array. */ public static void CSfromCIEXYZ(NamedColorSpace cs, float[] xyz, float[] colorvalue) { cs.fromCIEXYZ(xyz, xyz); } }