This library's primary purpose is to be able to specify a color and end up with a fitting name for that color π
"#ffffff" -> White
"#facfea" -> Classic Rose
#abcdef -> Alphabet Blue
#123456 -> Incremental Blue
#c1b2a3 -> Balanced Beige
...and so on
Color Names is meant to act as an easy drop-in dependency you can import and start using, meaning it's already bundled with a list of color names, a list that is maintained by another awesome open-sourced project: meodai/color-names. There's around 16.7 million sRGB colors, obviously not all of these are named, but this list provides plenty to work with, we can just extrapolate the closest color from the list.
Color Names remain customisable for those who'd like the extra control: you can use the ColorNameBuilder (usage outlined below) to fully customize the color names used, enabling you to add your own colors and even bypass the default list entirely. Alternatively, you could fork this project yourself and replace/modify the list in src/main/resources/colornames.csv with whatever you'd like. If you'd like to make changes to the default list, consider reviewing the naming rules of the open sourced list mentioned above and contributing there.
The default colour list has over 30,000 names (that's a lot). Trying to find the closest color by comparing distance in the 3D color space can be pretty computationally expensive.
Other libraries with similar functionality seem to often approach this linearly by iterating over all the colors, plotting the sRGB values as 3D vectors, then calculating Euclidian distance between the query vector and each and every other vector. At the end, whatever has the lowest distance is the "closest" color. This has 2 notable concerns:
- The sRGB color space isn't all that accurate in terms of visual similarity, ie: 3 sRGB values that are equally apart in terms of raw numerical value are unlikely to be visually "different" by the same factor. Okay... so, how do we put a number on the visual similarity of colors? Fortunately, that's not my job. The CIELAB Color Space has us covered! CIELAB precisely revolves around positioning colors with uniform visual perception, it's typically used for color correction work, but is exactly what we need. Perfect, we convert and cache our values from the sRGB color space to the CIELAB color space, problem one solved!
- Iterating through >30,000 vectors in a 3D space and finding the distance between all of them to a point is... a lot of calculations. But it's exactly what we need, since that's how we find the Delta-E variance between all our CIELAB colous to figure out whats the "closest". So, we should really try to optimise this. For this we cache our colors in a K-D Tree with 3 dimensions, providing us with fast nearest neighbour searches. This takes the time complexity for searches from O(n) to O(logn). In practice, this makes a pretty substantial difference.
| 10 lookups - size of list: | Linear approach | K-D Tree approach | 30,000 colors - No. of lookups: | Linear approach | K-D Tree approach | |
|---|---|---|---|---|---|---|
| 1,000 | 0.027ms | 0.0088ms | 1 | 0.17ms | 0.009ms | |
| 10,000 | 0.23ms | 0.012ms | 10 | 1.05ms | 0.024ms | |
| 20,000 | 0.62ms | 0.018ms | 100 | 8.07ms | 0.12ms | |
| 30,000 (~ default list) | 1.05ms | 0.024ms | 1,000 | 78.42ms | 0.84ms | |
| 300,000 | 9.24ms | 0.067ms | 10,000 | 800.94ms | 5.59ms |
Note
All of these tests were conducted ~100 times and averaged. Tests were ran on an i9 13900k. Your results may vary, but relative performance should be a lot faster with the K-D Tree.
With typical use (lookups with the default list), you can expect a roughly 50x performance improvement. For me, this resulted in being able to confidently do these lookups syncronously in real time applications, which wasn't the case previously :3
While researching K-D trees, I put together some visuals to help me understand, and I figured why not make them pretty and provide it here. Hopfully these prove to be helpful for anyone interested in learning about K-D trees. There's plenty of other great resources out there (YouTube videos did it for me!).

Note
You can open that image in a new tab for a nicer, full-resolution view.
repositories {
maven("https://jitpack.io")
}
dependencies {
implementation("me.aroze:color-names:1.0.4")
}<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
<dependency>
<groupId>me.aroze</groupId>
<artifactId>color-names</artifactId>
<version>1.0.4</version>
</dependency>public ColorNames colorNames = ColorNames.create() // Easily create an instance with the default color listpublic ColorNames colorNames = new ColorNameBuilder() // Builder with extra customisability
.addColor("Peachy Pink", "#ffdbed") // Custom color!! There's also .addColors() and various overloads
.loadDefaults() // Loads the default list, can be skipped entirely if you'd like to
.build();val colorNames = ColorNames.create() // Easily create an instance with the default color listval colorNames = ColorNameBuilder() // Builder with extra customisability
.addColor("Peachy Pink", "#ffdbed") // Custom color!! There's also .addColors() and various overloads
.loadDefaults() // Loads the default list, can be skipped entirely if you'd like to
.build();String fromHex = colorNames.getName("#facfea"); // "Classic Rose"
String fromRGB = colorNames.getName(224, 224, 255); // "Stoic White"
String fromColor = colorNames.getName(new Color(255, 219, 240)); // "Silky Pink"// Kotlin
val fromHex = colorNames.getName("#facfea") // "Classic Rose"
val fromRGB = colorNames.getName(224, 224, 255) // "Stoic White"
val fromColor = colorNames.getName(Color(255, 219, 240)) // "Silky Pink"