From 58ea934c9fb9ac687dc83d8416cebbdb39be1fe2 Mon Sep 17 00:00:00 2001 From: Valentin Weber Date: Thu, 10 Jul 2025 17:57:06 +0200 Subject: [PATCH] feat: Add animated GIF support --- src/main.rs | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4a11220..c4bed8d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::unnecessary_debug_formatting)] -use std::{fs, path::PathBuf}; +use std::{fs, fs::File, io::BufReader, path::PathBuf}; use anyhow::{Context, Result}; use base64::Engine; @@ -15,7 +15,9 @@ use embedded_graphics::{ Drawable, Pixel, }; use serde::Deserialize; -use image::{imageops::FilterType, ImageReader}; +use image::{ + codecs::gif::GifDecoder, imageops::FilterType, AnimationDecoder, ImageReader, Pixel as iPixel, +}; use badgemagic::{ ble::Device as BleDevice, @@ -95,6 +97,7 @@ enum Content { BitmapBase64 { width: u32, bitmap_base64: String }, BitmapFile { width: u32, bitmap_file: PathBuf }, ImageFile { img_file: PathBuf }, + GifFile { gif_file: PathBuf }, } fn main() -> Result<()> { @@ -104,7 +107,7 @@ fn main() -> Result<()> { return list_devices(&args.transport); } - let payload = gnerate_payload(&mut args)?; + let payload = generate_payload(&mut args)?; write_payload(&args.transport, payload) } @@ -130,7 +133,7 @@ fn list_devices(transport: &TransportProtocol) -> Result<()> { Ok(()) } -fn gnerate_payload(args: &mut Args) -> Result { +fn generate_payload(args: &mut Args) -> Result { let config_path = args.config.take().unwrap_or_default(); let config = fs::read_to_string(&config_path) .with_context(|| format!("load config: {config_path:?}"))?; @@ -242,6 +245,36 @@ fn gnerate_payload(args: &mut Args) -> Result { } } } + Content::GifFile { gif_file } => { + let file_in = BufReader::new(File::open(gif_file)?); + let frames = GifDecoder::new(file_in)? + .into_frames() + .collect_frames() + .expect("error decoding gif"); + + let frame_count = frames.len(); + let (width, height) = frames.first().unwrap().buffer().dimensions(); + if height != 11 || width != 44 { + anyhow::bail!("Expected 44x11 pixel gif file"); + } + + let mut buffer = payload.add_message(style, (48 * frame_count + 7) / 8); + + for (i, frame) in frames.iter().enumerate() { + let buf = frame.buffer(); + for y in 0..11 { + for x in 0..44 { + if buf.get_pixel(x, y).to_luma().0 > [31] { + Pixel( + Point::new((x as usize + i * 48).try_into()?, y.try_into()?), + BinaryColor::On, + ) + .draw(&mut buffer)?; + } + } + } + } + } } }