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
use image::{Rgba, RgbaImage};
use hsl::HSL;
use {hsl_to_rgba, fill_rect, rgba};

fn white() -> Rgba<u8> {
	rgba(255, 255, 255, 255)
}

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 struct Classic {
	randseed: f64,
}

impl Classic {
	fn seedrand(&mut self, seed: &[u8]) {
		let mut randseed = 0u64;

		for i in 0..seed.len() / 2 {
			let h = ((seed[i * 2] as u64) << 8) | seed[i * 2 + 1] as u64;
			randseed = randseed ^ h;
		}

		if seed.len() % 2 == 1 {
			randseed = randseed ^ ((seed[seed.len() - 1] as u64) << 8);
		}

		self.randseed = randseed as f64;
	}

	fn rand(&mut self) -> f64 {
		let n = (self.randseed.sin() + 1.0) / 2.0;
		self.randseed += 1.0;
		let r = n * 10000.0;
		r - r.floor()
	}

	fn create_color(&mut self) -> Rgba<u8> {
		let hsl = HSL {
			h: (self.rand() * 360.0).floor(),
			s: (self.rand() * 50.0 + 50.0) / 100.0,
			l: (self.rand() * 60.0 + 20.0) / 100.0,
		};
		hsl_to_rgba(hsl)
	}

	fn create_image_data(&mut self, size: u32) -> Vec<bool> {
		let odd = size % 2 == 1;
		let data_width = size / 2;
	
		(0..size)
			.into_iter()
			.map(|_| {
				let row = (0..data_width)
					.into_iter()
					.map(|_| self.rand() >= 0.5)
					.collect::<Vec<bool>>();
				let mut cloned_row = row.clone();
				if odd {
					let last = cloned_row.last().cloned().unwrap_or(false);
					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 = Classic {
			randseed: 0.0
		};

		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(|| white());

		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() {
			if fill {
				let index = index as u32;
				let row = index / options.size;
				let col = index % options.size;

				fill_rect(&mut image, col * scale, row * scale, scale, color);
			}
		}

		image
	}
}