use std::path::Path;
use anyhow::{bail, Context, Result};
use image::{DynamicImage, GenericImageView, ImageReader};
use super::types::Wallpaper;
use super::ventura::get_ventura_wallpaper;
const SUPPORTED_EXTENSIONS: &[&str] = &["png", "jpg", "jpeg", "tga"];
pub fn validate_wallpaper_dimensions(
image: &DynamicImage,
terminal_width: u32,
terminal_height: u32,
padding: u32,
) -> Result<()> {
let (wp_width, wp_height) = image.dimensions();
let min_width = terminal_width + (padding * 2);
let min_height = terminal_height + (padding * 2);
if wp_width < min_width || wp_height < min_height {
bail!(
"Wallpaper resolution {}x{} is too small.\n\
Required: at least {}x{} (terminal {}x{} + {}px padding on each side).\n\
Please use a larger wallpaper image or reduce the terminal size/padding.",
wp_width,
wp_height,
min_width,
min_height,
terminal_width,
terminal_height,
padding
);
}
Ok(())
}
pub fn resolve_wallpaper(
wallpaper: &Wallpaper,
terminal_width: u32,
terminal_height: u32,
padding: u32,
) -> Result<DynamicImage> {
let image = match wallpaper {
Wallpaper::Ventura => get_ventura_wallpaper().clone(),
Wallpaper::Custom(path) => load_wallpaper_from_path(path.as_path())?,
};
validate_wallpaper_dimensions(&image, terminal_width, terminal_height, padding)?;
Ok(image)
}
fn load_wallpaper_from_path(path: &Path) -> Result<DynamicImage> {
if !path.exists() {
bail!("Wallpaper file not found: {}", path.display());
}
if !path.is_file() {
bail!("Wallpaper path is not a file: {}", path.display());
}
let extension = path
.extension()
.and_then(|e| e.to_str())
.map(|e| e.to_lowercase())
.unwrap_or_default();
if !SUPPORTED_EXTENSIONS.contains(&extension.as_str()) {
bail!(
"Unsupported wallpaper format '{}'. Supported formats: {}",
extension,
SUPPORTED_EXTENSIONS.join(", ")
);
}
ImageReader::open(path)
.with_context(|| format!("Failed to open wallpaper file: {}", path.display()))?
.with_guessed_format()
.with_context(|| "Failed to detect wallpaper image format")?
.decode()
.with_context(|| format!("Failed to decode wallpaper image: {}", path.display()))
}
#[cfg(not(feature = "cli"))]
pub fn load_and_validate_wallpaper(
path: &Path,
terminal_width: u32,
terminal_height: u32,
padding: u32,
) -> Result<DynamicImage> {
let image = load_wallpaper_from_path(path)?;
validate_wallpaper_dimensions(&image, terminal_width, terminal_height, padding)?;
Ok(image)
}
#[cfg(test)]
mod tests {
fn is_builtin_wallpaper(value: &str) -> bool {
value.eq_ignore_ascii_case("ventura")
}
#[test]
fn test_is_builtin_wallpaper() {
assert!(is_builtin_wallpaper("ventura"));
assert!(is_builtin_wallpaper("Ventura"));
assert!(is_builtin_wallpaper("VENTURA"));
assert!(!is_builtin_wallpaper("/path/to/file.png"));
assert!(!is_builtin_wallpaper("./wallpaper.jpg"));
assert!(!is_builtin_wallpaper("custom"));
}
}