1use std::{path::Path, fs::File, io::Read, collections::hash_map::DefaultHasher, hash::{Hash, Hasher}};
2
3use image::{ColorType, GenericImageView, imageops::FilterType};
4use rand::prelude::SliceRandom;
5
6use crate::{ImageReturn, utils, create_path_with_hash};
7
8#[derive(Debug)]
9pub enum Apply<'a> {
10 FlipV,
12 FlipH,
13 Contrast(f32),
14 Resize(u32, u32),
15 CenterCrop(u32, u32),
16 Encode,
17 GetVec(&'a mut Vec<u8>),
18 GetImgRet(&'a mut ImageReturn),
19 SaveTo(&'a str),
20}
21
22pub struct Transforms<'a> {
23 applies: Vec<Apply<'a>>,
24 shuffle: bool,
25}
26
27impl <'a>Transforms<'a> {
28 pub fn new(applies: Vec<Apply<'a>>) -> Transforms<'a> {
29 Transforms {
30 applies,
31 shuffle: false,
32 }
33 }
34 pub fn shuffle(mut self) -> Self {
35 self.shuffle = !self.shuffle;
36 self
37 }
38
39 pub fn apply<P: AsRef<Path>>(&mut self, path: P) -> Result<(), std::io::Error> {
40 let (found_in, mut exact_paths) = utils::get_paths(path)?;
41
42 let mut rng = rand::thread_rng();
43
44 if self.shuffle {
45 exact_paths.shuffle(&mut rng);
46 }
47
48 let mut channels = Vec::new();
49 let mut dims = Vec::new();
50
51 let image_count = exact_paths.len();
52
53 let mut img_encode = false;
54
55 for (idx, image_path) in exact_paths.iter().enumerate() {
56 match image::open(image_path) {
57 Ok(mut img) => {
58 match img.color() {
59 ColorType::L8 => channels.push(1),
60 ColorType::La8 => channels.push(1),
61 ColorType::Rgb8 => channels.push(3),
62 ColorType::Rgba8 => channels.push(3),
63 _ => continue,
64 }
65 for apply in self.applies.iter_mut() {
66 match apply {
67 Apply::FlipV => img = img.flipv(),
68 Apply::FlipH => img = img.flipv(),
69 Apply::Contrast(c) => img = img.adjust_contrast(*c),
70 Apply::Resize(w, h) => img = img.resize_exact(*w, *h, FilterType::CatmullRom),
71 Apply::GetVec(vec) => {
72 vec.extend_from_slice(img.as_bytes());
73 },
74 Apply::SaveTo(p) => {
75 let mut hasher = DefaultHasher::default();
76 img.as_bytes().hash(&mut hasher);
77 let hash = hasher.finish();
78
79 let path = create_path_with_hash(image_path, p, hash)?;
80 std::fs::create_dir_all(path.parent().unwrap())?;
82 img.save(&path).unwrap();
83 },
84 Apply::GetImgRet(img_ret) => {
85
86 if img_encode {
87 let mut from_encoder = Vec::new();
88 let mut file = File::open(image_path).unwrap();
89 file.read_to_end(&mut from_encoder).unwrap();
90 img_ret.data.append(&mut from_encoder);
91 } else {
92 img_ret.data.extend_from_slice(img.as_bytes());
93 };
94
95 if idx == image_count-1 {
96 **img_ret = ImageReturn {
97 found_in: found_in.clone(),
98 exact_paths: exact_paths.clone(),
99 data: img_ret.data.clone(),
100 channels: channels.clone(),
101 dims: dims.clone(),
102 }
103 }
104 },
105 Apply::Encode => img_encode = true,
106 Apply::CenterCrop(nw, nh) => {
107 let (width, height) = img.dimensions();
108
109 let subtract_w = width - *nw;
110 let subtract_h = height - *nh;
111
112 img = img.crop_imm(subtract_w/2, subtract_h/2, width-subtract_w, height-subtract_h);
113 },
114 }
115 }
116 let img_dims = img.dimensions();
117 dims.push((img_dims.0 as usize, img_dims.1 as usize));
118 },
119 Err(_) => continue,
120 }
121 }
122
123 Ok(())
124 }
125}