mirror of
https://github.com/fossasia/badgemagic-rs
synced 2025-07-27 05:53:57 +00:00
feat: Add animated GIF support
This commit is contained in:
parent
a10617fe6d
commit
58ea934c9f
1 changed files with 37 additions and 4 deletions
41
src/main.rs
41
src/main.rs
|
@ -1,7 +1,7 @@
|
||||||
#![warn(clippy::all, clippy::pedantic)]
|
#![warn(clippy::all, clippy::pedantic)]
|
||||||
#![allow(clippy::unnecessary_debug_formatting)]
|
#![allow(clippy::unnecessary_debug_formatting)]
|
||||||
|
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, fs::File, io::BufReader, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
|
@ -15,7 +15,9 @@ use embedded_graphics::{
|
||||||
Drawable, Pixel,
|
Drawable, Pixel,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use image::{imageops::FilterType, ImageReader};
|
use image::{
|
||||||
|
codecs::gif::GifDecoder, imageops::FilterType, AnimationDecoder, ImageReader, Pixel as iPixel,
|
||||||
|
};
|
||||||
|
|
||||||
use badgemagic::{
|
use badgemagic::{
|
||||||
ble::Device as BleDevice,
|
ble::Device as BleDevice,
|
||||||
|
@ -95,6 +97,7 @@ enum Content {
|
||||||
BitmapBase64 { width: u32, bitmap_base64: String },
|
BitmapBase64 { width: u32, bitmap_base64: String },
|
||||||
BitmapFile { width: u32, bitmap_file: PathBuf },
|
BitmapFile { width: u32, bitmap_file: PathBuf },
|
||||||
ImageFile { img_file: PathBuf },
|
ImageFile { img_file: PathBuf },
|
||||||
|
GifFile { gif_file: PathBuf },
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
@ -104,7 +107,7 @@ fn main() -> Result<()> {
|
||||||
return list_devices(&args.transport);
|
return list_devices(&args.transport);
|
||||||
}
|
}
|
||||||
|
|
||||||
let payload = gnerate_payload(&mut args)?;
|
let payload = generate_payload(&mut args)?;
|
||||||
|
|
||||||
write_payload(&args.transport, payload)
|
write_payload(&args.transport, payload)
|
||||||
}
|
}
|
||||||
|
@ -130,7 +133,7 @@ fn list_devices(transport: &TransportProtocol) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gnerate_payload(args: &mut Args) -> Result<PayloadBuffer> {
|
fn generate_payload(args: &mut Args) -> Result<PayloadBuffer> {
|
||||||
let config_path = args.config.take().unwrap_or_default();
|
let config_path = args.config.take().unwrap_or_default();
|
||||||
let config = fs::read_to_string(&config_path)
|
let config = fs::read_to_string(&config_path)
|
||||||
.with_context(|| format!("load config: {config_path:?}"))?;
|
.with_context(|| format!("load config: {config_path:?}"))?;
|
||||||
|
@ -242,6 +245,36 @@ fn gnerate_payload(args: &mut Args) -> Result<PayloadBuffer> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue