Colour names
The nearest of the 148 CSS colour names to any colour, names back to hex, and the full list: for labels, filters and alt text.
Version 1.0.0 · 4 functions · 0 crates
Functions
What use color_names.qwer gives a program, with the types Quillo sees. To take only some, or under other names: use color_name, color_name_nearest from color_names (Quillo 0.6).
color_name(color: str) → anyor an errorThe CSS colour name nearest to color ("#3b82f6", "#abc", "rgb(59, 130, 246)" or a name): { name, hex, distance, exact }. distance is how far apart they look (Oklab, 0 the same, under 0.02 hard to tell, over 0.1 clearly different); exact true when it is that colour.
color_name_nearest(color: str, count: int) → listor an errorThe count nearest names (1 to 20), nearest first, each { name, hex, distance }: to offer a choice, or a search by colour.
color_name_hex(name: str) → stror an errorA CSS colour name ("rebeccapurple", "Light Sea Green" with spaces and capitals too) as "#rrggbb"; an error for a name CSS does not have.
color_name_list() → listAll 148 CSS colour names with their hex, as { name, hex } in alphabetical order (gray and grey spellings both).
Get it
$ quillo install color_names # color_names.qwer into this folder$ quillo install color_names --example # and its example, color_names.qweOr with curl:
$ curl -O https://quillolang.org/plugins/files/color_names.qwer$ curl -O https://quillolang.org/plugins/files/color_names.qweThen, in your program, all of it or only what you call:
use color_names.qweruse color_name, color_name_nearest from color_names // Quillo 0.6: only theseIt uses these crates, which cargo fetches the first time the plugin is built:
Example
// A shop's colour filter: each product colour gets a name people can search for and screen readers can say.//// quillo run color_names.qwe then open http://localhost:8080/productsuse "color_names.qwer"let products = [{ name: "Mug", color: "#3b82f6" }, { name: "Scarf", color: "#b91c1c" }, { name: "Tote", color: "rgb(240, 230, 140)" }]route GET /products = products | map((p) => merge(p, { color_name: color_name(p.color)?.name }))route GET /name ? { c: str = "#663399" } = { nearest: color_name(c)?, others: color_name_nearest(c, 3)? | map((x) => x.name) }route GET /hex ? { name: str = "Light Sea Green" } = { name, hex: color_name_hex(name)?, names: len(color_name_list()) }$ quillo run color_names.qwe$ curl 'localhost:8080/name?c=%23663399'$ curl 'localhost:8080/hex'$ curl 'localhost:8080/products'Source
//! The nearest of the 148 CSS colour names to any colour ("#3b82f6" is dodgerblue), names back to hex, and the full list: for labels, filters and alt text.//! version: 1.0.0//!//! [dependencies]use serde_json::{json, Value};const NAMES: [(&str, u32); 148] = [ ("aliceblue", 0xf0f8ff), ("antiquewhite", 0xfaebd7), ("aqua", 0x00ffff), ("aquamarine", 0x7fffd4), ("azure", 0xf0ffff), ("beige", 0xf5f5dc), ("bisque", 0xffe4c4), ("black", 0x000000), ("blanchedalmond", 0xffebcd), ("blue", 0x0000ff), ("blueviolet", 0x8a2be2), ("brown", 0xa52a2a), ("burlywood", 0xdeb887), ("cadetblue", 0x5f9ea0), ("chartreuse", 0x7fff00), ("chocolate", 0xd2691e), ("coral", 0xff7f50), ("cornflowerblue", 0x6495ed), ("cornsilk", 0xfff8dc), ("crimson", 0xdc143c), ("cyan", 0x00ffff), ("darkblue", 0x00008b), ("darkcyan", 0x008b8b), ("darkgoldenrod", 0xb8860b), ("darkgray", 0xa9a9a9), ("darkgreen", 0x006400), ("darkgrey", 0xa9a9a9), ("darkkhaki", 0xbdb76b), ("darkmagenta", 0x8b008b), ("darkolivegreen", 0x556b2f), ("darkorange", 0xff8c00), ("darkorchid", 0x9932cc), ("darkred", 0x8b0000), ("darksalmon", 0xe9967a), ("darkseagreen", 0x8fbc8f), ("darkslateblue", 0x483d8b), ("darkslategray", 0x2f4f4f), ("darkslategrey", 0x2f4f4f), ("darkturquoise", 0x00ced1), ("darkviolet", 0x9400d3), ("deeppink", 0xff1493), ("deepskyblue", 0x00bfff), ("dimgray", 0x696969), ("dimgrey", 0x696969), ("dodgerblue", 0x1e90ff), ("firebrick", 0xb22222), ("floralwhite", 0xfffaf0), ("forestgreen", 0x228b22), ("fuchsia", 0xff00ff), ("gainsboro", 0xdcdcdc), ("ghostwhite", 0xf8f8ff), ("gold", 0xffd700), ("goldenrod", 0xdaa520), ("gray", 0x808080), ("green", 0x008000), ("greenyellow", 0xadff2f), ("grey", 0x808080), ("honeydew", 0xf0fff0), ("hotpink", 0xff69b4), ("indianred", 0xcd5c5c), ("indigo", 0x4b0082), ("ivory", 0xfffff0), ("khaki", 0xf0e68c), ("lavender", 0xe6e6fa), ("lavenderblush", 0xfff0f5), ("lawngreen", 0x7cfc00), ("lemonchiffon", 0xfffacd), ("lightblue", 0xadd8e6), ("lightcoral", 0xf08080), ("lightcyan", 0xe0ffff), ("lightgoldenrodyellow", 0xfafad2), ("lightgray", 0xd3d3d3), ("lightgreen", 0x90ee90), ("lightgrey", 0xd3d3d3), ("lightpink", 0xffb6c1), ("lightsalmon", 0xffa07a), ("lightseagreen", 0x20b2aa), ("lightskyblue", 0x87cefa), ("lightslategray", 0x778899), ("lightslategrey", 0x778899), ("lightsteelblue", 0xb0c4de), ("lightyellow", 0xffffe0), ("lime", 0x00ff00), ("limegreen", 0x32cd32), ("linen", 0xfaf0e6), ("magenta", 0xff00ff), ("maroon", 0x800000), ("mediumaquamarine", 0x66cdaa), ("mediumblue", 0x0000cd), ("mediumorchid", 0xba55d3), ("mediumpurple", 0x9370db), ("mediumseagreen", 0x3cb371), ("mediumslateblue", 0x7b68ee), ("mediumspringgreen", 0x00fa9a), ("mediumturquoise", 0x48d1cc), ("mediumvioletred", 0xc71585), ("midnightblue", 0x191970), ("mintcream", 0xf5fffa), ("mistyrose", 0xffe4e1), ("moccasin", 0xffe4b5), ("navajowhite", 0xffdead), ("navy", 0x000080), ("oldlace", 0xfdf5e6), ("olive", 0x808000), ("olivedrab", 0x6b8e23), ("orange", 0xffa500), ("orangered", 0xff4500), ("orchid", 0xda70d6), ("palegoldenrod", 0xeee8aa), ("palegreen", 0x98fb98), ("paleturquoise", 0xafeeee), ("palevioletred", 0xdb7093), ("papayawhip", 0xffefd5), ("peachpuff", 0xffdab9), ("peru", 0xcd853f), ("pink", 0xffc0cb), ("plum", 0xdda0dd), ("powderblue", 0xb0e0e6), ("purple", 0x800080), ("rebeccapurple", 0x663399), ("red", 0xff0000), ("rosybrown", 0xbc8f8f), ("royalblue", 0x4169e1), ("saddlebrown", 0x8b4513), ("salmon", 0xfa8072), ("sandybrown", 0xf4a460), ("seagreen", 0x2e8b57), ("seashell", 0xfff5ee), ("sienna", 0xa0522d), ("silver", 0xc0c0c0), ("skyblue", 0x87ceeb), ("slateblue", 0x6a5acd), ("slategray", 0x708090), ("slategrey", 0x708090), ("snow", 0xfffafa), ("springgreen", 0x00ff7f), ("steelblue", 0x4682b4), ("tan", 0xd2b48c), ("teal", 0x008080), ("thistle", 0xd8bfd8), ("tomato", 0xff6347), ("turquoise", 0x40e0d0), ("violet", 0xee82ee), ("wheat", 0xf5deb3), ("white", 0xffffff), ("whitesmoke", 0xf5f5f5), ("yellow", 0xffff00), ("yellowgreen", 0x9acd32),];fn parse_hex(s: &str) -> Option<u32> { let h = s.trim().trim_start_matches('#'); let full = match h.len() { 3 | 4 => h.chars().take(3).flat_map(|c| [c, c]).collect::<String>(), 6 | 8 => h[..6].to_string(), _ => return None, }; u32::from_str_radix(&full, 16).ok()}// "#rgb", "#rrggbb", "rgb(r, g, b)" or a CSS name, as 0xRRGGBB.fn parse(c: &str) -> Result<u32, String> { let t = c.trim().to_lowercase(); if let Some(v) = NAMES.iter().find(|(n, _)| *n == t).map(|(_, v)| *v) { return Ok(v); } if let Some(inner) = t.strip_prefix("rgb(").or_else(|| t.strip_prefix("rgba(")).and_then(|r| r.strip_suffix(')')) { let parts: Vec<u32> = inner.split(|ch| ch == ',' || ch == ' ' || ch == '/').filter(|p| !p.is_empty()).take(3).filter_map(|p| p.trim().parse::<f64>().ok()).map(|x| x.round().clamp(0.0, 255.0) as u32).collect(); if parts.len() == 3 { return Ok(parts[0] << 16 | parts[1] << 8 | parts[2]); } } if t.starts_with('#') || t.chars().all(|ch| ch.is_ascii_hexdigit()) { if let Some(v) = parse_hex(&t) { return Ok(v); } } Err(format!("`{}` is not a colour: give \"#rrggbb\", \"#rgb\", \"rgb(r, g, b)\" or a CSS name", c))}fn hex(v: u32) -> String { format!("#{:06x}", v)}// Oklab: distances there follow how different colours look.fn oklab(v: u32) -> [f64; 3] { let lin = |c: u32| { let s = c as f64 / 255.0; if s <= 0.04045 { s / 12.92 } else { ((s + 0.055) / 1.055).powf(2.4) } }; let (r, g, b) = (lin(v >> 16 & 255), lin(v >> 8 & 255), lin(v & 255)); let l = (0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b).cbrt(); let m = (0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b).cbrt(); let s = (0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b).cbrt(); [0.2104542553 * l + 0.7936177850 * m - 0.0040720468 * s, 1.9779984951 * l - 2.4285922050 * m + 0.4505937099 * s, 0.0259040371 * l + 0.7827717662 * m - 0.8086757660 * s]}fn dist(a: u32, b: u32) -> f64 { let (x, y) = (oklab(a), oklab(b)); ((x[0] - y[0]).powi(2) + (x[1] - y[1]).powi(2) + (x[2] - y[2]).powi(2)).sqrt()}fn ranked(v: u32) -> Vec<(&'static str, u32, f64)> { let mut all: Vec<(&str, u32, f64)> = NAMES.iter().map(|(n, h)| (*n, *h, dist(v, *h))).collect(); // grey and gray name the same colours: keep the "gray" spellings once. all.retain(|(n, _, _)| !n.contains("grey")); all.sort_by(|a, b| a.2.partial_cmp(&b.2).unwrap_or(std::cmp::Ordering::Equal)); all}/// The CSS colour name nearest to `color` ("#3b82f6", "#abc", "rgb(59, 130, 246)" or a name): `{ name, hex, distance, exact }`./// `distance` is how far apart they look (Oklab, 0 the same, under 0.02 hard to tell, over 0.1 clearly different); `exact` true when it is that colour.pub fn color_name(color: &str) -> Result<Value, String> { let v = parse(color)?; let (n, h, d) = ranked(v)[0]; Ok(json!({ "name": n, "hex": hex(h), "distance": (d * 10000.0).round() / 10000.0, "exact": h == v }))}/// The `count` nearest names (1 to 20), nearest first, each `{ name, hex, distance }`: to offer a choice, or a search by colour.pub fn color_name_nearest(color: &str, count: i64) -> Result<Vec<Value>, String> { let v = parse(color)?; Ok(ranked(v).into_iter().take(count.clamp(1, 20) as usize).map(|(n, h, d)| json!({ "name": n, "hex": hex(h), "distance": (d * 10000.0).round() / 10000.0 })).collect())}/// A CSS colour name ("rebeccapurple", "Light Sea Green" with spaces and capitals too) as "#rrggbb"; an error for a name CSS does not have.pub fn color_name_hex(name: &str) -> Result<String, String> { let n: String = name.trim().to_lowercase().chars().filter(|c| !c.is_whitespace() && *c != '-' && *c != '_').collect(); NAMES.iter().find(|(k, _)| *k == n).map(|(_, v)| hex(*v)).ok_or_else(|| format!("`{}` is not a CSS colour name", name))}/// All 148 CSS colour names with their hex, as `{ name, hex }` in alphabetical order (gray and grey spellings both).pub fn color_name_list() -> Vec<Value> { NAMES.iter().map(|(n, h)| json!({ "name": n, "hex": hex(*h) })).collect()}Related
color_vision.qwer · 1.0.0Colours and pictures as people with colour blindness see them, at full or milder severity; chart palettes checked for colours that become alike; and text contrast (WCAG) as each of them sees it.8 views · 7 downloadsColour contrast color.qwer · 1.0.0Colours in any CSS form, contrast checked against WCAG AA and AAA, readable text on any colour, and mixes.6 views · 6 downloadsGradients gradient.qwer · 1.0.0Colour scales and gradients (viridis, magma, blues, red-blue and more, or your own stops) as hex lists, a colour per value, CSS or SVG.6 views · 7 downloadsImage hash image_hash.qwer · 1.0.0Perceptual hashes of pictures and how far apart two are, to find near-duplicates among uploads or a photo library.7 views · 7 downloadsPalette palette.qwer · 1.0.0A picture's main colours as hex, how much of it each covers, and a readable text colour on each, for themes and matching cards.7 views · 8 downloadsThread 0 posts
On Colour names: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.