mirror of
https://github.com/Vomitblood/stort.git
synced 2025-03-26 16:51:00 +08:00
87 lines
3.2 KiB
Rust
87 lines
3.2 KiB
Rust
|
#[derive(Debug, PartialEq)]
|
||
|
enum ImageType {
|
||
|
Jpeg,
|
||
|
Png,
|
||
|
Gif,
|
||
|
WebP,
|
||
|
AnimatedWebP,
|
||
|
Unsupported,
|
||
|
}
|
||
|
|
||
|
/// function to interface with the tauri api on the javascript side
|
||
|
#[tauri::command]
|
||
|
pub fn process_wallpaper_image(file_path_string: String) -> Result<String, String> {
|
||
|
// convert the string to a path
|
||
|
let file_path = std::path::Path::new(&file_path_string);
|
||
|
|
||
|
// determine the image type
|
||
|
match determine_image_type(file_path) {
|
||
|
Ok(image_type) => match image_type {
|
||
|
ImageType::Jpeg => Ok("jpeg".to_string()),
|
||
|
ImageType::Png => Ok("png".to_string()),
|
||
|
ImageType::Gif => Ok("gif".to_string()),
|
||
|
ImageType::WebP => Ok("webp".to_string()),
|
||
|
ImageType::AnimatedWebP => Ok("webp".to_string()),
|
||
|
ImageType::Unsupported => {
|
||
|
Err("Unsupported image type (accepts webp, jpg, jpeg, png, gif)".to_string())
|
||
|
}
|
||
|
},
|
||
|
Err(e) => Err(format!("Error determining image type: {e}")),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// determines the image type of a file that is passed in using the filepath
|
||
|
fn determine_image_type(file_path: &std::path::Path) -> Result<ImageType, String> {
|
||
|
// open the file
|
||
|
let mut file =
|
||
|
std::fs::File::open(file_path).map_err(|e| format!("Failed to open file: {e}"))?;
|
||
|
|
||
|
// read the first few bytes to determine the format
|
||
|
let mut buffer = [0; 12];
|
||
|
std::io::Read::read_exact(&mut file, &mut buffer)
|
||
|
.map_err(|e| format!("Failed to read file: {e}"))?;
|
||
|
|
||
|
// with hopes and prayers, try to guess the format and pray that it is correct haha
|
||
|
match image::guess_format(&buffer) {
|
||
|
Ok(image::ImageFormat::Jpeg) => Ok(ImageType::Jpeg),
|
||
|
Ok(image::ImageFormat::Png) => Ok(ImageType::Png),
|
||
|
Ok(image::ImageFormat::Gif) => Ok(ImageType::Gif),
|
||
|
Ok(image::ImageFormat::WebP) => {
|
||
|
// additional check for webp
|
||
|
is_animated_webp(file_path).map(|animated| {
|
||
|
if animated {
|
||
|
ImageType::AnimatedWebP
|
||
|
} else {
|
||
|
ImageType::WebP
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
_ => Ok(ImageType::Unsupported),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// check if the file is a valid webp image and if it is animated
|
||
|
/// returns `Ok(true)` if it is animated, `Ok(false)` if it is not
|
||
|
/// and errors out if the file cannot be read or is not a webp
|
||
|
fn is_animated_webp(file_path: &std::path::Path) -> Result<bool, String> {
|
||
|
// open the file and read its contents into a buffer
|
||
|
let mut buffer = Vec::new();
|
||
|
std::fs::File::open(file_path)
|
||
|
.and_then(|mut file| std::io::Read::read_to_end(&mut file, &mut buffer))
|
||
|
.map_err(|e| format!("Failed to read file: {}", e))?;
|
||
|
|
||
|
// use the webp crate to decode the image and check for animation
|
||
|
webp::AnimDecoder::new(&buffer)
|
||
|
.decode()
|
||
|
.map(|anim| anim.has_animation())
|
||
|
.map_err(|_| "File is not a valid WebP image".to_string())
|
||
|
}
|
||
|
|
||
|
fn get_file_extension(file_path: &std::path::Path) -> Result<String, String> {
|
||
|
file_path
|
||
|
.extension()
|
||
|
.and_then(|extension| extension.to_str())
|
||
|
.map(|extension| extension.to_lowercase())
|
||
|
.ok_or_else(|| "Failed to get file extension".to_string())
|
||
|
}
|