Clover icon

Coverage Report

  1. Project Clover database Mon Nov 18 2024 09:38:20 GMT
  2. Package jalview.util

File ColorUtils.java

 

Coverage histogram

../../img/srcFileCovDistChart6.png
27% of files have more coverage

Code metrics

46
130
10
1
396
232
48
0.37
13
10
4.8

Classes

Class Line # Actions
ColorUtils 33 130 48
0.5215053652.2%
 

Contributing tests

This file is covered by 119 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
7    * Jalview is free software: you can redistribute it and/or
8    * modify it under the terms of the GNU General Public License
9    * as published by the Free Software Foundation, either version 3
10    * of the License, or (at your option) any later version.
11    *
12    * Jalview is distributed in the hope that it will be useful, but
13    * WITHOUT ANY WARRANTY; without even the implied warranty
14    * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15    * PURPOSE. See the GNU General Public License for more details.
16    *
17    * You should have received a copy of the GNU General Public License
18    * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19    * The Jalview Authors are detailed in the 'AUTHORS' file.
20    */
21    /**
22    * author: Lauren Michelle Lui
23    */
24   
25    package jalview.util;
26   
27    import java.awt.Color;
28    import java.util.HashMap;
29    import java.util.Locale;
30    import java.util.Map;
31    import java.util.Random;
32   
 
33    public class ColorUtils
34    {
35    private static final int MAX_CACHE_SIZE = 1729;
36   
37    /*
38    * a cache for colours generated from text strings
39    */
40    static Map<String, Color> myColours = new HashMap<>();
41   
42    /**
43    * Generates a random color, will mix with input color. Code taken from
44    * http://stackoverflow
45    * .com/questions/43044/algorithm-to-randomly-generate-an-aesthetically
46    * -pleasing-color-palette
47    *
48    * @param mix
49    * @return Random color in RGB
50    */
 
51  0 toggle public static final Color generateRandomColor(Color mix)
52    {
53  0 Random random = new Random();
54  0 int red = random.nextInt(256);
55  0 int green = random.nextInt(256);
56  0 int blue = random.nextInt(256);
57   
58    // mix the color
59  0 if (mix != null)
60    {
61  0 red = (red + mix.getRed()) / 2;
62  0 green = (green + mix.getGreen()) / 2;
63  0 blue = (blue + mix.getBlue()) / 2;
64    }
65   
66  0 Color color = new Color(red, green, blue);
67  0 return color;
68   
69    }
70   
71    /**
72    *
73    * @return random color
74    */
 
75  0 toggle public static final Color getARandomColor()
76    {
77   
78  0 Color col = new Color((int) (Math.random() * 255),
79    (int) (Math.random() * 255), (int) (Math.random() * 255));
80  0 return col;
81    }
82   
83    /**
84    * Convert to Tk colour code format
85    *
86    * @param colour
87    * @return
88    * @see http
89    * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/colortool.html#
90    * tkcode
91    */
 
92  10 toggle public static final String toTkCode(Color colour)
93    {
94  10 String colstring = "#" + ((colour.getRed() < 16) ? "0" : "")
95    + Integer.toHexString(colour.getRed())
96  10 + ((colour.getGreen() < 16) ? "0" : "")
97    + Integer.toHexString(colour.getGreen())
98  10 + ((colour.getBlue() < 16) ? "0" : "")
99    + Integer.toHexString(colour.getBlue());
100  10 return colstring;
101    }
102   
103    /**
104    * Returns a colour three shades darker. Note you can't guarantee that
105    * brighterThan reverses this, as darkerThan may result in black.
106    *
107    * @param col
108    * @return
109    */
 
110  0 toggle public static Color darkerThan(Color col)
111    {
112  0 return col == null ? null : col.darker().darker().darker();
113    }
114   
115    /**
116    * Returns a colour three shades brighter. Note you can't guarantee that
117    * darkerThan reverses this, as brighterThan may result in white.
118    *
119    * @param col
120    * @return
121    */
 
122  0 toggle public static Color brighterThan(Color col)
123    {
124  0 return col == null ? null : col.brighter().brighter().brighter();
125    }
126   
127    /**
128    * Returns a color between minColour and maxColour; the RGB values are in
129    * proportion to where 'value' lies between minValue and maxValue
130    *
131    * @param value
132    * @param minValue
133    * @param minColour
134    * @param maxValue
135    * @param maxColour
136    * @return
137    */
 
138  0 toggle public static Color getGraduatedColour(float value, float minValue,
139    Color minColour, float maxValue, Color maxColour)
140    {
141  0 if (minValue == maxValue)
142    {
143  0 return minColour;
144    }
145  0 if (value < minValue)
146    {
147  0 value = minValue;
148    }
149  0 if (value > maxValue)
150    {
151  0 value = maxValue;
152    }
153   
154    /*
155    * prop = proportion of the way value is from minValue to maxValue
156    */
157  0 float prop = (value - minValue) / (maxValue - minValue);
158  0 float r = minColour.getRed()
159    + prop * (maxColour.getRed() - minColour.getRed());
160  0 float g = minColour.getGreen()
161    + prop * (maxColour.getGreen() - minColour.getGreen());
162  0 float b = minColour.getBlue()
163    + prop * (maxColour.getBlue() - minColour.getBlue());
164  0 return new Color(r / 255, g / 255, b / 255);
165    }
166   
167    /**
168    * 'Fades' the given colour towards white by the specified proportion. A
169    * factor of 1 or more results in White, a factor of 0 leaves the colour
170    * unchanged, and a factor between 0 and 1 results in a proportionate change
171    * of RGB values towards (255, 255, 255).
172    * <p>
173    * A negative bleachFactor can be specified to darken the colour towards Black
174    * (0, 0, 0).
175    *
176    * @param colour
177    * @param bleachFactor
178    * @return
179    */
 
180  88936 toggle public static Color bleachColour(Color colour, float bleachFactor)
181    {
182  88938 if (bleachFactor >= 1f)
183    {
184  221 return Color.WHITE;
185    }
186  88717 if (bleachFactor <= -1f)
187    {
188  0 return Color.BLACK;
189    }
190  88719 if (bleachFactor == 0f)
191    {
192  11983 return colour;
193    }
194   
195  76736 int red = colour.getRed();
196  76736 int green = colour.getGreen();
197  76736 int blue = colour.getBlue();
198   
199  76736 if (bleachFactor > 0)
200    {
201  76736 red += (255 - red) * bleachFactor;
202  76736 green += (255 - green) * bleachFactor;
203  76736 blue += (255 - blue) * bleachFactor;
204  76736 return new Color(red, green, blue);
205    }
206    else
207    {
208  0 float factor = 1 + bleachFactor;
209  0 red *= factor;
210  0 green *= factor;
211  0 blue *= factor;
212  0 return new Color(red, green, blue);
213    }
214    }
215   
216    /**
217    * Parses a string into a Color, where the accepted formats are
218    * <ul>
219    * <li>an AWT colour name e.g. white</li>
220    * <li>a hex colour value (without prefix) e.g. ff0000</li>
221    * <li>an rgb triple e.g. 100,50,150</li>
222    * </ul>
223    *
224    * @param colour
225    * @return the parsed colour, or null if parsing fails
226    */
 
227  51 toggle public static Color parseColourString(String colour)
228    {
229  51 if (colour == null)
230    {
231  4 return null;
232    }
233  47 colour = colour.trim();
234   
235  47 Color col = null;
236   
237  47 if ("random".equals(colour))
238    {
239  0 return generateRandomColor(null);
240    }
241   
242  47 try
243    {
244  47 int value = Integer.parseInt(colour, 16);
245  20 col = new Color(value);
246    } catch (NumberFormatException ex)
247    {
248    }
249   
250  47 if (col == null)
251    {
252  27 col = ColorUtils.getAWTColorFromName(colour);
253    }
254   
255  47 if (col == null)
256    {
257  7 try
258    {
259  7 String[] tokens = colour.split(",");
260  7 if (tokens.length == 3)
261    {
262  5 int r = Integer.parseInt(tokens[0].trim());
263  5 int g = Integer.parseInt(tokens[1].trim());
264  5 int b = Integer.parseInt(tokens[2].trim());
265  5 col = new Color(r, g, b);
266    }
267    } catch (IllegalArgumentException ex) // IllegalArgumentException includes
268    // NumberFormatException
269    {
270    // non-numeric token or out of 0-255 range
271    }
272    }
273   
274  47 return col;
275    }
276   
277    /**
278    * Constructs a colour from a text string. The hashcode of the whole string is
279    * scaled to the range 0-135. This is added to RGB values made from the
280    * hashcode of each third of the string, and scaled to the range 20-229.
281    *
282    * @param name
283    * @return
284    */
 
285  27 toggle public static Color createColourFromName(String name)
286    {
287  27 if (name == null)
288    {
289  0 return Color.white;
290    }
291  27 if (myColours.containsKey(name))
292    {
293  14 return myColours.get(name);
294    }
295  13 int lsize = name.length();
296  13 int start = 0;
297  13 int end = lsize / 3;
298   
299  13 int rgbOffset = Math.abs(name.hashCode() % 10) * 15; // 0-135
300   
301    /*
302    * red: first third
303    */
304  13 int r = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
305    % 210 + 20;
306  13 start = end;
307  13 end += lsize / 3;
308  13 if (end > lsize)
309    {
310  0 end = lsize;
311    }
312   
313    /*
314    * green: second third
315    */
316  13 int g = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
317    % 210 + 20;
318   
319    /*
320    * blue: third third
321    */
322  13 int b = Math.abs(name.substring(end).hashCode() + rgbOffset) % 210 + 20;
323   
324  13 Color color = new Color(r, g, b);
325   
326  13 if (myColours.size() < MAX_CACHE_SIZE)
327    {
328  13 myColours.put(name, color);
329    }
330   
331  13 return color;
332    }
333   
334    /**
335    * Returns the Color constant for a given colour name e.g. "pink", or null if
336    * the name is not recognised
337    *
338    * @param name
339    * @return
340    */
 
341  27 toggle public static Color getAWTColorFromName(String name)
342    {
343  27 if (name == null)
344    {
345  0 return null;
346    }
347  27 Color col = null;
348  27 name = name.toLowerCase(Locale.ROOT);
349   
350    // or make a static map; or use reflection on the field name
351  27 switch (name)
352    {
353  0 case "black":
354  0 col = Color.black;
355  0 break;
356  2 case "blue":
357  2 col = Color.blue;
358  2 break;
359  0 case "cyan":
360  0 col = Color.cyan;
361  0 break;
362  0 case "darkgray":
363  0 col = Color.darkGray;
364  0 break;
365  0 case "gray":
366  0 col = Color.gray;
367  0 break;
368  8 case "green":
369  8 col = Color.green;
370  8 break;
371  0 case "lightgray":
372  0 col = Color.lightGray;
373  0 break;
374  0 case "magenta":
375  0 col = Color.magenta;
376  0 break;
377  0 case "orange":
378  0 col = Color.orange;
379  0 break;
380  0 case "pink":
381  0 col = Color.pink;
382  0 break;
383  10 case "red":
384  10 col = Color.red;
385  10 break;
386  0 case "white":
387  0 col = Color.white;
388  0 break;
389  0 case "yellow":
390  0 col = Color.yellow;
391  0 break;
392    }
393   
394  27 return col;
395    }
396    }