use super::photo::Photo; use crate::constants::{PHOTO_BASE_XY, PHOTO_FULLSIZE_XY, PHOTO_THUMBNAIL_XY}; use crate::error::DichroismError; use crate::result::Result; use base64::decode; use image::imageops::FilterType; use image::GenericImageView; use once_cell::sync::Lazy; use regex::Regex; static DATA_URI_RE: Lazy = Lazy::new(|| { Regex::new("^data:image/(png|jpeg);base64,(?P.+)") .expect("Couldn't parse data URI Regex.") }); pub struct PhotoSet { pub original: Photo, // original, just for safe-keeping pub fullsize: Photo, // full-size, "zoomed" view pub base: Photo, // basic viewing pub thumbnail: Photo, // tiny, square thumbnail } impl PhotoSet { pub fn from_photos(original: Photo, fullsize: Photo, base: Photo, thumbnail: Photo) -> Self { Self { original, fullsize, base, thumbnail, } } pub fn from_data_uri(uri: &str) -> Result { let data = DATA_URI_RE .captures(uri) .ok_or(DichroismError::UriDataExtract)? .name("data") .ok_or(DichroismError::UriDataExtract)? .as_str(); let original = image::load_from_memory(&decode(data)?)?; let fullsize = original.resize(PHOTO_FULLSIZE_XY, PHOTO_FULLSIZE_XY, FilterType::Lanczos3); let base = original.resize(PHOTO_BASE_XY, PHOTO_BASE_XY, FilterType::Lanczos3); let (width, height) = original.dimensions(); let thumbnail = if width > height { let offset = (width - height) / 2; original.crop_imm(offset, 0, width - offset * 2, height) } else { let offset = (height - width) / 2; original.crop_imm(0, offset, width, height - offset * 2) } .resize(PHOTO_THUMBNAIL_XY, PHOTO_THUMBNAIL_XY, FilterType::Lanczos3); Ok(Self { original: Photo::from_image(&original)?, fullsize: Photo::from_image(&fullsize)?, base: Photo::from_image(&base)?, thumbnail: Photo::from_image(&thumbnail)?, }) } }