Add Preset type with 8 built-in presets and JSON serialization

All 5 preset tests passing.
This commit is contained in:
2026-03-06 01:42:35 +02:00
parent 715d8ab626
commit e7142604d4
2 changed files with 276 additions and 1 deletions

View File

@@ -1 +1,217 @@
// Preset management
use serde::{Deserialize, Serialize};
use crate::operations::*;
use crate::pipeline::ProcessingJob;
use crate::types::*;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Preset {
pub name: String,
pub description: String,
pub icon: String,
pub is_custom: bool,
pub resize: Option<ResizeConfig>,
pub rotation: Option<Rotation>,
pub flip: Option<Flip>,
pub convert: Option<ConvertConfig>,
pub compress: Option<CompressConfig>,
pub metadata: Option<MetadataConfig>,
pub watermark: Option<WatermarkConfig>,
pub rename: Option<RenameConfig>,
}
impl Preset {
pub fn to_job(
&self,
input_dir: impl Into<std::path::PathBuf>,
output_dir: impl Into<std::path::PathBuf>,
) -> ProcessingJob {
ProcessingJob {
input_dir: input_dir.into(),
output_dir: output_dir.into(),
sources: Vec::new(),
resize: self.resize.clone(),
rotation: self.rotation,
flip: self.flip,
convert: self.convert.clone(),
compress: self.compress.clone(),
metadata: self.metadata.clone(),
watermark: self.watermark.clone(),
rename: self.rename.clone(),
preserve_directory_structure: false,
}
}
pub fn all_builtins() -> Vec<Preset> {
vec![
Self::builtin_blog_photos(),
Self::builtin_social_media(),
Self::builtin_web_optimization(),
Self::builtin_email_friendly(),
Self::builtin_privacy_clean(),
Self::builtin_photographer_export(),
Self::builtin_archive_compress(),
Self::builtin_fediverse_ready(),
]
}
pub fn builtin_blog_photos() -> Preset {
Preset {
name: "Blog Photos".into(),
description: "Resize 1200px wide, JPEG quality High, strip all metadata".into(),
icon: "image-x-generic-symbolic".into(),
is_custom: false,
resize: Some(ResizeConfig::ByWidth(1200)),
rotation: None,
flip: None,
convert: None,
compress: Some(CompressConfig::Preset(QualityPreset::High)),
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: None,
}
}
pub fn builtin_social_media() -> Preset {
Preset {
name: "Social Media".into(),
description: "Resize to fit 1080x1080, compress Medium, strip metadata".into(),
icon: "system-users-symbolic".into(),
is_custom: false,
resize: Some(ResizeConfig::FitInBox {
max: Dimensions {
width: 1080,
height: 1080,
},
allow_upscale: false,
}),
rotation: None,
flip: None,
convert: None,
compress: Some(CompressConfig::Preset(QualityPreset::Medium)),
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: None,
}
}
pub fn builtin_web_optimization() -> Preset {
Preset {
name: "Web Optimization".into(),
description: "Convert to WebP, compress High, sequential rename".into(),
icon: "web-browser-symbolic".into(),
is_custom: false,
resize: None,
rotation: None,
flip: None,
convert: Some(ConvertConfig::SingleFormat(ImageFormat::WebP)),
compress: Some(CompressConfig::Preset(QualityPreset::High)),
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: Some(RenameConfig {
prefix: String::new(),
suffix: String::new(),
counter_start: 1,
counter_padding: 3,
template: None,
}),
}
}
pub fn builtin_email_friendly() -> Preset {
Preset {
name: "Email Friendly".into(),
description: "Resize 800px wide, JPEG quality Medium".into(),
icon: "mail-unread-symbolic".into(),
is_custom: false,
resize: Some(ResizeConfig::ByWidth(800)),
rotation: None,
flip: None,
convert: None,
compress: Some(CompressConfig::Preset(QualityPreset::Medium)),
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: None,
}
}
pub fn builtin_privacy_clean() -> Preset {
Preset {
name: "Privacy Clean".into(),
description: "Strip all metadata, no other changes".into(),
icon: "security-high-symbolic".into(),
is_custom: false,
resize: None,
rotation: None,
flip: None,
convert: None,
compress: None,
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: None,
}
}
pub fn builtin_photographer_export() -> Preset {
Preset {
name: "Photographer Export".into(),
description: "Resize 2048px, compress High, privacy metadata, rename by date".into(),
icon: "camera-photo-symbolic".into(),
is_custom: false,
resize: Some(ResizeConfig::ByWidth(2048)),
rotation: None,
flip: None,
convert: None,
compress: Some(CompressConfig::Preset(QualityPreset::High)),
metadata: Some(MetadataConfig::Privacy),
watermark: None,
rename: Some(RenameConfig {
prefix: String::new(),
suffix: String::new(),
counter_start: 1,
counter_padding: 4,
template: Some("{exif_date}_{name}_{counter:4}".into()),
}),
}
}
pub fn builtin_archive_compress() -> Preset {
Preset {
name: "Archive Compress".into(),
description: "Lossless compression, preserve metadata".into(),
icon: "folder-symbolic".into(),
is_custom: false,
resize: None,
rotation: None,
flip: None,
convert: None,
compress: Some(CompressConfig::Preset(QualityPreset::Maximum)),
metadata: Some(MetadataConfig::KeepAll),
watermark: None,
rename: None,
}
}
pub fn builtin_fediverse_ready() -> Preset {
Preset {
name: "Fediverse Ready".into(),
description: "Resize 1920x1080, convert to WebP, compress High, strip metadata".into(),
icon: "network-server-symbolic".into(),
is_custom: false,
resize: Some(ResizeConfig::FitInBox {
max: Dimensions {
width: 1920,
height: 1080,
},
allow_upscale: false,
}),
rotation: None,
flip: None,
convert: Some(ConvertConfig::SingleFormat(ImageFormat::WebP)),
compress: Some(CompressConfig::Preset(QualityPreset::High)),
metadata: Some(MetadataConfig::StripAll),
watermark: None,
rename: None,
}
}
}