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
use image::{imageops::overlay, ImageError, DynamicImage};
use std::path::Path;
use rand::prelude::*;

mod emoji;


fn measure_dist_chunks(samples_a: &[u8], samples_b: &[u8]) -> i64 {
    samples_a.iter()
        .zip(samples_b.iter())
        .fold(0, |rgba, (p_a, p_b)| {
                rgba + (*p_a as i64 - *p_b as i64).abs()
        })
}

fn subimage_compare(image_a: &DynamicImage, image_b: &DynamicImage, x: u32, y: u32 ) -> i64 {
    let sub_image_a = image_a.crop_imm(x,y,16,16).to_rgb();
    let sub_image_b = image_b.crop_imm(x,y,16,16).to_rgb();
    measure_dist_chunks(&sub_image_a, &sub_image_b)
}

pub fn generate_image(
    image_buffer: &DynamicImage,
    iterations: u64,
    save_progress: bool,
    path: &Path,
) -> Result<Vec<u8>, ImageError> {

    let mut emoji_cache = emoji::EmojiCache::new();

    let image_buffer_rgb = image_buffer.clone().to_rgb();
    let (width, height) = image_buffer_rgb.dimensions();
    let canvas_size = width * height;
    let mut rng = thread_rng();
    let mut new_img = DynamicImage::new_rgb16(width, height);

    for _  in 0..canvas_size/20 {
        let e = emoji_cache.get_emoji();
        let x: u32 = (0..width).choose(&mut rng).unwrap();
        let y: u32 = (0..height).choose(&mut rng).unwrap();
        overlay(&mut new_img, e, x, y);
    }

    for index in 0..iterations {
        let e = emoji_cache.get_emoji();
        let x: u32 = (0..width).choose(&mut rng).unwrap();
        let y: u32 = (0..height).choose(&mut rng).unwrap();
        let mut temp_img = new_img.clone();
        let temp_dist1 = subimage_compare(&image_buffer, &temp_img, x, y);
        overlay(&mut temp_img, e, x, y);
        let temp_dist2 = subimage_compare(&image_buffer, &temp_img, x, y);
        if temp_dist1 > temp_dist2 {
            new_img = temp_img;
        }
        if index%10000==0 && save_progress {
            new_img.save(path)?;
        }
    }
    new_img.save(path)?;

    Ok(new_img.to_rgb().to_vec())
}

#[cfg(test)]

mod tests {
    #[test]
    fn it_works() {
        use image::open;
        use std::path::Path;
        use std::time::Instant;
        let now = Instant::now();

        let img = open(Path::new("./assets/georgia.jpg")).unwrap();
        let path = Path::new("./g.png");

        let new_img = crate::generate_image(&img, 30_000, false, path);
        println!("{}", now.elapsed().as_secs());
        match new_img {
            Ok(_) => println!("OK"),
            Err(e) => println!("{}", e),
        }
    }
}