Added image colour sum

This commit is contained in:
2024-05-07 18:24:04 +01:00
parent 7b6a16b662
commit c46405efce
13 changed files with 7177 additions and 0 deletions

View File

@@ -0,0 +1,150 @@
use std::fs::read_to_string;
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 1 || args[1].contains("xkcd") {
gen_xkcd_file();
} else if args[1].contains("x11") {
gen_x11_file();
} else if args[1].contains("css") {
gen_css_file();
}
}
fn gen_css_file() {
let rgb_file = "resources/css_rgb.txt";
let mut colour_pairs: Vec<(String, [u8; 3])> = Vec::new();
for line in read_to_string(rgb_file).unwrap().lines() {
if line.starts_with('#') {
continue;
}
let parts: Vec<&str> = line.trim().split("#").collect();
assert_eq!(2, parts.len());
let name = titlecase_no_spaces(&parts[0].trim());
let c = hexstr_to_rgb_u8(parts[1].trim());
colour_pairs.push((name, c));
}
gen_file(colour_pairs);
}
fn gen_x11_file() {
let rgb_file = "resources/x11_rgb.txt";
let mut colour_pairs: Vec<(String, [u8; 3])> = Vec::new();
for line in read_to_string(rgb_file).unwrap().lines() {
if line.starts_with('#') {
continue;
}
let parts: Vec<&str> = line.split("\t\t").collect();
assert_eq!(parts.len(), 2);
if parts[1].contains("grey") || parts[1].contains("Grey") {
// Deduplicate and remove US spelling
continue;
}
let name = titlecase_no_spaces(&parts[1]);
let c_parts = parts[0].replace(" ", " ");
let c_parts = c_parts.replace(" ", " ");
let c_parts: Vec<&str> = c_parts.trim().split(' ').collect();
let c_nums = [
c_parts[0].parse::<u8>().unwrap(),
c_parts[1].parse::<u8>().unwrap(),
c_parts[2].parse::<u8>().unwrap(),
];
if colour_pairs.contains(&(name.clone(), c_nums)) {
continue;
}
colour_pairs.push((name, c_nums));
}
gen_file(colour_pairs);
}
fn gen_xkcd_file() {
let rgb_file = "resources/xkcd_rgb.txt";
let mut colour_pairs: Vec<(String, [u8; 3])> = Vec::new();
for line in read_to_string(rgb_file).unwrap().lines() {
if line.starts_with('#') {
continue;
}
let parts: Vec<&str> = line.split("#").collect();
assert_eq!(parts.len(), 2);
let c = hexstr_to_rgb_u8(parts[1].trim());
let name = titlecase_no_spaces(&parts[0]);
colour_pairs.push((name, c));
}
gen_file(colour_pairs);
}
fn gen_file(colour_pairs: Vec<(String, [u8; 3])>) {
println!("#![allow(dead_code)]");
println!("use std::slice::Iter;");
println!("pub const NUM_COLOURS: usize = {};", colour_pairs.len());
println!("#[derive(PartialEq, Clone, Copy, Hash, Eq, Debug)]");
println!("pub enum Colour {{");
for c in &colour_pairs {
println!(" {},", c.0);
}
println!("}}\n");
println!("impl Colour {{");
println!(" pub fn iterator() -> Iter<'static, Colour> {{");
println!(
" static COLOURS: [Colour; {}] = [",
colour_pairs.len()
);
for c in &colour_pairs {
println!(" Colour::{},", c.0)
}
println!(" ];");
println!(" COLOURS.iter()");
println!(" }}");
println!(" pub fn to_rgb(&self) -> [u8; 3] {{");
println!(" match self {{");
for c in &colour_pairs {
println!(
" Colour::{} => [{}, {}, {}],",
c.0, c.1[0], c.1[1], c.1[2]
);
}
println!(" }}");
println!(" }}");
println!("}}");
}
fn titlecase_no_spaces(s: &str) -> String {
let mut ts: String = String::new();
let mut last_char_was_space = true;
for c in s.chars() {
if last_char_was_space {
ts.push(c.to_ascii_uppercase());
last_char_was_space = false;
continue;
}
if c.is_whitespace() {
last_char_was_space = true;
continue;
}
if c == '\'' {
continue;
}
if c == '/' {
last_char_was_space = true;
ts.push('A');
ts.push('n');
ts.push('d');
continue;
}
if c.is_alphanumeric() {
ts.push(c);
}
}
ts
}
// Taken from https://stackoverflow.com/questions/52987181
fn hexstr_to_rgb_u8(hex: &str) -> [u8; 3] {
assert_eq!(hex.len(), 6);
let c: Vec<u8> = (0..hex.len())
.step_by(2)
.map(|i| u8::from_str_radix(&hex[i..i + 2], 16).unwrap())
.collect();
[c[0], c[1], c[2]]
}

View File

@@ -0,0 +1,462 @@
#![allow(dead_code)]
use std::slice::Iter;
pub const NUM_COLOURS: usize = 148;
#[derive(PartialEq, Clone, Copy, Hash, Eq, Debug)]
pub enum Colour {
Aliceblue,
Antiquewhite,
Aqua,
Aquamarine,
Azure,
Beige,
Bisque,
Black,
Blanchedalmond,
Blue,
Blueviolet,
Brown,
Burlywood,
Cadetblue,
Chartreuse,
Chocolate,
Coral,
Cornflowerblue,
Cornsilk,
Crimson,
Cyan,
Darkblue,
Darkcyan,
Darkgoldenrod,
Darkgray,
Darkgreen,
Darkgrey,
Darkkhaki,
Darkmagenta,
Darkolivegreen,
Darkorange,
Darkorchid,
Darkred,
Darksalmon,
Darkseagreen,
Darkslateblue,
Darkslategray,
Darkslategrey,
Darkturquoise,
Darkviolet,
Deeppink,
Deepskyblue,
Dimgray,
Dimgrey,
Dodgerblue,
Firebrick,
Floralwhite,
Forestgreen,
Fuchsia,
Gainsboro,
Ghostwhite,
Gold,
Goldenrod,
Gray,
Green,
Greenyellow,
Grey,
Honeydew,
Hotpink,
Indianred,
Indigo,
Ivory,
Khaki,
Lavender,
Lavenderblush,
Lawngreen,
Lemonchiffon,
Lightblue,
Lightcoral,
Lightcyan,
Lightgoldenrodyellow,
Lightgray,
Lightgreen,
Lightgrey,
Lightpink,
Lightsalmon,
Lightseagreen,
Lightskyblue,
Lightslategray,
Lightslategrey,
Lightsteelblue,
Lightyellow,
Lime,
Limegreen,
Linen,
Magenta,
Maroon,
Mediumaquamarine,
Mediumblue,
Mediumorchid,
Mediumpurple,
Mediumseagreen,
Mediumslateblue,
Mediumspringgreen,
Mediumturquoise,
Mediumvioletred,
Midnightblue,
Mintcream,
Mistyrose,
Moccasin,
Navajowhite,
Navy,
Oldlace,
Olive,
Olivedrab,
Orange,
Orangered,
Orchid,
Palegoldenrod,
Palegreen,
Paleturquoise,
Palevioletred,
Papayawhip,
Peachpuff,
Peru,
Pink,
Plum,
Powderblue,
Purple,
Rebeccapurple,
Red,
Rosybrown,
Royalblue,
Saddlebrown,
Salmon,
Sandybrown,
Seagreen,
Seashell,
Sienna,
Silver,
Skyblue,
Slateblue,
Slategray,
Slategrey,
Snow,
Springgreen,
Steelblue,
Tan,
Teal,
Thistle,
Tomato,
Turquoise,
Violet,
Wheat,
White,
Whitesmoke,
Yellow,
Yellowgreen,
}
impl Colour {
pub fn iterator() -> Iter<'static, Colour> {
static COLOURS: [Colour; 148] = [
Colour::Aliceblue,
Colour::Antiquewhite,
Colour::Aqua,
Colour::Aquamarine,
Colour::Azure,
Colour::Beige,
Colour::Bisque,
Colour::Black,
Colour::Blanchedalmond,
Colour::Blue,
Colour::Blueviolet,
Colour::Brown,
Colour::Burlywood,
Colour::Cadetblue,
Colour::Chartreuse,
Colour::Chocolate,
Colour::Coral,
Colour::Cornflowerblue,
Colour::Cornsilk,
Colour::Crimson,
Colour::Cyan,
Colour::Darkblue,
Colour::Darkcyan,
Colour::Darkgoldenrod,
Colour::Darkgray,
Colour::Darkgreen,
Colour::Darkgrey,
Colour::Darkkhaki,
Colour::Darkmagenta,
Colour::Darkolivegreen,
Colour::Darkorange,
Colour::Darkorchid,
Colour::Darkred,
Colour::Darksalmon,
Colour::Darkseagreen,
Colour::Darkslateblue,
Colour::Darkslategray,
Colour::Darkslategrey,
Colour::Darkturquoise,
Colour::Darkviolet,
Colour::Deeppink,
Colour::Deepskyblue,
Colour::Dimgray,
Colour::Dimgrey,
Colour::Dodgerblue,
Colour::Firebrick,
Colour::Floralwhite,
Colour::Forestgreen,
Colour::Fuchsia,
Colour::Gainsboro,
Colour::Ghostwhite,
Colour::Gold,
Colour::Goldenrod,
Colour::Gray,
Colour::Green,
Colour::Greenyellow,
Colour::Grey,
Colour::Honeydew,
Colour::Hotpink,
Colour::Indianred,
Colour::Indigo,
Colour::Ivory,
Colour::Khaki,
Colour::Lavender,
Colour::Lavenderblush,
Colour::Lawngreen,
Colour::Lemonchiffon,
Colour::Lightblue,
Colour::Lightcoral,
Colour::Lightcyan,
Colour::Lightgoldenrodyellow,
Colour::Lightgray,
Colour::Lightgreen,
Colour::Lightgrey,
Colour::Lightpink,
Colour::Lightsalmon,
Colour::Lightseagreen,
Colour::Lightskyblue,
Colour::Lightslategray,
Colour::Lightslategrey,
Colour::Lightsteelblue,
Colour::Lightyellow,
Colour::Lime,
Colour::Limegreen,
Colour::Linen,
Colour::Magenta,
Colour::Maroon,
Colour::Mediumaquamarine,
Colour::Mediumblue,
Colour::Mediumorchid,
Colour::Mediumpurple,
Colour::Mediumseagreen,
Colour::Mediumslateblue,
Colour::Mediumspringgreen,
Colour::Mediumturquoise,
Colour::Mediumvioletred,
Colour::Midnightblue,
Colour::Mintcream,
Colour::Mistyrose,
Colour::Moccasin,
Colour::Navajowhite,
Colour::Navy,
Colour::Oldlace,
Colour::Olive,
Colour::Olivedrab,
Colour::Orange,
Colour::Orangered,
Colour::Orchid,
Colour::Palegoldenrod,
Colour::Palegreen,
Colour::Paleturquoise,
Colour::Palevioletred,
Colour::Papayawhip,
Colour::Peachpuff,
Colour::Peru,
Colour::Pink,
Colour::Plum,
Colour::Powderblue,
Colour::Purple,
Colour::Rebeccapurple,
Colour::Red,
Colour::Rosybrown,
Colour::Royalblue,
Colour::Saddlebrown,
Colour::Salmon,
Colour::Sandybrown,
Colour::Seagreen,
Colour::Seashell,
Colour::Sienna,
Colour::Silver,
Colour::Skyblue,
Colour::Slateblue,
Colour::Slategray,
Colour::Slategrey,
Colour::Snow,
Colour::Springgreen,
Colour::Steelblue,
Colour::Tan,
Colour::Teal,
Colour::Thistle,
Colour::Tomato,
Colour::Turquoise,
Colour::Violet,
Colour::Wheat,
Colour::White,
Colour::Whitesmoke,
Colour::Yellow,
Colour::Yellowgreen,
];
COLOURS.iter()
}
pub fn to_rgb(&self) -> [u8; 3] {
match self {
Colour::Aliceblue => [240, 248, 255],
Colour::Antiquewhite => [250, 235, 215],
Colour::Aqua => [0, 255, 255],
Colour::Aquamarine => [127, 255, 212],
Colour::Azure => [240, 255, 255],
Colour::Beige => [245, 245, 220],
Colour::Bisque => [255, 228, 196],
Colour::Black => [0, 0, 0],
Colour::Blanchedalmond => [255, 235, 205],
Colour::Blue => [0, 0, 255],
Colour::Blueviolet => [138, 43, 226],
Colour::Brown => [165, 42, 42],
Colour::Burlywood => [222, 184, 135],
Colour::Cadetblue => [95, 158, 160],
Colour::Chartreuse => [127, 255, 0],
Colour::Chocolate => [210, 105, 30],
Colour::Coral => [255, 127, 80],
Colour::Cornflowerblue => [100, 149, 237],
Colour::Cornsilk => [255, 248, 220],
Colour::Crimson => [220, 20, 60],
Colour::Cyan => [0, 255, 255],
Colour::Darkblue => [0, 0, 139],
Colour::Darkcyan => [0, 139, 139],
Colour::Darkgoldenrod => [184, 134, 11],
Colour::Darkgray => [169, 169, 169],
Colour::Darkgreen => [0, 100, 0],
Colour::Darkgrey => [169, 169, 169],
Colour::Darkkhaki => [189, 183, 107],
Colour::Darkmagenta => [139, 0, 139],
Colour::Darkolivegreen => [85, 107, 47],
Colour::Darkorange => [255, 140, 0],
Colour::Darkorchid => [153, 50, 204],
Colour::Darkred => [139, 0, 0],
Colour::Darksalmon => [233, 150, 122],
Colour::Darkseagreen => [143, 188, 143],
Colour::Darkslateblue => [72, 61, 139],
Colour::Darkslategray => [47, 79, 79],
Colour::Darkslategrey => [47, 79, 79],
Colour::Darkturquoise => [0, 206, 209],
Colour::Darkviolet => [148, 0, 211],
Colour::Deeppink => [255, 20, 147],
Colour::Deepskyblue => [0, 191, 255],
Colour::Dimgray => [105, 105, 105],
Colour::Dimgrey => [105, 105, 105],
Colour::Dodgerblue => [30, 144, 255],
Colour::Firebrick => [178, 34, 34],
Colour::Floralwhite => [255, 250, 240],
Colour::Forestgreen => [34, 139, 34],
Colour::Fuchsia => [255, 0, 255],
Colour::Gainsboro => [220, 220, 220],
Colour::Ghostwhite => [248, 248, 255],
Colour::Gold => [255, 215, 0],
Colour::Goldenrod => [218, 165, 32],
Colour::Gray => [128, 128, 128],
Colour::Green => [0, 128, 0],
Colour::Greenyellow => [173, 255, 47],
Colour::Grey => [128, 128, 128],
Colour::Honeydew => [240, 255, 240],
Colour::Hotpink => [255, 105, 180],
Colour::Indianred => [205, 92, 92],
Colour::Indigo => [75, 0, 130],
Colour::Ivory => [255, 255, 240],
Colour::Khaki => [240, 230, 140],
Colour::Lavender => [230, 230, 250],
Colour::Lavenderblush => [255, 240, 245],
Colour::Lawngreen => [124, 252, 0],
Colour::Lemonchiffon => [255, 250, 205],
Colour::Lightblue => [173, 216, 230],
Colour::Lightcoral => [240, 128, 128],
Colour::Lightcyan => [224, 255, 255],
Colour::Lightgoldenrodyellow => [250, 250, 210],
Colour::Lightgray => [211, 211, 211],
Colour::Lightgreen => [144, 238, 144],
Colour::Lightgrey => [211, 211, 211],
Colour::Lightpink => [255, 182, 193],
Colour::Lightsalmon => [255, 160, 122],
Colour::Lightseagreen => [32, 178, 170],
Colour::Lightskyblue => [135, 206, 250],
Colour::Lightslategray => [119, 136, 153],
Colour::Lightslategrey => [119, 136, 153],
Colour::Lightsteelblue => [176, 196, 222],
Colour::Lightyellow => [255, 255, 224],
Colour::Lime => [0, 255, 0],
Colour::Limegreen => [50, 205, 50],
Colour::Linen => [250, 240, 230],
Colour::Magenta => [255, 0, 255],
Colour::Maroon => [128, 0, 0],
Colour::Mediumaquamarine => [102, 205, 170],
Colour::Mediumblue => [0, 0, 205],
Colour::Mediumorchid => [186, 85, 211],
Colour::Mediumpurple => [147, 112, 219],
Colour::Mediumseagreen => [60, 179, 113],
Colour::Mediumslateblue => [123, 104, 238],
Colour::Mediumspringgreen => [0, 250, 154],
Colour::Mediumturquoise => [72, 209, 204],
Colour::Mediumvioletred => [199, 21, 133],
Colour::Midnightblue => [25, 25, 112],
Colour::Mintcream => [245, 255, 250],
Colour::Mistyrose => [255, 228, 225],
Colour::Moccasin => [255, 228, 181],
Colour::Navajowhite => [255, 222, 173],
Colour::Navy => [0, 0, 128],
Colour::Oldlace => [253, 245, 230],
Colour::Olive => [128, 128, 0],
Colour::Olivedrab => [107, 142, 35],
Colour::Orange => [255, 165, 0],
Colour::Orangered => [255, 69, 0],
Colour::Orchid => [218, 112, 214],
Colour::Palegoldenrod => [238, 232, 170],
Colour::Palegreen => [152, 251, 152],
Colour::Paleturquoise => [175, 238, 238],
Colour::Palevioletred => [219, 112, 147],
Colour::Papayawhip => [255, 239, 213],
Colour::Peachpuff => [255, 218, 185],
Colour::Peru => [205, 133, 63],
Colour::Pink => [255, 192, 203],
Colour::Plum => [221, 160, 221],
Colour::Powderblue => [176, 224, 230],
Colour::Purple => [128, 0, 128],
Colour::Rebeccapurple => [102, 51, 153],
Colour::Red => [255, 0, 0],
Colour::Rosybrown => [188, 143, 143],
Colour::Royalblue => [65, 105, 225],
Colour::Saddlebrown => [139, 69, 19],
Colour::Salmon => [250, 128, 114],
Colour::Sandybrown => [244, 164, 96],
Colour::Seagreen => [46, 139, 87],
Colour::Seashell => [255, 245, 238],
Colour::Sienna => [160, 82, 45],
Colour::Silver => [192, 192, 192],
Colour::Skyblue => [135, 206, 235],
Colour::Slateblue => [106, 90, 205],
Colour::Slategray => [112, 128, 144],
Colour::Slategrey => [112, 128, 144],
Colour::Snow => [255, 250, 250],
Colour::Springgreen => [0, 255, 127],
Colour::Steelblue => [70, 130, 180],
Colour::Tan => [210, 180, 140],
Colour::Teal => [0, 128, 128],
Colour::Thistle => [216, 191, 216],
Colour::Tomato => [255, 99, 71],
Colour::Turquoise => [64, 224, 208],
Colour::Violet => [238, 130, 238],
Colour::Wheat => [245, 222, 179],
Colour::White => [255, 255, 255],
Colour::Whitesmoke => [245, 245, 245],
Colour::Yellow => [255, 255, 0],
Colour::Yellowgreen => [154, 205, 50],
}
}
}

View File

@@ -0,0 +1,87 @@
use image::{DynamicImage, GenericImageView, Pixel, Rgb, RgbImage, ImageBuffer};
use std::env;
mod xkcd_colours;
mod x11_colours;
mod css_colours;
//use xkcd_colours as colours;
//use x11_colours as colours;
use css_colours as colours;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 2 {
process_image_file(&args[1]);
}
replace_colours_with_nearest();
}
fn replace_colours_with_nearest() {
let img = image::open("resources/pexels-scott-webb-137594.jpg").unwrap();
let (width, height) = img.dimensions();
let mut out: RgbImage = ImageBuffer::new(width, height);
for x in 0..width {
for y in 0..height {
let pixel = img.get_pixel(x, y).to_rgb();
out.put_pixel(x, y, Rgb(get_nearest_colour(pixel).to_rgb()));
}
}
out.save("out.jpg").unwrap();
}
fn get_all_nearest_colours(img: DynamicImage) -> Vec<(colours::Colour, u32)> {
let mut colours: Vec<(colours::Colour, u32)> = Vec::with_capacity(colours::NUM_COLOURS);
for c in colours::Colour::iterator() {
colours.push((c.clone(), 0));
}
for pixel in img.pixels() {
let pixel_colour = get_nearest_colour(pixel.2.to_rgb());
colours[pixel_colour as usize].1 = colours[pixel_colour as usize].1 + 1;
}
colours.retain(|(_c, n)| *n != 0 as u32);
colours.sort_by(|a, b| b.1.cmp(&a.1));
colours
}
fn get_nearest_colour(p: Rgb<u8>) -> colours::Colour {
let mut lowest_distance = f64::MAX;
let mut closest_colour = colours::Colour::Black;
for col in colours::Colour::iterator() {
let c = col.to_rgb();
let d = (p.0[0] as i32 - c[0] as i32).pow(2) + (p.0[1] as i32 - c[1] as i32).pow(2) as i32 + (p.0[2] as i32 - c[2] as i32).pow(2);
let d = (d as f64).sqrt();
if d < lowest_distance {
closest_colour = col.clone();
lowest_distance = d;
}
}
closest_colour
}
fn process_image_file(file: &str) -> Vec<(colours::Colour, u32)> {
let img = image::open(file).unwrap();
let colours = get_all_nearest_colours(img);
colours
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rusty_pic() {
let colours = process_image_file("resources/pexels-scott-webb-137594.jpg");
println!("{:?}", colours);
}
#[test]
fn test_birdy_pic() {
let colours = process_image_file("resources/pexels-erik-karits-3761421.jpg");
println!("{:?}", colours);
}
#[test]
fn test_painty_pic() {
let colours = process_image_file("resources/pexels-steve-johnson-1070536.jpg");
println!("{:?}", colours);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff