added process wallpaper image tauri function

This commit is contained in:
Vomitblood 2024-08-08 03:09:31 +08:00
parent aafa0b9430
commit 69332f1655
5 changed files with 157 additions and 58 deletions

View file

@ -8,21 +8,6 @@ enum ImageType {
Unsupported, Unsupported,
} }
// fn process_image(file_path_string: String) -> Result<String, String> {
// // convert string to path to use in rust
// let file_path = std::path::Path::new(&file_path_string);
// // get the data directory path
// let data_dir = tauri::api::path::data_dir().ok_or("Failed to get data directory")?;
// let mut destination = data_dir.clone();
// // we can hardcode the file name since
// // 1. we are only dealing with one wallpaper image at a time
// // 2. we will be converting all images to the webp format
// destination.push("wallpaper.webp");
// // determine the file format
// }
/// determines the image type of a file that is passed in using the filepath /// 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> { fn determine_image_type(file_path: &std::path::Path) -> Result<ImageType, String> {
// open the file // open the file
@ -70,49 +55,58 @@ fn is_animated_webp(file_path: &std::path::Path) -> Result<bool, String> {
.map_err(|_| "File is not a valid WebP image".to_string()) .map_err(|_| "File is not a valid WebP image".to_string())
} }
/// crop static images (jpeg, png and still webp) to a maximum of 1280x800 and maintaining aspect ratio fn get_file_extension(file_path: &std::path::Path) -> Result<String, String> {
fn crop_static_image( file_path
file_path: &std::path::Path, .extension()
destination: &std::path::Path, .and_then(|extension| extension.to_str())
) -> Result<(), String> { .map(|extension| extension.to_lowercase())
let img = image::open(file_path).map_err(|e| format!("Failed to open image: {e}"))?; .ok_or_else(|| "Failed to get file extension".to_string())
let (width, height) = image::GenericImageView::dimensions(&img);
let resized_img = if width > 1280 || height > 800 {
img.resize(1280, 800, image::imageops::FilterType::Lanczos3)
} else {
img
};
let mut output_file = std::fs::File::create(destination)
.map_err(|e: std::io::Error| format!("Failed to create file: {e}"))?;
resized_img
.write_to(&mut output_file, image::ImageFormat::WebP)
.map_err(|e| format!("Failed to save image as WebP: {}", e))?;
Ok(())
} }
/// crop animated webp images /// function to interface with the tauri api on the javascript side
fn crop_animated_webp( fn process_wallpaper_image(file_path_string: String) -> Result<String, String> {
file_path: &std::path::Path, // convert the string to a path
destination: &std::path::Path, let file_path = std::path::Path::new(&file_path_string);
) -> Result<(), String> {
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))?;
let decoder = webp::AnimDecoder::new(&buffer); // determine the image type
let decoded = decoder match determine_image_type(file_path) {
.decode() Ok(image_type) => {
.map_err(|e| format!("Failed to decode WebP animation: {e}"))?; // convert the image type to a string extension for printing
let extension = match image_type {
ImageType::Jpeg => "jpeg",
ImageType::Png => "png",
ImageType::Gif => "gif",
ImageType::WebP => "webp",
ImageType::AnimatedWebP => "webp",
ImageType::Unsupported => "",
};
Ok(extension.to_string())
}
Err(e) => Err(format!("Error determining image type: {e}")),
}
} }
fn main() { fn main() {
// Example usage // Example usage
let path = std::path::Path::new("/home/vomitblood/Downloads/title.keys"); let path = std::path::Path::new("/home/vomitblood/Downloads/background.jpg");
match determine_image_type(path) { match determine_image_type(path) {
Ok(image_type) => println!("Image type: {:?}", image_type), Ok(image_type) => {
Err(e) => println!("Error determining image type: {}", e), // convert the image type to a string extension for printing
let extension = match image_type {
ImageType::Jpeg => "jpeg",
ImageType::Png => "png",
ImageType::Gif => "gif",
ImageType::WebP => "webp",
ImageType::AnimatedWebP => "webp",
ImageType::Unsupported => "",
};
println!("Image extension: {extension}");
}
Err(e) => println!("Error determining image type: {e}"),
}
match get_file_extension(path) {
Ok(extension) => println!("File extension: {extension}"),
Err(e) => println!("Error getting file extension: {e}"),
} }
} }

1
src-tauri/src/lib.rs Normal file
View file

@ -0,0 +1 @@
pub mod wallpaper;

View file

@ -1,8 +1,11 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!! // Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use app::wallpaper;
fn main() { fn main() {
tauri::Builder::default() tauri::Builder::default()
.invoke_handler(tauri::generate_handler![wallpaper::process_wallpaper_image])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
} }

View file

@ -0,0 +1,86 @@
#[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())
}

View file

@ -5,6 +5,7 @@ import { useState } from "react";
import { SettingsItem } from "../components/HeaderBar/Settings/SettingsItem"; import { SettingsItem } from "../components/HeaderBar/Settings/SettingsItem";
import { useSettings } from "../contexts/SettingsContext"; import { useSettings } from "../contexts/SettingsContext";
import { testing } from "../lib/testing"; import { testing } from "../lib/testing";
import { invoke } from "@tauri-apps/api/tauri";
export default function Testing() { export default function Testing() {
// contexts // contexts
@ -24,28 +25,42 @@ export default function Testing() {
> >
<BugReport /> <BugReport />
</IconButton> </IconButton>
<Button <button
onClick={() => { onClick={() => {
resetSettings(); resetSettings();
}} }}
> >
reset settings reset settings
</Button> </button>
<Button>update settings</Button> <button>update settings</button>
<Button <button
onClick={() => { onClick={() => {
console.log(settings); console.log(settings);
}} }}
> >
log settings log settings
</Button> </button>
<Button <button
onClick={() => { onClick={() => {
console.log(testing()); console.log(testing());
}} }}
> >
testing testing
</Button> </button>
<button
onClick={async () => {
try {
const bruh = await invoke("process_wallpaper_image", {
filePathString: "/home/vomitblood/Downloads/9fd62bc7_2024-08-07_7.csv",
});
console.log(bruh);
} catch (error) {
console.error("deec nuts", error);
}
}}
>
invoke tauri shit
</button>
<Typography>{text}</Typography> <Typography>{text}</Typography>
<SettingsItem <SettingsItem
defaultText="#8ab4f8" defaultText="#8ab4f8"