From 61bbec5aa6715707e59dffa6eefef7ea1e1d17a2 Mon Sep 17 00:00:00 2001 From: Joey Hines Date: Thu, 17 Apr 2025 21:33:27 -0600 Subject: [PATCH] Add green_screen co --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/discord/mod.rs | 1 + src/discord/motivate.rs | 125 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 125 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59b5ff7..e41d29a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1080,7 +1080,7 @@ dependencies = [ [[package]] name = "fren" -version = "1.2.0" +version = "1.3.0" dependencies = [ "axum 0.8.1", "base64 0.22.1", diff --git a/Cargo.toml b/Cargo.toml index 33d1bf4..4760391 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fren" -version = "1.2.0" +version = "1.3.0" edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/src/discord/mod.rs b/src/discord/mod.rs index b52675b..ed63c12 100644 --- a/src/discord/mod.rs +++ b/src/discord/mod.rs @@ -304,6 +304,7 @@ pub async fn run_bot(global_data: GlobalData) { little_fren::play(), motivate::motivation(), motivate::motivation_add_album(), + motivate::green_screen(), role::list_roles(), role::join_role(), role::leave_role(), diff --git a/src/discord/motivate.rs b/src/discord/motivate.rs index 1b7f3f0..0cd6878 100644 --- a/src/discord/motivate.rs +++ b/src/discord/motivate.rs @@ -1,12 +1,79 @@ -use crate::album_manager::AlbumQuery; +use crate::album_manager::{AlbumQuery, ImageQuery, ImageSort}; use crate::discord::Context; use crate::error::Error; use crate::models::motivation::{Motivation, MotivationConfig}; -use magick_rust::{DrawingWand, MagickWand, PixelWand}; +use magick_rust::{CompositeOperator, DrawingWand, FilterType, MagickWand, PixelWand}; use poise::serenity_prelude::builder::{CreateAttachment, CreateMessage}; -use reqwest::Client; +use reqwest::{Client, Url}; use std::borrow::Cow; +pub async fn create_greenscreen_image( + background_image_url: Url, + foreground_image_url: Url, +) -> Result, Error> { + let client = Client::new(); + + let background_image_blob = client + .get(background_image_url) + .send() + .await? + .bytes() + .await? + .to_vec(); + + let foreground_image_blob = client + .get(foreground_image_url) + .send() + .await? + .bytes() + .await? + .to_vec(); + + let background_wand = MagickWand::new(); + let foreground_wand = MagickWand::new(); + + background_wand.read_image_blob(background_image_blob)?; + foreground_wand.read_image_blob(foreground_image_blob)?; + + let background_height = background_wand.get_image_height(); + let background_width = background_wand.get_image_width(); + + let foreground_height = foreground_wand.get_image_height(); + let foreground_width = foreground_wand.get_image_width(); + + let (scale_height, scale_width) = + if foreground_height > background_height && foreground_width > background_width { + ( + background_height as f64 / foreground_height as f64, + background_width as f64 / foreground_width as f64, + ) + } else if foreground_height > background_height { + let scale = background_height as f64 / foreground_height as f64; + + (scale, scale) + } else if foreground_width > background_width { + let scale = background_width as f64 / foreground_width as f64; + + (scale, scale) + } else { + (1.0, 1.0) + }; + + foreground_wand.scale_image(scale_width, scale_height, FilterType::Lanczos2)?; + + let pos_x = background_width / 2 - foreground_wand.get_image_width() / 2; + let pos_y = background_height / 2 - foreground_wand.get_image_height() / 2; + background_wand.compose_images( + &foreground_wand, + CompositeOperator::Atop, + true, + pos_x as isize, + pos_y as isize, + )?; + + Ok(background_wand.write_image_blob("jpg")?) +} + pub async fn create_motivation_image(motivation: Motivation) -> Result, Error> { let client = Client::new(); @@ -88,6 +155,58 @@ pub async fn motivation( Ok(()) } +/// Greenscreen your friends! +#[poise::command(prefix_command, category = "Motivation")] +pub async fn green_screen( + ctx: Context<'_>, + #[description = "Album to use as the foreground image"] foreground: Option, + #[description = "Album to use for the background image"] background: Option, +) -> Result<(), Error> { + let foreground = ctx + .data() + .picox + .query_image(ImageQuery { + album: foreground, + tags: vec![], + order: ImageSort::Random, + limit: 1, + }) + .await? + .first() + .cloned() + .unwrap(); + + let background = ctx + .data() + .picox + .query_image(ImageQuery { + album: background, + tags: vec![], + order: ImageSort::Random, + limit: 1, + }) + .await? + .first() + .cloned() + .unwrap(); + + let image = create_greenscreen_image(background.link.clone(), foreground.link.clone()).await?; + + ctx.channel_id() + .send_message( + &ctx, + CreateMessage::new() + .content("i am photoshop pro:") + .add_file(CreateAttachment::bytes( + Cow::from(image), + "greenscreen.jpg".to_string(), + )), + ) + .await?; + + Ok(()) +} + /// Add an album to the pool of images to be used for motivations #[poise::command(prefix_command, category = "Motivation")] pub async fn motivation_add_album(