1use std::path::Path;
2
3pub mod error;
4pub use error::ThumbsError;
5
6#[cfg(target_os = "macos")]
7pub mod platform;
8
9#[cfg(target_os = "windows")]
10pub mod platform;
11
12#[derive(Debug, Clone)]
18pub struct Thumbnail {
19 pub rgba: Vec<u8>,
21
22 pub width: u32,
24
25 pub height: u32,
27}
28
29impl Thumbnail {
30 pub fn new(rgba: Vec<u8>, width: u32, height: u32) -> Self {
35 assert_eq!(
36 rgba.len(),
37 (width as usize) * (height as usize) * 4,
38 "rgba length must be width * height * 4"
39 );
40 Self {
41 rgba,
42 width,
43 height,
44 }
45 }
46}
47
48const BASE_PX: u32 = 256;
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54pub struct ThumbnailScale(pub u32);
55
56impl Default for ThumbnailScale {
57 fn default() -> Self {
58 Self(1)
59 }
60}
61
62impl ThumbnailScale {
63 pub fn px(&self) -> u32 {
65 self.0 * BASE_PX
66 }
67}
68
69pub fn get_thumbnail<P: AsRef<Path>>(
85 file_path: P,
86 scale: ThumbnailScale,
87) -> Result<Thumbnail, ThumbsError> {
88 let file_path = file_path.as_ref();
89
90 if !file_path.exists() {
91 return Err(ThumbsError::FileNotFound(file_path.display().to_string()));
92 }
93
94 #[cfg(target_os = "macos")]
95 {
96 platform::macos::generate_thumbnail(file_path, scale)
97 }
98
99 #[cfg(target_os = "windows")]
100 {
101 platform::windows::generate_thumbnail(file_path, scale)
102 }
103
104 #[cfg(not(any(target_os = "macos", target_os = "windows")))]
105 {
106 Err(ThumbsError::PlatformNotSupported)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_thumbnail_scale_default() {
116 let scale = ThumbnailScale::default();
117 assert_eq!(scale.0, 1);
118 assert_eq!(scale.px(), 256);
119 }
120
121 #[test]
122 fn test_thumbnail_scale_multiplier() {
123 let scale = ThumbnailScale(2);
124 assert_eq!(scale.px(), 512);
125 }
126
127 #[test]
128 fn test_thumbnail_new_valid() {
129 let rgba = vec![0u8; 256 * 256 * 4];
130 let thumb = Thumbnail::new(rgba, 256, 256);
131 assert_eq!(thumb.width, 256);
132 assert_eq!(thumb.height, 256);
133 }
134
135 #[test]
136 #[should_panic(expected = "rgba length must be")]
137 fn test_thumbnail_new_invalid_size() {
138 let rgba = vec![0u8; 100];
139 Thumbnail::new(rgba, 256, 256);
140 }
141}