From 0f37df7ed4800103406fb89af850a9f71779296d Mon Sep 17 00:00:00 2001 From: John Lewis Date: Fri, 1 Mar 2024 11:46:48 -0600 Subject: [PATCH 1/5] chore: create watermark module --- crates/bl/src/upload/watermark.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 crates/bl/src/upload/watermark.rs diff --git a/crates/bl/src/upload/watermark.rs b/crates/bl/src/upload/watermark.rs new file mode 100644 index 0000000..e69de29 From 5c1d46cba46d3674da194235689a6ec75dfb4717 Mon Sep 17 00:00:00 2001 From: John Lewis Date: Fri, 1 Mar 2024 11:47:33 -0600 Subject: [PATCH 2/5] chore: move upload module to directory --- crates/bl/src/{upload.rs => upload/mod.rs} | 2 ++ 1 file changed, 2 insertions(+) rename crates/bl/src/{upload.rs => upload/mod.rs} (99%) diff --git a/crates/bl/src/upload.rs b/crates/bl/src/upload/mod.rs similarity index 99% rename from crates/bl/src/upload.rs rename to crates/bl/src/upload/mod.rs index 1b5886e..8473cb0 100644 --- a/crates/bl/src/upload.rs +++ b/crates/bl/src/upload/mod.rs @@ -1,3 +1,5 @@ +mod watermark; + use std::collections::HashMap; #[cfg(feature = "ssr")] From 1db3980c8c54f8febd9fa024ff4b0aa2f87c2d47 Mon Sep 17 00:00:00 2001 From: John Lewis Date: Fri, 1 Mar 2024 12:35:28 -0600 Subject: [PATCH 3/5] feat: first attempt at watermark --- crates/bl/assets/watermark.png | Bin 0 -> 6605 bytes crates/bl/assets/watermark.xcf | Bin 0 -> 6579 bytes crates/bl/src/upload/mod.rs | 5 ++++- crates/bl/src/upload/watermark.rs | 29 +++++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 crates/bl/assets/watermark.png create mode 100644 crates/bl/assets/watermark.xcf diff --git a/crates/bl/assets/watermark.png b/crates/bl/assets/watermark.png new file mode 100644 index 0000000000000000000000000000000000000000..ef15f55c86920fe30a971c0b648a2307c61640c6 GIT binary patch literal 6605 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 literal 0 HcmV?d00001 diff --git a/crates/bl/src/upload/mod.rs b/crates/bl/src/upload/mod.rs index 8473cb0..d95b330 100644 --- a/crates/bl/src/upload/mod.rs +++ b/crates/bl/src/upload/mod.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "ssr")] mod watermark; use std::collections::HashMap; @@ -171,11 +172,13 @@ async fn create_photo(img: image::DynamicImage) -> Result { let thumbnail_size = thumbnail_size(aspect_ratio); // create thumbnail - let thumbnail_image = img.resize_exact( + let mut thumbnail_image = img.resize_exact( thumbnail_size.0, thumbnail_size.1, image::imageops::FilterType::Lanczos3, ); + // apply watermark + watermark::apply_watermark(&mut thumbnail_image); // encode thumbnail image as jpeg let mut thumbnail_bytes = Vec::new(); diff --git a/crates/bl/src/upload/watermark.rs b/crates/bl/src/upload/watermark.rs index e69de29..7ded496 100644 --- a/crates/bl/src/upload/watermark.rs +++ b/crates/bl/src/upload/watermark.rs @@ -0,0 +1,29 @@ +use image::{DynamicImage, GenericImage, GenericImageView, Rgba}; + +fn create_watermark(width: u32, height: u32) -> image::RgbaImage { + // load the watermark image from bytes which is a transparent 200x200 pixels + // image + let watermark_bytes = include_bytes!("../../assets/watermark.png"); + let watermark = image::load_from_memory(watermark_bytes).unwrap(); + + // center the watermark inside an image of the correct size + let mut watermark_image = image::RgbaImage::new(width, height); + let (watermark_width, watermark_height) = watermark.dimensions(); + let x = (width - watermark_width) / 2; + let y = (height - watermark_height) / 2; + watermark_image.copy_from(&watermark, x, y).unwrap(); + + watermark_image +} + +pub fn apply_watermark(target: &mut DynamicImage) { + // create the watermark image + let (width, height) = target.dimensions(); + let watermark = create_watermark(width, height); + let watermark = DynamicImage::ImageRgba8(watermark); + + // blend the watermark onto the target image + for (x, y, pixel) in watermark.pixels() { + target.put_pixel(x, y, pixel); + } +} From eaa8c846cc26f2f3c585400672a82431a426cc86 Mon Sep 17 00:00:00 2001 From: John Lewis Date: Fri, 1 Mar 2024 12:40:12 -0600 Subject: [PATCH 4/5] fix: avoid panicking when resizing --- crates/bl/src/upload/watermark.rs | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/crates/bl/src/upload/watermark.rs b/crates/bl/src/upload/watermark.rs index 7ded496..1fbb5f4 100644 --- a/crates/bl/src/upload/watermark.rs +++ b/crates/bl/src/upload/watermark.rs @@ -1,4 +1,4 @@ -use image::{DynamicImage, GenericImage, GenericImageView, Rgba}; +use image::{DynamicImage, GenericImage, GenericImageView}; fn create_watermark(width: u32, height: u32) -> image::RgbaImage { // load the watermark image from bytes which is a transparent 200x200 pixels @@ -6,14 +6,22 @@ fn create_watermark(width: u32, height: u32) -> image::RgbaImage { let watermark_bytes = include_bytes!("../../assets/watermark.png"); let watermark = image::load_from_memory(watermark_bytes).unwrap(); - // center the watermark inside an image of the correct size - let mut watermark_image = image::RgbaImage::new(width, height); - let (watermark_width, watermark_height) = watermark.dimensions(); - let x = (width - watermark_width) / 2; - let y = (height - watermark_height) / 2; - watermark_image.copy_from(&watermark, x, y).unwrap(); + // center the watermark inside an image of the correct size, or if it's too + // large, scale it down + let (w, h) = watermark.dimensions(); + let (w, h) = if w > width || h > height { + let scale = (width as f32 / w as f32).min(height as f32 / h as f32); + (w as f32 * scale, h as f32 * scale) + } else { + (w as f32, h as f32) + }; + let watermark = watermark.resize_exact( + w as u32, + h as u32, + image::imageops::FilterType::Lanczos3, + ); - watermark_image + watermark.into() } pub fn apply_watermark(target: &mut DynamicImage) { From a34f70d3f69d04c63d314afd5f2b5cad7f5731f8 Mon Sep 17 00:00:00 2001 From: John Lewis Date: Fri, 1 Mar 2024 12:48:41 -0600 Subject: [PATCH 5/5] fix: center and correctly blend watermark --- crates/bl/src/upload/watermark.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/crates/bl/src/upload/watermark.rs b/crates/bl/src/upload/watermark.rs index 1fbb5f4..8aacfbb 100644 --- a/crates/bl/src/upload/watermark.rs +++ b/crates/bl/src/upload/watermark.rs @@ -1,6 +1,6 @@ -use image::{DynamicImage, GenericImage, GenericImageView}; +use image::{DynamicImage, GenericImageView}; -fn create_watermark(width: u32, height: u32) -> image::RgbaImage { +fn create_watermark(width: u32, height: u32) -> image::DynamicImage { // load the watermark image from bytes which is a transparent 200x200 pixels // image let watermark_bytes = include_bytes!("../../assets/watermark.png"); @@ -20,18 +20,25 @@ fn create_watermark(width: u32, height: u32) -> image::RgbaImage { h as u32, image::imageops::FilterType::Lanczos3, ); + // center the watermark + let x = (width - w as u32) / 2; + let y = (height - h as u32) / 2; + let mut final_watermark = image::RgbaImage::new(width, height); + image::imageops::overlay( + &mut final_watermark, + &watermark.to_rgba8(), + x.into(), + y.into(), + ); - watermark.into() + DynamicImage::ImageRgba8(final_watermark) } pub fn apply_watermark(target: &mut DynamicImage) { // create the watermark image let (width, height) = target.dimensions(); let watermark = create_watermark(width, height); - let watermark = DynamicImage::ImageRgba8(watermark); // blend the watermark onto the target image - for (x, y, pixel) in watermark.pixels() { - target.put_pixel(x, y, pixel); - } + image::imageops::overlay(target, &watermark, 0, 0); }