Clover icon

Coverage Report

  1. Project Clover database Mon Sep 2 2024 17:57:51 BST
  2. Package jalview.util

File ColorUtils.java

 

Coverage histogram

../../img/srcFileCovDistChart9.png
13% 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.8870967688.7%
 

Contributing tests

This file is covered by 235 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  3 toggle public static final Color generateRandomColor(Color mix)
52    {
53  3 Random random = new Random();
54  3 int red = random.nextInt(256);
55  3 int green = random.nextInt(256);
56  3 int blue = random.nextInt(256);
57   
58    // mix the color
59  3 if (mix != null)
60    {
61  3 red = (red + mix.getRed()) / 2;
62  3 green = (green + mix.getGreen()) / 2;
63  3 blue = (blue + mix.getBlue()) / 2;
64    }
65   
66  3 Color color = new Color(red, green, blue);
67  3 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  15 toggle public static final String toTkCode(Color colour)
93    {
94  15 String colstring = "#" + ((colour.getRed() < 16) ? "0" : "")
95    + Integer.toHexString(colour.getRed())
96  15 + ((colour.getGreen() < 16) ? "0" : "")
97    + Integer.toHexString(colour.getGreen())
98  15 + ((colour.getBlue() < 16) ? "0" : "")
99    + Integer.toHexString(colour.getBlue());
100  15 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  4 toggle public static Color darkerThan(Color col)
111    {
112  4 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  4 toggle public static Color brighterThan(Color col)
123    {
124  4 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  138927 toggle public static Color getGraduatedColour(float value, float minValue,
139    Color minColour, float maxValue, Color maxColour)
140    {
141  138927 if (minValue == maxValue)
142    {
143  1 return minColour;
144    }
145  138926 if (value < minValue)
146    {
147  1 value = minValue;
148    }
149  138926 if (value > maxValue)
150    {
151  1214 value = maxValue;
152    }
153   
154    /*
155    * prop = proportion of the way value is from minValue to maxValue
156    */
157  138926 float prop = (value - minValue) / (maxValue - minValue);
158  138926 float r = minColour.getRed()
159    + prop * (maxColour.getRed() - minColour.getRed());
160  138926 float g = minColour.getGreen()
161    + prop * (maxColour.getGreen() - minColour.getGreen());
162  138926 float b = minColour.getBlue()
163    + prop * (maxColour.getBlue() - minColour.getBlue());
164  138926 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  1141042 toggle public static Color bleachColour(Color colour, float bleachFactor)
181    {
182  1141055 if (bleachFactor >= 1f)
183    {
184  1441 return Color.WHITE;
185    }
186  1139626 if (bleachFactor <= -1f)
187    {
188  2 return Color.BLACK;
189    }
190  1139628 if (bleachFactor == 0f)
191    {
192  565492 return colour;
193    }
194   
195  574136 int red = colour.getRed();
196  574136 int green = colour.getGreen();
197  574136 int blue = colour.getBlue();
198   
199  574136 if (bleachFactor > 0)
200    {
201  574134 red += (255 - red) * bleachFactor;
202  574134 green += (255 - green) * bleachFactor;
203  574134 blue += (255 - blue) * bleachFactor;
204  574134 return new Color(red, green, blue);
205    }
206    else
207    {
208  2 float factor = 1 + bleachFactor;
209  2 red *= factor;
210  2 green *= factor;
211  2 blue *= factor;
212  2 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  22466 toggle public static Color parseColourString(String colour)
228    {
229  22466 if (colour == null)
230    {
231  5 return null;
232    }
233  22461 colour = colour.trim();
234   
235  22461 Color col = null;
236   
237  22461 if ("random".equals(colour))
238    {
239  0 return generateRandomColor(null);
240    }
241   
242  22461 try
243    {
244  22461 int value = Integer.parseInt(colour, 16);
245  22340 col = new Color(value);
246    } catch (NumberFormatException ex)
247    {
248    }
249   
250  22461 if (col == null)
251    {
252  121 col = ColorUtils.getAWTColorFromName(colour);
253    }
254   
255  22461 if (col == null)
256    {
257  42 try
258    {
259  42 String[] tokens = colour.split(",");
260  42 if (tokens.length == 3)
261    {
262  16 int r = Integer.parseInt(tokens[0].trim());
263  16 int g = Integer.parseInt(tokens[1].trim());
264  16 int b = Integer.parseInt(tokens[2].trim());
265  16 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  22461 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  106 toggle public static Color createColourFromName(String name)
286    {
287  106 if (name == null)
288    {
289  1 return Color.white;
290    }
291  105 if (myColours.containsKey(name))
292    {
293  66 return myColours.get(name);
294    }
295  39 int lsize = name.length();
296  39 int start = 0;
297  39 int end = lsize / 3;
298   
299  39 int rgbOffset = Math.abs(name.hashCode() % 10) * 15; // 0-135
300   
301    /*
302    * red: first third
303    */
304  39 int r = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
305    % 210 + 20;
306  39 start = end;
307  39 end += lsize / 3;
308  39 if (end > lsize)
309    {
310  0 end = lsize;
311    }
312   
313    /*
314    * green: second third
315    */
316  39 int g = Math.abs(name.substring(start, end).hashCode() + rgbOffset)
317    % 210 + 20;
318   
319    /*
320    * blue: third third
321    */
322  39 int b = Math.abs(name.substring(end).hashCode() + rgbOffset) % 210 + 20;
323   
324  39 Color color = new Color(r, g, b);
325   
326  39 if (myColours.size() < MAX_CACHE_SIZE)
327    {
328  39 myColours.put(name, color);
329    }
330   
331  39 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  128 toggle public static Color getAWTColorFromName(String name)
342    {
343  128 if (name == null)
344    {
345  1 return null;
346    }
347  127 Color col = null;
348  127 name = name.toLowerCase(Locale.ROOT);
349   
350    // or make a static map; or use reflection on the field name
351  127 switch (name)
352    {
353  6 case "black":
354  6 col = Color.black;
355  6 break;
356  30 case "blue":
357  30 col = Color.blue;
358  30 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  11 case "green":
369  11 col = Color.green;
370  11 break;
371  1 case "lightgray":
372  1 col = Color.lightGray;
373  1 break;
374  0 case "magenta":
375  0 col = Color.magenta;
376  0 break;
377  1 case "orange":
378  1 col = Color.orange;
379  1 break;
380  2 case "pink":
381  2 col = Color.pink;
382  2 break;
383  26 case "red":
384  26 col = Color.red;
385  26 break;
386  5 case "white":
387  5 col = Color.white;
388  5 break;
389  1 case "yellow":
390  1 col = Color.yellow;
391  1 break;
392    }
393   
394  127 return col;
395    }
396    }