arko 0.2.4

A small library for pixel manipulation in images
Documentation
use crate::io::IO;
use crate::pixel_color;
use crate::pixel_sorting::PixelSorting;
use image::GenericImageView;

pub fn bottom_to_top(
    io: IO,
    detection_type: i32,
    detection_min: i32,
    detection_max: i32,
    multiple_range: bool,
    detection_min_2: i32,
    detection_max_2: i32,
    sorting_by: i32,
) {
    let pixel_sort = PixelSort {
        io,
        detection_type,
        detection_max,
        detection_min,
        multiple_range,
        detection_max_2,
        detection_min_2,
        sorting_by,
    };
    pixel_sort.bottom_to_top_sort()
}

pub fn left_to_right(
    io: IO,
    detection_type: i32,
    detection_min: i32,
    detection_max: i32,
    multiple_range: bool,
    detection_min_2: i32,
    detection_max_2: i32,
    sorting_by: i32,
) {
    let pixel_sort = PixelSort {
        io,
        detection_type,
        detection_max,
        detection_min,
        multiple_range,
        detection_max_2,
        detection_min_2,
        sorting_by,
    };
    pixel_sort.left_to_right_sort()
}

pub fn right_to_left(
    io: IO,
    detection_type: i32,
    detection_min: i32,
    detection_max: i32,
    multiple_range: bool,
    detection_min_2: i32,
    detection_max_2: i32,
    sorting_by: i32,
) {
    let pixel_sort = PixelSort {
        io,
        detection_type,
        detection_max,
        detection_min,
        multiple_range,
        detection_max_2,
        detection_min_2,
        sorting_by,
    };
    pixel_sort.right_to_left_sort()
}

pub fn top_to_bottom(
    io: IO,
    detection_type: i32,
    detection_min: i32,
    detection_max: i32,
    multiple_range: bool,
    detection_min_2: i32,
    detection_max_2: i32,
    sorting_by: i32,
) {
    let pixel_sort = PixelSort {
        io,
        detection_type,
        detection_max,
        detection_min,
        multiple_range,
        detection_max_2,
        detection_min_2,
        sorting_by,
    };
    pixel_sort.top_to_bottom_sort()
}

struct PixelSort<'a> {
    io: IO<'a>,
    detection_type: i32,
    detection_max: i32,
    detection_min: i32,
    multiple_range: bool,
    detection_max_2: i32,
    detection_min_2: i32,
    sorting_by: i32,
}

impl<'a> PixelSort<'a> {
    fn are_pixels_grouped(&self, p1: image::Rgba<u8>, p2: image::Rgba<u8>) -> bool {
        if self.detection_type == 0 {
            self.is_pixel_lightness_in_range(p1) && self.is_pixel_lightness_in_range(p2)
        } else {
            self.are_pixels_same_colors(p1, p2)
        }
    }

    fn are_pixels_same_colors(&self, p1: image::Rgba<u8>, p2: image::Rgba<u8>) -> bool {
        pixel_color::get_pixel_color(p1) == pixel_color::get_pixel_color(p2)
    }

    fn bottom_to_top_sort(&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() - 1) {
            let mut strip = Vec::new();
            let mut start_h = self.io.in_img.height() - 1;
            strip.push(self.io.in_img.get_pixel(w, self.io.in_img.height() - 1));
            for h in 1..(self.io.in_img.height() - 1) {
                let previous_pixel = self.io.in_img.get_pixel(w, self.io.in_img.height() - h);
                let current_pixel = self.io.in_img.get_pixel(w, self.io.in_img.height() - 1 - h);
                if self.are_pixels_grouped(previous_pixel, current_pixel) {
                    strip.push(current_pixel);
                } else {
                    let new_strip = self.sort_strip(&mut strip);
                    self.prepend_strip_to_image_vertically(&mut new_img, new_strip, start_h, w);
                    start_h = self.io.in_img.height() - 1 - h;
                    strip = Vec::new();
                    strip.push(current_pixel);
                }
            }
            let new_strip = self.sort_strip(&mut strip);
            self.prepend_strip_to_image_vertically(&mut new_img, new_strip, start_h, w);
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn is_pixel_lightness_in_range(&self, p: image::Rgba<u8>) -> bool {
        let lig = pixel_color::get_pixel_lightness(p);
        if self.multiple_range {
            (lig / 5000.) > (self.detection_min as f32)
                && (lig / 5000.) < (self.detection_max as f32)
                || (lig / 5000.) > (self.detection_min_2 as f32)
                    && (lig / 5000.) < (self.detection_max_2 as f32)
        } else {
            (lig / 5000.) > (self.detection_min as f32)
                && (lig / 5000.) < (self.detection_max as f32)
        }
    }

    fn left_to_right_sort(&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() - 1) {
            let mut strip = Vec::new();
            let mut start_w = 0;
            strip.push(self.io.in_img.get_pixel(0, h));
            for w in 1..(self.io.in_img.width() - 1) {
                let previous_pixel = self.io.in_img.get_pixel(w - 1, h);
                let current_pixel = self.io.in_img.get_pixel(w, h);
                if self.are_pixels_grouped(previous_pixel, current_pixel) {
                    strip.push(current_pixel);
                } else {
                    let new_strip = self.sort_strip(&mut strip);
                    self.append_strip_to_image(&mut new_img, new_strip, h, start_w);
                    start_w = w + 1;
                    strip = Vec::new();
                    strip.push(current_pixel);
                }
            }
            let new_strip = self.sort_strip(&mut strip);
            self.append_strip_to_image(&mut new_img, new_strip, h, start_w);
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn right_to_left_sort(&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() - 1) {
            let mut strip = Vec::new();
            let mut start_w = self.io.in_img.width() - 1;
            strip.push(self.io.in_img.get_pixel(self.io.in_img.width() - 1, h));
            for w in 1..(self.io.in_img.width() - 1) {
                let previous_pixel = self.io.in_img.get_pixel(self.io.in_img.width() - w, h);
                let current_pixel = self.io.in_img.get_pixel(self.io.in_img.width() - 1 - w, h);
                if self.are_pixels_grouped(previous_pixel, current_pixel) {
                    strip.push(current_pixel);
                } else {
                    let new_strip = self.sort_strip(&mut strip);
                    self.prepend_strip_to_image(&mut new_img, new_strip, h, start_w);
                    start_w = self.io.in_img.width() - 1 - w;
                    strip = Vec::new();
                    strip.push(current_pixel);
                }
            }
            let new_strip = self.sort_strip(&mut strip);
            self.prepend_strip_to_image(&mut new_img, new_strip, h, start_w);
        }
        new_img.save(self.io.out_img).unwrap();
    }

    fn sort_strip<'b>(&self, strip: &'b mut Vec<image::Rgba<u8>>) -> &'b mut Vec<image::Rgba<u8>> {
        if self.sorting_by == 0 {
            self.sort_strip_by_hue(strip)
        } else {
            self.sort_strip_by_saturation(strip)
        }
    }

    fn sort_strip_by_hue<'b>(
        &self,
        strip: &'b mut Vec<image::Rgba<u8>>,
    ) -> &'b mut Vec<image::Rgba<u8>> {
        strip.sort_by(|a, b| {
            pixel_color::get_pixel_hue(*a)
                .partial_cmp(&pixel_color::get_pixel_hue(*b))
                .unwrap()
        });
        strip
    }

    fn sort_strip_by_saturation<'b>(
        &self,
        strip: &'b mut Vec<image::Rgba<u8>>,
    ) -> &'b mut Vec<image::Rgba<u8>> {
        strip.sort_by(|a, b| {
            pixel_color::get_pixel_saturation(*a)
                .partial_cmp(&pixel_color::get_pixel_saturation(*b))
                .unwrap()
        });
        strip
    }

    fn top_to_bottom_sort(&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() - 1) {
            let mut strip = Vec::new();
            let mut start_h = 0;
            strip.push(self.io.in_img.get_pixel(w, 0));
            for h in 1..(self.io.in_img.height() - 1) {
                let previous_pixel = self.io.in_img.get_pixel(w, h - 1);
                let current_pixel = self.io.in_img.get_pixel(w, h);
                if self.are_pixels_grouped(previous_pixel, current_pixel) {
                    strip.push(current_pixel);
                } else {
                    let new_strip = self.sort_strip(&mut strip);
                    self.append_strip_to_image_vertically(&mut new_img, new_strip, start_h, w);
                    start_h = h + 1;
                    strip = Vec::new();
                    strip.push(current_pixel);
                }
            }
            let new_strip = self.sort_strip(&mut strip);
            self.append_strip_to_image_vertically(&mut new_img, new_strip, start_h, w);
        }
        new_img.save(self.io.out_img).unwrap();
    }
}

impl<'a> PixelSorting for PixelSort<'a> {}