From 6038240d5ab4a600c4f17d861ed8b6ca78a15c3e Mon Sep 17 00:00:00 2001 From: Seoxi Ryouko Date: Thu, 22 May 2025 09:41:06 -0500 Subject: [PATCH] Porting to tiny_skia: art and avatar working --- src/avatar_mask.png | Bin 4184 -> 4488 bytes src/img.rs | 15 +++++++++++++++ src/main.rs | 41 ++++++++++++++++++++++++++++++++--------- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/src/avatar_mask.png b/src/avatar_mask.png index 64372655969e317a658c5836db0d680e65d84f1b..655455bd8e50fb006a8ec3b8fd995dca58cdc95c 100644 GIT binary patch literal 4488 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 Bq80!E diff --git a/src/img.rs b/src/img.rs index 7d319ad..316bf46 100644 --- a/src/img.rs +++ b/src/img.rs @@ -1,6 +1,7 @@ use image::{RgbaImage, ExtendedColorType, ImageEncoder, load_from_memory}; use image::codecs::png::PngEncoder; +use tiny_skia::{Pixmap, Transform, PixmapPaint, BlendMode, FilterQuality}; pub fn save_to_memory_png(p: &RgbaImage) -> Result, String> { let (width, height) = p.dimensions(); @@ -19,3 +20,17 @@ pub fn ensure_32_bit_png(p: &[u8]) -> Result, String> { }; save_to_memory_png(&img.into_rgba8()) } + +pub fn scale_skia_pixmap(p: Pixmap, width: u32, height: u32) -> Option { + let mut new_pixmap = Pixmap::new(width, height)?; + let width_scale = width as f32 / p.width() as f32; + let height_scale = height as f32 / p.width() as f32; + let matrix = Transform::from_scale(width_scale, height_scale); + let pixmap_paint = PixmapPaint { + opacity: 1.0, + blend_mode: BlendMode::Source, + quality: FilterQuality::Bilinear, + }; + new_pixmap.draw_pixmap(0, 0, p.as_ref(), &pixmap_paint, matrix, None); + Some(new_pixmap) +} diff --git a/src/main.rs b/src/main.rs index 64bba08..9f8c8fe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -125,7 +125,9 @@ fn parse_cielab(s: String) -> Result<(f32, f32, f32), &'static str> { const FMI_WIDTH: u32 = 548; const FMI_HEIGHT: u32 = 147; -const FMI_GAP: i32 = 12; +const FMI_GAP: u32 = 12; +const FMI_AVATAR_SIZE: u32 = 64; +const FMI_AVATAR_GAP: u32 = 10; async fn fmi(ctx: &Context, arg: &str, id: UserId, avatar: Option) -> Reply { let lastfm_user = match arg { @@ -168,16 +170,24 @@ async fn fmi(ctx: &Context, arg: &str, id: UserId, avatar: Option) -> Re let mask_wand = MagickWand::new(); let text_image_wand = MagickWand::new();*/ let mut main_image = handle_option!(tiny_skia::Pixmap::new(FMI_WIDTH, FMI_HEIGHT), "Failed to load main image"); - let album_image = handle_result!(tiny_skia::Pixmap::decode_png(&image_base), "Failed to load album art image"); + let mut album_image = handle_result!(tiny_skia::Pixmap::decode_png(&image_base), "Failed to load album art image"); //let album_image = handle_result!(tiny_skia::Pixmap::decode_png(&image_rgba8), "Failed to decode album art"); - let art_size = (FMI_HEIGHT as i32 - 2_i32 * FMI_GAP) as f32 / 300.0; - let scale_matrix = tiny_skia::Transform::from_scale(art_size, art_size); - let paint = tiny_skia::PixmapPaint { - opacity: 1.0, + let color_paint = tiny_skia::Paint { + shader: tiny_skia::Shader::SolidColor(tiny_skia::Color::WHITE), + anti_alias: true, blend_mode: tiny_skia::BlendMode::Source, + force_hq_pipeline: false, + }; + main_image.fill_rect(tiny_skia::Rect::from_xywh(0.0, 0.0, FMI_WIDTH as f32, FMI_HEIGHT as f32).unwrap(), &color_paint, tiny_skia::Transform::identity(), None); + let art_size = FMI_HEIGHT- 2 * FMI_GAP; + album_image = handle_option!(img::scale_skia_pixmap(album_image, art_size, art_size), "Failed to scale bitmap"); + //let art_scale_matrix = tiny_skia::Transform::from_transla(art_size, art_size).pre_translate(FMI_GAP as f32, FMI_GAP as f32); + let source_paint = tiny_skia::PixmapPaint { + opacity: 1.0, + blend_mode: tiny_skia::BlendMode::SourceOver, quality: tiny_skia::FilterQuality::Bilinear, }; - main_image.draw_pixmap(FMI_GAP, FMI_GAP, album_image.as_ref(), &paint, scale_matrix, None); + main_image.draw_pixmap(FMI_GAP as i32, FMI_GAP as i32, album_image.as_ref(), &source_paint, tiny_skia::Transform::identity(), None); /*handle_magick_result!( base_color.set_color("#7f7f7f"), "Failed to set init base color" @@ -277,8 +287,21 @@ async fn fmi(ctx: &Context, arg: &str, id: UserId, avatar: Option) -> Re avatar_wand.new_image(100, 100, &white), "Failed to load dummy avatar" ), - } - let avatar_mask_wand = MagickWand::new(); + }*/ + let avatar_uri = avatar.unwrap(); // TODO: FIX THIS + let avatar_base = match get_image(ctx, avatar_uri.as_str()).await { + Ok(i) => i, + Err(e) => return Reply::Text(e.to_string()), + }; + let mut avatar_image = handle_result!(tiny_skia::Pixmap::decode_png(&avatar_base), "Failed to load album art image"); + let mut avatar_mask = handle_result!(tiny_skia::Mask::decode_png(include_bytes!("avatar_mask.png")), "Failed to load album art image"); + let (avatar_x, avatar_y) = (FMI_WIDTH - FMI_AVATAR_SIZE - FMI_AVATAR_GAP, FMI_HEIGHT - FMI_AVATAR_SIZE - FMI_AVATAR_GAP); + avatar_image.apply_mask(&avatar_mask); + avatar_image = handle_option!(img::scale_skia_pixmap(avatar_image, FMI_AVATAR_SIZE, FMI_AVATAR_SIZE), "Failed to scale avatar image"); + //let avatar_matrix = tiny_skia::Transform::from_scale(avatar_scale, avatar_scale).pre_translate(avatar_x as f32, avatar_y as f32); + main_image.draw_pixmap(avatar_x as i32, avatar_y as i32, avatar_image.as_ref(), &source_paint, tiny_skia::Transform::identity(), None); + + /*let avatar_mask_wand = MagickWand::new(); handle_magick_result!( avatar_mask_wand.read_image_blob(include_bytes!("avatar_mask.png")), "Failed to load avatar mask"