20
20
import java .awt .color .ColorSpace ;
21
21
import java .util .Collections ;
22
22
import java .util .EnumMap ;
23
+ import java .util .LinkedHashMap ;
23
24
import java .util .Map ;
24
- import java .util .Map .Entry ;
25
25
26
26
import org .springframework .util .Assert ;
27
27
36
36
*/
37
37
public final class AnsiColors {
38
38
39
- private static final Map <AnsiColor , LabColor > ANSI_COLOR_MAP ;
39
+ private static final Map <AnsiElement , LabColor > ANSI_COLOR_MAP ;
40
40
41
41
static {
42
42
Map <AnsiColor , LabColor > colorMap = new EnumMap <>(AnsiColor .class );
@@ -59,24 +59,86 @@ public final class AnsiColors {
59
59
ANSI_COLOR_MAP = Collections .unmodifiableMap (colorMap );
60
60
}
61
61
62
- private AnsiColors () {
62
+ private static final int [] ANSI_8BIT_COLOR_CODE_LOOKUP = new int [] { 0x000000 , 0x800000 , 0x008000 , 0x808000 ,
63
+ 0x000080 , 0x800080 , 0x008080 , 0xc0c0c0 , 0x808080 , 0xff0000 , 0x00ff00 , 0xffff00 , 0x0000ff , 0xff00ff ,
64
+ 0x00ffff , 0xffffff , 0x000000 , 0x00005f , 0x000087 , 0x0000af , 0x0000d7 , 0x0000ff , 0x005f00 , 0x005f5f ,
65
+ 0x005f87 , 0x005faf , 0x005fd7 , 0x005fff , 0x008700 , 0x00875f , 0x008787 , 0x0087af , 0x0087d7 , 0x0087ff ,
66
+ 0x00af00 , 0x00af5f , 0x00af87 , 0x00afaf , 0x00afd7 , 0x00afff , 0x00d700 , 0x00d75f , 0x00d787 , 0x00d7af ,
67
+ 0x00d7d7 , 0x00d7ff , 0x00ff00 , 0x00ff5f , 0x00ff87 , 0x00ffaf , 0x00ffd7 , 0x00ffff , 0x5f0000 , 0x5f005f ,
68
+ 0x5f0087 , 0x5f00af , 0x5f00d7 , 0x5f00ff , 0x5f5f00 , 0x5f5f5f , 0x5f5f87 , 0x5f5faf , 0x5f5fd7 , 0x5f5fff ,
69
+ 0x5f8700 , 0x5f875f , 0x5f8787 , 0x5f87af , 0x5f87d7 , 0x5f87ff , 0x5faf00 , 0x5faf5f , 0x5faf87 , 0x5fafaf ,
70
+ 0x5fafd7 , 0x5fafff , 0x5fd700 , 0x5fd75f , 0x5fd787 , 0x5fd7af , 0x5fd7d7 , 0x5fd7ff , 0x5fff00 , 0x5fff5f ,
71
+ 0x5fff87 , 0x5fffaf , 0x5fffd7 , 0x5fffff , 0x870000 , 0x87005f , 0x870087 , 0x8700af , 0x8700d7 , 0x8700ff ,
72
+ 0x875f00 , 0x875f5f , 0x875f87 , 0x875faf , 0x875fd7 , 0x875fff , 0x878700 , 0x87875f , 0x878787 , 0x8787af ,
73
+ 0x8787d7 , 0x8787ff , 0x87af00 , 0x87af5f , 0x87af87 , 0x87afaf , 0x87afd7 , 0x87afff , 0x87d700 , 0x87d75f ,
74
+ 0x87d787 , 0x87d7af , 0x87d7d7 , 0x87d7ff , 0x87ff00 , 0x87ff5f , 0x87ff87 , 0x87ffaf , 0x87ffd7 , 0x87ffff ,
75
+ 0xaf0000 , 0xaf005f , 0xaf0087 , 0xaf00af , 0xaf00d7 , 0xaf00ff , 0xaf5f00 , 0xaf5f5f , 0xaf5f87 , 0xaf5faf ,
76
+ 0xaf5fd7 , 0xaf5fff , 0xaf8700 , 0xaf875f , 0xaf8787 , 0xaf87af , 0xaf87d7 , 0xaf87ff , 0xafaf00 , 0xafaf5f ,
77
+ 0xafaf87 , 0xafafaf , 0xafafd7 , 0xafafff , 0xafd700 , 0xafd75f , 0xafd787 , 0xafd7af , 0xafd7d7 , 0xafd7ff ,
78
+ 0xafff00 , 0xafff5f , 0xafff87 , 0xafffaf , 0xafffd7 , 0xafffff , 0xd70000 , 0xd7005f , 0xd70087 , 0xd700af ,
79
+ 0xd700d7 , 0xd700ff , 0xd75f00 , 0xd75f5f , 0xd75f87 , 0xd75faf , 0xd75fd7 , 0xd75fff , 0xd78700 , 0xd7875f ,
80
+ 0xd78787 , 0xd787af , 0xd787d7 , 0xd787ff , 0xd7af00 , 0xd7af5f , 0xd7af87 , 0xd7afaf , 0xd7afd7 , 0xd7afff ,
81
+ 0xd7d700 , 0xd7d75f , 0xd7d787 , 0xd7d7af , 0xd7d7d7 , 0xd7d7ff , 0xd7ff00 , 0xd7ff5f , 0xd7ff87 , 0xd7ffaf ,
82
+ 0xd7ffd7 , 0xd7ffff , 0xff0000 , 0xff005f , 0xff0087 , 0xff00af , 0xff00d7 , 0xff00ff , 0xff5f00 , 0xff5f5f ,
83
+ 0xff5f87 , 0xff5faf , 0xff5fd7 , 0xff5fff , 0xff8700 , 0xff875f , 0xff8787 , 0xff87af , 0xff87d7 , 0xff87ff ,
84
+ 0xffaf00 , 0xffaf5f , 0xffaf87 , 0xffafaf , 0xffafd7 , 0xffafff , 0xffd700 , 0xffd75f , 0xffd787 , 0xffd7af ,
85
+ 0xffd7d7 , 0xffd7ff , 0xffff00 , 0xffff5f , 0xffff87 , 0xffffaf , 0xffffd7 , 0xffffff , 0x080808 , 0x121212 ,
86
+ 0x1c1c1c , 0x262626 , 0x303030 , 0x3a3a3a , 0x444444 , 0x4e4e4e , 0x585858 , 0x626262 , 0x6c6c6c , 0x767676 ,
87
+ 0x808080 , 0x8a8a8a , 0x949494 , 0x9e9e9e , 0xa8a8a8 , 0xb2b2b2 , 0xbcbcbc , 0xc6c6c6 , 0xd0d0d0 , 0xdadada ,
88
+ 0xe4e4e4 , 0xeeeeee };
89
+
90
+ private final Map <AnsiElement , LabColor > lookup ;
91
+
92
+ /**
93
+ * Create a new {@link AnsiColors} instance with the specified bit depth.
94
+ * @param bitDepth the required bit depth
95
+ */
96
+ public AnsiColors (BitDepth bitDepth ) {
97
+ this .lookup = getLookup (bitDepth );
63
98
}
64
99
65
- public static AnsiColor getClosest (Color color ) {
66
- return getClosest (new LabColor (color ));
100
+ private Map <AnsiElement , LabColor > getLookup (BitDepth bitDepth ) {
101
+ if (bitDepth == BitDepth .EIGHT ) {
102
+ Map <Ansi8BitColor , LabColor > lookup = new LinkedHashMap <>();
103
+ for (int i = 0 ; i < ANSI_8BIT_COLOR_CODE_LOOKUP .length ; i ++) {
104
+ lookup .put (Ansi8BitColor .foreground (i ), new LabColor (ANSI_8BIT_COLOR_CODE_LOOKUP [i ]));
105
+ }
106
+ return Collections .unmodifiableMap (lookup );
107
+ }
108
+ return ANSI_COLOR_MAP ;
109
+ }
110
+
111
+ /**
112
+ * Find the closest {@link AnsiElement ANSI color} to the given AWT {@link Color}.
113
+ * @param color the AWT color
114
+ * @return the closest ANSI color
115
+ */
116
+ public AnsiElement findClosest (Color color ) {
117
+ return findClosest (new LabColor (color ));
67
118
}
68
119
69
- private static AnsiColor getClosest (LabColor color ) {
70
- AnsiColor result = null ;
71
- double resultDistance = Float .MAX_VALUE ;
72
- for (Entry <AnsiColor , LabColor > entry : ANSI_COLOR_MAP .entrySet ()) {
73
- double distance = color .getDistance (entry .getValue ());
74
- if (result == null || distance < resultDistance ) {
75
- resultDistance = distance ;
76
- result = entry .getKey ();
120
+ private AnsiElement findClosest (LabColor color ) {
121
+ AnsiElement closest = null ;
122
+ double closestDistance = Float .MAX_VALUE ;
123
+ for (Map . Entry <AnsiElement , LabColor > entry : this . lookup .entrySet ()) {
124
+ double candidateDistance = color .getDistance (entry .getValue ());
125
+ if (closest == null || candidateDistance < closestDistance ) {
126
+ closestDistance = candidateDistance ;
127
+ closest = entry .getKey ();
77
128
}
78
129
}
79
- return result ;
130
+ return closest ;
131
+ }
132
+
133
+ /**
134
+ * Get the closest {@link AnsiColor ANSI color} to the given AWT {@link Color}.
135
+ * @param color the color to find
136
+ * @return the closest color
137
+ * @deprecated since 2.2.0 in favor of {@link #findClosest(Color)}
138
+ */
139
+ @ Deprecated
140
+ public static AnsiColor getClosest (Color color ) {
141
+ return (AnsiColor ) new AnsiColors (BitDepth .FOUR ).findClosest (color );
80
142
}
81
143
82
144
/**
@@ -132,4 +194,38 @@ private double f(double t) {
132
194
133
195
}
134
196
197
+ /**
198
+ * Bit depths supported by this class.
199
+ */
200
+ public enum BitDepth {
201
+
202
+ /**
203
+ * 4 bits (16 color).
204
+ * @see AnsiColor
205
+ */
206
+ FOUR (4 ),
207
+
208
+ /**
209
+ * 8 bits (256 color).
210
+ * @see Ansi8BitColor
211
+ */
212
+ EIGHT (8 );
213
+
214
+ private final int bits ;
215
+
216
+ BitDepth (int bits ) {
217
+ this .bits = bits ;
218
+ }
219
+
220
+ public static BitDepth of (int bits ) {
221
+ for (BitDepth candidate : values ()) {
222
+ if (candidate .bits == bits ) {
223
+ return candidate ;
224
+ }
225
+ }
226
+ throw new IllegalArgumentException ("Unsupported ANSI bit depth '" + bits + "'" );
227
+ }
228
+
229
+ }
230
+
135
231
}
0 commit comments