arko 0.2.4

A small library for pixel manipulation in images
Documentation
use crate::colors::Colors;
use crate::io::IO;
use crate::pixel_color;
use crate::validator;
use image::GenericImageView;
use rand::Rng;

pub fn bottom_to_top_global(io: IO, proba: i32, colors: Vec<Colors>) {
    let slim_global = SlimGlobal { colors, io, proba };
    slim_global.validate_attributes();
    slim_global.bottom_to_top()
}

pub fn left_to_right_global(io: IO, proba: i32, colors: Vec<Colors>) {
    let slim_global = SlimGlobal { colors, io, proba };
    slim_global.validate_attributes();
    slim_global.left_to_right()
}

pub fn right_to_left_global(io: IO, proba: i32, colors: Vec<Colors>) {
    let slim_global = SlimGlobal { colors, io, proba };
    slim_global.validate_attributes();
    slim_global.right_to_left()
}

pub fn top_to_bottom_global(io: IO, proba: i32, colors: Vec<Colors>) {
    let slim_global = SlimGlobal { colors, io, proba };
    slim_global.validate_attributes();
    slim_global.top_to_bottom()
}

pub fn bottom_to_top_per_color(io: IO, colors_proba: Vec<(Colors, i32)>) {
    let slim_per_color = SlimPerColor { io, colors_proba };
    slim_per_color.bottom_to_top()
}

pub fn left_to_right_per_color(io: IO, colors_proba: Vec<(Colors, i32)>) {
    let slim_per_color = SlimPerColor { io, colors_proba };
    slim_per_color.left_to_right()
}

pub fn right_to_left_per_color(io: IO, colors_proba: Vec<(Colors, i32)>) {
    let slim_per_color = SlimPerColor { io, colors_proba };
    slim_per_color.right_to_left()
}

pub fn top_to_bottom_per_color(io: IO, colors_proba: Vec<(Colors, i32)>) {
    let slim_per_color = SlimPerColor { io, colors_proba };
    slim_per_color.top_to_bottom()
}

struct SlimGlobal<'a> {
    colors: Vec<Colors>,
    io: IO<'a>,
    proba: i32,
}

struct SlimPerColor<'a> {
    io: IO<'a>,
    colors_proba: Vec<(Colors, i32)>,
}

trait ProbabilityCheck {
    fn color_to_glitch(&self, pixel_color: Colors) -> bool;
    fn probability_reached(&self, p: image::Rgba<u8>) -> bool;
}

impl<'a> ProbabilityCheck for SlimGlobal<'a> {
    fn color_to_glitch(&self, pixel_color: Colors) -> bool {
        self.colors.contains(&pixel_color)
    }

    fn probability_reached(&self, p: image::Rgba<u8>) -> bool {
        let pixel_color = pixel_color::get_pixel_color(p);
        let rng = rand::thread_rng().gen_range(0..100);
        !self.color_to_glitch(pixel_color) || rng > self.proba
    }
}

impl<'a> ProbabilityCheck for SlimPerColor<'a> {
    fn color_to_glitch(&self, pixel_color: Colors) -> bool {
        let color_proba = self.colors_proba.iter().filter(|cp| cp.0 == pixel_color);
        let last_value = color_proba.last().unwrap_or(&(Colors::White, 0));
        let rng = rand::thread_rng().gen_range(0..100);
        let proba = last_value.1;
        rng > proba
    }

    fn probability_reached(&self, p: image::Rgba<u8>) -> bool {
        let pixel_color = pixel_color::get_pixel_color(p);
        self.color_to_glitch(pixel_color)
    }
}

impl<'a> SlimGlobal<'a> {
    fn bottom_to_top(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for w in 0..(self.io.in_img.width()) {
            let mut tested_pixel = self.io.in_img.get_pixel(w, self.io.in_img.height() - 1);
            for h in 0..(self.io.in_img.height() - 1) {
                let inverted_h = self.io.in_img.height() - 2 - h;
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, inverted_h, self.io.in_img.get_pixel(w, inverted_h + 1));
                    tested_pixel = self.io.in_img.get_pixel(w, inverted_h);
                } else {
                    new_img.put_pixel(w, inverted_h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn left_to_right(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for h in 0..(self.io.in_img.height()) {
            let mut tested_pixel = self.io.in_img.get_pixel(0, h);
            for w in 1..(self.io.in_img.width()) {
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, h, self.io.in_img.get_pixel(w, h));
                    tested_pixel = self.io.in_img.get_pixel(w, h);
                } else {
                    new_img.put_pixel(w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn right_to_left(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for h in 0..(self.io.in_img.height()) {
            let mut tested_pixel = self.io.in_img.get_pixel(self.io.in_img.width() - 1, h);
            for w in 0..(self.io.in_img.width() - 1) {
                let inverted_w = self.io.in_img.width() - 2 - w;
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(inverted_w, h, self.io.in_img.get_pixel(inverted_w + 1, h));
                    tested_pixel = self.io.in_img.get_pixel(inverted_w, h);
                } else {
                    new_img.put_pixel(inverted_w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn top_to_bottom(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for w in 0..(self.io.in_img.width()) {
            let mut tested_pixel = self.io.in_img.get_pixel(w, 0);
            for h in 1..(self.io.in_img.height()) {
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, h, self.io.in_img.get_pixel(w, h));
                    tested_pixel = self.io.in_img.get_pixel(w, h);
                } else {
                    new_img.put_pixel(w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn validate_attributes(&self) {
        validator::percent("probability", self.proba);
    }
}

impl<'a> SlimPerColor<'a> {
    fn bottom_to_top(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for w in 0..(self.io.in_img.width()) {
            let mut tested_pixel = self.io.in_img.get_pixel(w, self.io.in_img.height() - 1);
            for h in 0..(self.io.in_img.height() - 1) {
                let inverted_h = self.io.in_img.height() - 2 - h;
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, inverted_h, self.io.in_img.get_pixel(w, inverted_h + 1));
                    tested_pixel = self.io.in_img.get_pixel(w, inverted_h);
                } else {
                    new_img.put_pixel(w, inverted_h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn left_to_right(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for h in 0..(self.io.in_img.height()) {
            let mut tested_pixel = self.io.in_img.get_pixel(0, h);
            for w in 1..(self.io.in_img.width()) {
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, h, self.io.in_img.get_pixel(w, h));
                    tested_pixel = self.io.in_img.get_pixel(w, h);
                } else {
                    new_img.put_pixel(w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn right_to_left(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for h in 0..(self.io.in_img.height()) {
            let mut tested_pixel = self.io.in_img.get_pixel(self.io.in_img.width() - 1, h);
            for w in 0..(self.io.in_img.width() - 1) {
                let inverted_w = self.io.in_img.width() - 2 - w;
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(inverted_w, h, self.io.in_img.get_pixel(inverted_w + 1, h));
                    tested_pixel = self.io.in_img.get_pixel(inverted_w, h);
                } else {
                    new_img.put_pixel(inverted_w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn top_to_bottom(&self) {
        let mut new_img = image::ImageBuffer::new(self.io.in_img.width(), self.io.in_img.height());
        for w in 0..(self.io.in_img.width()) {
            let mut tested_pixel = self.io.in_img.get_pixel(w, 0);
            for h in 1..(self.io.in_img.height()) {
                if self.probability_reached(tested_pixel) {
                    new_img.put_pixel(w, h, self.io.in_img.get_pixel(w, h));
                    tested_pixel = self.io.in_img.get_pixel(w, h);
                } else {
                    new_img.put_pixel(w, h, tested_pixel);
                }
            }
        }
        new_img.save(self.io.out_img).unwrap();
    }
}