stitchy_core/files/
path.rs1use crate::{FileLocation, FileProperties};
2use image::{metadata::Orientation, DynamicImage, ImageFormat};
3
4use std::ffi::OsStr;
5use std::fs::File;
6use std::io::BufReader;
7use std::path::{Path, PathBuf};
8use std::time::SystemTime;
9
10#[derive(Debug)]
14pub struct FilePathWithMetadata {
15 full_path: String,
16 modify_time: SystemTime,
17 size_bytes: u64,
18}
19
20impl Default for FilePathWithMetadata {
21 fn default() -> Self {
22 Self {
23 full_path: "".to_owned(),
24 modify_time: SystemTime::now(),
25 size_bytes: 0,
26 }
27 }
28}
29
30impl FileProperties for FilePathWithMetadata {
31 fn infer_format(&self) -> Option<ImageFormat> {
32 match self.full_path.rfind('.') {
33 Some(pos) => {
34 let extension = &self.full_path[pos..self.full_path.len()];
35 for &(ext, fmt) in crate::files::util::extension_formats().iter() {
36 if ext == extension {
37 return Some(fmt);
38 }
39 }
40 None
41 }
42 None => None,
43 }
44 }
45
46 fn into_image_contents(self, print_info: bool) -> Result<DynamicImage, String> {
47 let path = Path::new(&self.full_path);
48 let image = image::open(path).map_err(|e| format!("Failed to open {:?}: {:?}", path, e))?;
49
50 if print_info {
51 if let Some(file_name) = path.file_name() {
52 let w = image.width();
53 let h = image.height();
54 println!(
55 "Path: {}, w: {}, h: {}, {}",
56 file_name.to_str().unwrap(),
57 w,
58 h,
59 crate::util::make_size_string(self.size_bytes)
60 );
61 }
62 }
63
64 Ok(image)
65 }
66
67 #[inline]
68 fn file_size(&self) -> u64 {
69 self.size_bytes
70 }
71
72 #[inline]
73 fn modify_time(&self) -> SystemTime {
74 self.modify_time
75 }
76
77 #[inline]
78 fn full_path(&self) -> Option<&String> {
79 Some(&self.full_path)
80 }
81
82 fn orientation(&self) -> Result<Orientation, String> {
83 let file = File::open(&self.full_path)
84 .map_err(|e| format!("Cannot open file {}: {:?}", &self.full_path, e))?;
85 let reader = BufReader::new(file);
86 self.decode_orientation(reader)
87 }
88}
89
90#[derive(Default, Debug)]
92pub struct FilePath {
93 path: PathBuf,
94}
95
96impl FilePath {
97 pub fn new(path: PathBuf) -> Self {
98 Self { path }
99 }
100}
101
102impl FileLocation<FilePathWithMetadata> for FilePath {
103 fn is_file(&self) -> Result<bool, String> {
104 let path_buf = PathBuf::from(&self.path);
105 Ok(path_buf.is_file())
106 }
107
108 fn extension(&self) -> Result<String, String> {
109 let path_buf = PathBuf::from(&self.path);
110 path_buf
111 .extension()
112 .unwrap_or(OsStr::new(""))
113 .to_ascii_lowercase()
114 .into_string()
115 .map_err(|o| format!("Error reading file extension, found {:?}", o))
116 }
117
118 fn into_properties(self) -> Result<FilePathWithMetadata, String> {
119 let metadata = self
121 .path
122 .metadata()
123 .map_err(|_| format!("Failed reading metadata for: {:?}", self.path))?;
124 let modify_time = metadata
125 .modified()
126 .map_err(|_| format!("Failed reading modify date for: {:?}", self.path))?;
127 let size_bytes = metadata.len();
128
129 let path_string = match self.path.to_str() {
131 Some(s) => s.to_owned(),
132 None => return Err(format!("Failed converting to string: {:?}", self.path)),
133 };
134 let properties = FilePathWithMetadata {
135 full_path: path_string,
136 modify_time,
137 size_bytes,
138 };
139 Ok(properties)
140 }
141}