use poise::serenity_prelude as serenity; use crate::Data; use crate::error::{Error, Result}; use crate::lang; type Context<'a> = poise::Context<'a, Data, Error>; /// QR group #[poise::command(slash_command, subcommands("dekodowanie", "generowanie",))] pub async fn qr(_ctx: Context<'_>) -> Result<()> { Ok(()) } /// Generate a QR code from text #[poise::command(slash_command)] pub async fn generowanie( ctx: Context<'_>, #[description = "Zawartość kodu QR"] text: String, ) -> Result<()> { ctx.defer().await?; let code = qrcode::QrCode::new(text.as_bytes())?; let image = code.render::>().build(); let scaled = image::imageops::resize( &image, image.width() * 10, image.height() * 10, image::imageops::Nearest, ); let mut buf = std::io::Cursor::new(Vec::new()); scaled.write_to(&mut buf, image::ImageFormat::Png)?; ctx.send( poise::CreateReply::default() .content(lang::L_QR_GENERATED) .attachment(serenity::CreateAttachment::bytes( buf.into_inner(), "qrcode.png", )), ) .await?; Ok(()) } /// Decode a QR code from an uploaded image #[poise::command(slash_command)] pub async fn dekodowanie( ctx: Context<'_>, #[description = "Obraz zawierający kod QR"] image: serenity::Attachment, ) -> Result<()> { ctx.defer().await?; let img_data = ctx .data() .http_client .get(&image.url) .send() .await? .bytes() .await?; let img = image::load_from_memory(&img_data)?; let gray = img.to_luma8(); let decoded = decode_qr_simple(&gray); match decoded { Some(text) => { ctx.say(lang::fmt_qr_decoded(&text)).await?; } None => { ctx.say(lang::L_QR_DECODE_FAILED).await?; } } Ok(()) } fn decode_qr_simple(img: &image::ImageBuffer, Vec>) -> Option { rxing::helpers::detect_in_luma(img.as_raw().to_vec(), img.width(), img.height(), None) .ok() .map(|r| r.getText().to_owned()) } pub fn commands() -> Vec> { vec![qr()] }