X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fjalview%2Futil%2FColorUtils.java;h=d465632b6c6cbee44102bc5a6699617c935ce113;hb=f6d94f44ef8adcc960ac0cf419928bdf2198fcc0;hp=1ab63617525d849daa255101c9bba52968db4080;hpb=b2f9a8d7bce642ff4011bc6d49e02bb0569fbb11;p=jalview.git diff --git a/src/jalview/util/ColorUtils.java b/src/jalview/util/ColorUtils.java index 1ab6361..d465632 100644 --- a/src/jalview/util/ColorUtils.java +++ b/src/jalview/util/ColorUtils.java @@ -1,19 +1,21 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.1) - * Copyright (C) 2014 The Jalview Authors + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License along with Jalview. If not, see . + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ /** @@ -23,10 +25,21 @@ package jalview.util; import java.awt.Color; +import java.util.HashMap; +import java.util.Map; import java.util.Random; +/** + * A class with utility methods for manipulating AWT colours/colors + */ public class ColorUtils { + private static final int MAX_CACHE_SIZE = 1729; + + /* + * a cache for colours generated from text strings + */ + static Map myColours = new HashMap<>(); /** * Generates a random color, will mix with input color. Code taken from @@ -57,4 +70,298 @@ public class ColorUtils } + /** + * Convert to Tk colour code format + * + * @param colour + * @return + * @see http + * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/colortool.html# + * tkcode + */ + public static final String toTkCode(Color colour) + { + String colstring = "#" + ((colour.getRed() < 16) ? "0" : "") + + Integer.toHexString(colour.getRed()) + + ((colour.getGreen() < 16) ? "0" : "") + + Integer.toHexString(colour.getGreen()) + + ((colour.getBlue() < 16) ? "0" : "") + + Integer.toHexString(colour.getBlue()); + return colstring; + } + + /** + * Returns a colour three shades darker. Note you can't guarantee that + * brighterThan reverses this, as darkerThan may result in black. + * + * @param col + * @return + */ + public static Color darkerThan(Color col) + { + return col == null ? null : col.darker().darker().darker(); + } + + /** + * Returns a colour three shades brighter. Note you can't guarantee that + * darkerThan reverses this, as brighterThan may result in white. + * + * @param col + * @return + */ + public static Color brighterThan(Color col) + { + return col == null ? null : col.brighter().brighter().brighter(); + } + + /** + * Returns a color between minColour and maxColour; the RGB values are in + * proportion to where 'value' lies between minValue and maxValue + * + * @param value + * @param minValue + * @param minColour + * @param maxValue + * @param maxColour + * @return + */ + public static Color getGraduatedColour(float value, float minValue, + Color minColour, float maxValue, Color maxColour) + { + if (minValue == maxValue) + { + return minColour; + } + if (value < minValue) + { + value = minValue; + } + if (value > maxValue) + { + value = maxValue; + } + + /* + * prop = proportion of the way value is from minValue to maxValue + */ + float prop = (value - minValue) / (maxValue - minValue); + float r = minColour.getRed() + + prop * (maxColour.getRed() - minColour.getRed()); + float g = minColour.getGreen() + + prop * (maxColour.getGreen() - minColour.getGreen()); + float b = minColour.getBlue() + + prop * (maxColour.getBlue() - minColour.getBlue()); + return new Color(r / 255, g / 255, b / 255); + } + + /** + * 'Fades' the given colour towards white by the specified proportion. A + * factor of 1 or more results in White, a factor of 0 leaves the colour + * unchanged, and a factor between 0 and 1 results in a proportionate change + * of RGB values towards (255, 255, 255). + *

+ * A negative bleachFactor can be specified to darken the colour towards Black + * (0, 0, 0). + * + * @param colour + * @param bleachFactor + * @return + */ + public static Color bleachColour(Color colour, float bleachFactor) + { + if (bleachFactor >= 1f) + { + return Color.WHITE; + } + if (bleachFactor <= -1f) + { + return Color.BLACK; + } + if (bleachFactor == 0f) + { + return colour; + } + + int red = colour.getRed(); + int green = colour.getGreen(); + int blue = colour.getBlue(); + + if (bleachFactor > 0) + { + red += (255 - red) * bleachFactor; + green += (255 - green) * bleachFactor; + blue += (255 - blue) * bleachFactor; + return new Color(red, green, blue); + } + else + { + float factor = 1 + bleachFactor; + red *= factor; + green *= factor; + blue *= factor; + return new Color(red, green, blue); + } + } + + /** + * Parses a string into a Color, where the accepted formats are + *

    + *
  • an AWT colour name e.g. white
  • + *
  • a six digit rgb hex colour value (without prefix) e.g. ff0000
  • + *
  • a comma-separated rgb triple e.g. 100,50,150
  • + *
+ * + * @param colour + * @return the parsed colour, or null if parsing fails + */ + public static Color parseColourString(String colour) + { + if (colour == null) + { + return null; + } + colour = colour.trim(); + + Color col = null; + if (colour.length() == 6 && StringUtils.isHexString(colour)) + { + try + { + int value = Integer.parseInt(colour, 16); + col = new Color(value); + } catch (NumberFormatException ex) + { + } + } + + if (col == null) + { + col = ColorUtils.getColorFromName(colour); + } + + if (col == null) + { + try + { + String[] tokens = colour.split(","); + if (tokens.length == 3) + { + int r = Integer.parseInt(tokens[0].trim()); + int g = Integer.parseInt(tokens[1].trim()); + int b = Integer.parseInt(tokens[2].trim()); + col = new Color(r, g, b); + } + } catch (IllegalArgumentException ex) + { + // non-numeric token or out of 0-255 range + } + } + + return col; + } + + /** + * Constructs a colour from a text string. The hashcode of the whole string is + * scaled to the range 0-135. This is added to RGB values made from the + * hashcode of each third of the string, and scaled to the range 20-229. + * + * @param name + * @return + */ + public static Color createColourFromName(String name) + { + if (name == null) + { + return Color.white; + } + if (myColours.containsKey(name)) + { + return myColours.get(name); + } + int lsize = name.length(); + int start = 0; + int end = lsize / 3; + + int rgbOffset = Math.abs(name.hashCode() % 10) * 15; // 0-135 + + /* + * red: first third + */ + int r = Math.abs(name.substring(start, end).hashCode() + rgbOffset) + % 210 + 20; + start = end; + end += lsize / 3; + if (end > lsize) + { + end = lsize; + } + + /* + * green: second third + */ + int g = Math.abs(name.substring(start, end).hashCode() + rgbOffset) + % 210 + 20; + + /* + * blue: third third + */ + int b = Math.abs(name.substring(end).hashCode() + rgbOffset) % 210 + 20; + + Color color = new Color(r, g, b); + + if (myColours.size() < MAX_CACHE_SIZE) + { + myColours.put(name, color); + } + + return color; + } + + /** + * Returns the Color constant for a given colour name e.g. "pink", or null if + * the name is not recognised. Currently recognises only AWT colour names, but + * could be extended to support others e.g. standard html colour names. + * + * @param name + * @return + */ + public static Color getColorFromName(String name) + { + if (name == null) + { + return null; + } + // or make a static map; or use reflection on the field name + switch (name.toLowerCase()) + { + case "black": + return Color.black; + case "blue": + return Color.blue; + case "cyan": + return Color.cyan; + case "darkgray": + return Color.darkGray; + case "gray": + return Color.gray; + case "green": + return Color.green; + case "lightgray": + return Color.lightGray; + case "magenta": + return Color.magenta; + case "orange": + return Color.orange; + case "pink": + return Color.pink; + case "red": + return Color.red; + case "white": + return Color.white; + case "yellow": + return Color.yellow; + default: + return null; + } + } }