1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
use image::{Rgba, RgbaImage}; use hsl::HSL; use {hsl_to_rgba, fill_rect}; pub struct Options { pub size: u32, pub scale: u32, pub seed: Vec<u8>, pub color: Option<Rgba<u8>>, pub background_color: Option<Rgba<u8>>, pub spot_color: Option<Rgba<u8>>, } pub struct Ethereum { randseed: [i32; 4], } #[derive(Debug, Clone)] enum FillType { None, Color, SpotColor, } impl Ethereum { fn seedrand(&mut self, seed: &[u8]) { self.randseed = [0i32; 4]; for i in 0..seed.len() { let (tmp, _) = (self.randseed[i % 4] << 5).overflowing_sub(self.randseed[i % 4]); self.randseed[i % 4] = tmp + seed[i] as i32; } } fn rand(&mut self) -> f64 { let t = self.randseed[0] ^ (self.randseed[0] << 11); self.randseed[0] = self.randseed[1]; self.randseed[1] = self.randseed[2]; self.randseed[2] = self.randseed[3]; self.randseed[3] = self.randseed[3] ^ (self.randseed[3] >> 19) ^ (t ^ (t >> 8)); ((self.randseed[3].abs() as f64) / ((1i32 << 31) as f64)).abs() } fn create_color(&mut self) -> Rgba<u8> { let hsl = HSL { h: (self.rand() * 360.0).floor(), s: (self.rand() * 60.0 + 40.0) / 100.0, l: (self.rand() + self.rand() + self.rand() + self.rand()) * 25.0 / 100.0, }; hsl_to_rgba(hsl) } fn create_image_data(&mut self, size: u32) -> Vec<FillType> { let odd = size % 2 == 1; let data_width = size / 2; (0..size) .into_iter() .map(|_| { let row = (0..data_width) .into_iter() .map(|_| { match (self.rand() * 2.3).floor() { 0.0 => FillType::None, 1.0 => FillType::Color, _ => FillType::SpotColor, } }) .collect::<Vec<_>>(); let mut cloned_row = row.clone(); if odd { let last = cloned_row.last().cloned().unwrap_or(FillType::None); cloned_row.push(last); } cloned_row.into_iter().chain(row.into_iter().rev()).collect::<Vec<_>>() }) .flat_map(|x| x) .collect() } pub fn create_icon(options: Options) -> RgbaImage { let mut builder = Ethereum { randseed: [0i32; 4], }; builder.seedrand(&options.seed); let scale = options.scale; let color = options.color.unwrap_or_else(|| builder.create_color()); let background_color = options.background_color.unwrap_or_else(|| builder.create_color()); let spot_color = options.spot_color.unwrap_or_else(|| builder.create_color()); let image_data = builder.create_image_data(options.size); let real_size = options.size * scale; let mut image = RgbaImage::new(real_size, real_size); fill_rect(&mut image, 0, 0, real_size, background_color); for (index, fill) in image_data.into_iter().enumerate() { let index = index as u32; let row = index / options.size; let col = index % options.size; match fill { FillType::None => (), FillType::Color => fill_rect(&mut image, col * scale, row * scale, scale, color), FillType::SpotColor => fill_rect(&mut image, col * scale, row * scale, scale, spot_color), } } image } }