diff options
Diffstat (limited to 'dichroism/src/image_service.rs')
-rw-r--r-- | dichroism/src/image_service.rs | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/dichroism/src/image_service.rs b/dichroism/src/image_service.rs new file mode 100644 index 0000000..b33d5c8 --- /dev/null +++ b/dichroism/src/image_service.rs @@ -0,0 +1,66 @@ +use crate::config::CONFIG_INSTANCE; +use crate::constants::{PHOTO_BASE_XY, PHOTO_FULLSIZE_XY, PHOTO_THUMBNAIL_XY}; +use crate::error::DichroismError; +use crate::models::{Photo, PhotoSet}; +use crate::result::Result; +use base64::decode; +use image::imageops::FilterType; +use image::DynamicImage; +use image::GenericImageView; +use once_cell::sync::Lazy; +use regex::Regex; +use std::path::PathBuf; +use uuid::Uuid; + +static DATA_URI_RE: Lazy<Regex> = Lazy::new(|| { + Regex::new("^data:image/(png|jpeg);base64,(?P<data>.+)") + .expect("Couldn't parse data URI Regex.") +}); + +// TODO: should be async so server threads don't block on FS access +pub fn generate_photo_set(uri: &str) -> Result<PhotoSet> { + 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(PhotoSet { + id: None, + original: generate_photo(&original)?, + fullsize: generate_photo(&fullsize)?, + base: generate_photo(&base)?, + thumbnail: generate_photo(&thumbnail)?, + }) +} + +pub fn generate_photo(image: &DynamicImage) -> Result<Photo> { + let base_name = Uuid::new_v3(&Uuid::NAMESPACE_OID, &image.to_bytes()) + .to_hyphenated() + .to_string(); + let mut path = PathBuf::from(&CONFIG_INSTANCE.img_root); + path.push(base_name); + path.set_extension("jpg"); + image.save(&path)?; + + let id = path + .file_name() + .ok_or(DichroismError::ImageWrite)? + .to_str() + .ok_or(DichroismError::ImageWrite)?; + Ok(Photo::new(String::from(id))) +} |