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
use crate::errors::SicImageEngineError;
use crate::operations::ImageOperation;
use crate::wrapper::overlay::OverlayInputs;
use rayon::iter::{IndexedParallelIterator, IntoParallelRefMutIterator, ParallelIterator};
use sic_core::image::{imageops, DynamicImage};
use sic_core::{image, SicImage};
use std::convert::TryFrom;

pub struct Overlay<'overlay> {
    inputs: &'overlay OverlayInputs,
}

impl<'overlay> Overlay<'overlay> {
    pub fn new(inputs: &'overlay OverlayInputs) -> Self {
        Self { inputs }
    }
}

impl<'overlay> ImageOperation for Overlay<'overlay> {
    fn apply_operation(&self, image: &mut SicImage) -> Result<(), SicImageEngineError> {
        match image {
            SicImage::Static(image) => overlay_static(image, self.inputs),
            SicImage::Animated(image) => overlay_animated_image(image.frames_mut(), self.inputs),
        }
    }
}

fn overlay_animated_image(
    frames: &mut [image::Frame],
    inputs: &OverlayInputs,
) -> Result<(), SicImageEngineError> {
    // Open matching image
    let overlay_image = inputs.image_path().open_image()?;
    let (x, y) = inputs.position();

    match overlay_image {
        SicImage::Static(image) => overlay_animated_with_static(frames, &image, x, y),
        SicImage::Animated(other) => overlay_animated_with_animated(frames, other.frames(), x, y),
    }

    Ok(())
}

fn overlay_animated_with_animated(
    frames: &mut [image::Frame],
    other: &[image::Frame],
    x: i64,
    y: i64,
) {
    frames.par_iter_mut().zip(other).for_each(|(lhs, rhs)| {
        imageops::overlay(lhs.buffer_mut(), rhs.buffer(), x, y);
    });
}

fn overlay_animated_with_static(frames: &mut [image::Frame], other: &DynamicImage, x: i64, y: i64) {
    frames.par_iter_mut().for_each(|frame| {
        imageops::overlay(frame.buffer_mut(), other, x, y);
    });
}

fn overlay_static(
    image: &mut DynamicImage,
    overlay: &OverlayInputs,
) -> Result<(), SicImageEngineError> {
    let overlay_image = overlay.image_path().open_image()?;
    let overlay_image = DynamicImage::try_from(overlay_image)?;

    let (x, y) = overlay.position();
    imageops::overlay(image, &overlay_image, x, y);

    Ok(())
}