1use crate::*;
2
3const HASH_SIZE: usize = 16;
4
5#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
7pub struct Hash(Vec<bool>);
8
9impl std::fmt::Display for Hash {
10 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
11 write!(fmt, "{:x}", self)
12 }
13}
14
15fn to_byte(b: &[bool]) -> u8 {
16 let mut dest = 0;
17 for (i, x) in b.iter().enumerate() {
18 if *x {
19 dest |= 1 << i;
20 }
21 }
22 dest
23}
24
25impl std::fmt::LowerHex for Hash {
26 fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
27 for c in self.0.chunks(8).map(to_byte) {
28 write!(fmt, "{:02x}", c)?
29 }
30 Ok(())
31 }
32}
33
34impl Hash {
35 pub fn diff(&self, other: &Hash) -> usize {
37 let mut diff = 0;
38
39 for (i, x) in self.0.iter().enumerate() {
40 if other.0[i] != *x {
41 diff += 1;
42 }
43 }
44
45 diff
46 }
47}
48
49impl From<Hash> for String {
50 fn from(hash: Hash) -> String {
51 format!("{}", hash)
52 }
53}
54
55impl From<Hash> for Vec<bool> {
56 fn from(hash: Hash) -> Vec<bool> {
57 hash.0
58 }
59}
60
61impl<T: Type, C: Color> Image<T, C> {
62 pub fn hash(&self) -> Hash {
64 let small: Image<T, C> = self.resize((HASH_SIZE, HASH_SIZE));
65 let mut hash = vec![false; HASH_SIZE * HASH_SIZE];
66 let mut index = 0;
67 let mut px = Pixel::new();
68 let mut c = C::CHANNELS;
69 if C::ALPHA.is_some() {
70 c -= 1;
71 }
72
73 let mut sum: f64 = 0.;
74
75 for j in 0..HASH_SIZE {
76 for i in 0..HASH_SIZE {
77 for c in 0..c {
78 sum += small.get_f((i, j), c);
79 }
80 }
81 }
82
83 let avg = sum / (HASH_SIZE * HASH_SIZE * c) as f64;
84
85 for j in 0..HASH_SIZE {
86 for i in 0..HASH_SIZE {
87 small.pixel_at((i, j), &mut px);
88 if px.iter().sum::<f64>() / c as f64 > avg {
89 hash[index] = true;
90 }
91 index += 1
92 }
93 }
94 Hash(hash)
95 }
96}