use std::fs::read_to_string; use std::path::PathBuf; use serde_derive::{Serialize, Deserialize}; use crate::colour::Colour; /// todo enumerate original format #[derive(Debug, Eq, PartialEq, Serialize, Deserialize)] pub struct Palette { pub name: String, pub colours: Vec, } impl Palette { pub fn from(name: &str, toml: &str) -> Self { let intermediate: IntermediatePalette = toml::from_str(toml).unwrap(); println!("palette name: {}", name); for colour in &intermediate.colours { println!("palette colour: {}{}{}", colour[0], colour[1], colour[2]); } Palette { name: name.to_string(), colours: intermediate.colours.iter().map(|vec| { Colour::from(vec.clone()) }).collect(), } } /// JASC .pal format (Paint Shop Pro) pub fn from_jasc(path: PathBuf) -> Self { let name = path.file_stem().unwrap().to_str().unwrap().into(); let mut colours = Vec::new(); for (index, line) in read_to_string(&path).unwrap().lines().enumerate() { // ignore the first 3 lines if index > 2 { let mut values: Vec = Vec::new(); for value in line.split_whitespace() { values.push(value.parse().unwrap()); } colours.push(Colour::from(values)); } } Palette { name, colours } } pub fn to_jasc(&self) -> String { let colours: Vec = self.colours.iter().map(|colour| format!("{} {} {}", colour.red, colour.green, colour.blue) ).collect(); format!("JASC-PAL\r\n0100\r\n{}\r\n{}\r\n", self.colours.len(), colours.join("\r\n")) } } /// for toml purposes #[derive(Serialize, Deserialize)] pub struct IntermediatePalette { pub colours: Vec>, } /// for toml purposes #[derive(Serialize, Deserialize)] struct IntermediatePalettes { /// singular so each palette section is named "palette" instead of "palettes" in toml palette: Vec, } impl IntermediatePalettes { pub fn from_dir() -> Self { Self { palette: vec![] } } } #[cfg(test)] mod test { use std::path::PathBuf; use crate::{Colour, Palette}; #[test] fn palette_from_jasc() { let path = PathBuf::from("src/test-resources/basic/palettes/soup11.pal"); let output = Palette::from_jasc(path); let expected = Palette { name: "soup11".into(), colours: vec![ Colour { red: 79, green: 30, blue: 69 }, Colour { red: 150, green: 48, blue: 87 }, Colour { red: 215, green: 68, blue: 89 }, Colour { red: 235, green: 112, blue: 96 }, Colour { red: 255, green: 179, blue: 131 }, Colour { red: 255, green: 255, blue: 255 }, Colour { red: 127, green: 227, blue: 187 }, Colour { red: 92, green: 187, blue: 196 }, Colour { red: 69, green: 126, blue: 163 }, Colour { red: 56, green: 66, blue: 118 }, Colour { red: 50, green: 36, blue: 81 } ] }; assert_eq!(output, expected); } #[test] fn palette_to_jasc() { let output = Palette { name: "soup11".into(), colours: vec![ Colour { red: 79, green: 30, blue: 69 }, Colour { red: 150, green: 48, blue: 87 }, Colour { red: 215, green: 68, blue: 89 }, Colour { red: 235, green: 112, blue: 96 }, Colour { red: 255, green: 179, blue: 131 }, Colour { red: 255, green: 255, blue: 255 }, Colour { red: 127, green: 227, blue: 187 }, Colour { red: 92, green: 187, blue: 196 }, Colour { red: 69, green: 126, blue: 163 }, Colour { red: 56, green: 66, blue: 118 }, Colour { red: 50, green: 36, blue: 81 } ] }.to_jasc(); let expected = include_str!("test-resources/basic/palettes/soup11.pal"); assert_eq!(output, expected); } #[test] fn palette_from_toml() { let output = Palette::from( "blueprint", include_str!("test-resources/basic/palettes/blueprint.toml") ); let expected = crate::mock::palette::default(); assert_eq!(output, expected); } #[test] fn palette_to_toml() { let intermediate = crate::mock::palette::intermediate(); let output = toml::to_string(&intermediate).unwrap(); let expected = include_str!("test-resources/basic/palettes/blueprint.toml"); assert_eq!(&output, expected); } }