Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,4 @@ serde_json = { version = "1.0.140", optional = true }
time = "0.3.41"
toml = { version = "0.9.2", optional = true }
zerocopy = { version = "0.8.26", features = ["derive"] }
image = "0.25.6"
71 changes: 61 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
#![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 badgemagic::{
ble::Device as BleDevice,
protocol::{Mode, PayloadBuffer, Speed, Style},
usb_hid::Device as UsbDevice,
};
use base64::Engine;
use clap::{Parser, ValueEnum};
use embedded_graphics::{
Expand All @@ -20,6 +15,15 @@ use embedded_graphics::{
Drawable, Pixel,
};
use serde::Deserialize;
use image::{
codecs::gif::GifDecoder, imageops::FilterType, AnimationDecoder, ImageReader, Pixel as iPixel,
};

use badgemagic::{
ble::Device as BleDevice,
protocol::{Mode, PayloadBuffer, Speed, Style},
usb_hid::Device as UsbDevice,
};

#[derive(Parser)]
/// Upload a configuration with up to 8 messages to an LED badge
Expand Down Expand Up @@ -92,8 +96,8 @@ enum Content {
Bitstring { bitstring: String },
BitmapBase64 { width: u32, bitmap_base64: String },
BitmapFile { width: u32, bitmap_file: PathBuf },
// TODO: implement png
// PngFile { png_file: PathBuf },
ImageFile { img_file: PathBuf },
GifFile { gif_file: PathBuf },
}

fn main() -> Result<()> {
Expand All @@ -103,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)
}
Expand All @@ -129,7 +133,7 @@ fn list_devices(transport: &TransportProtocol) -> Result<()> {
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 = fs::read_to_string(&config_path)
.with_context(|| format!("load config: {config_path:?}"))?;
Expand Down Expand Up @@ -224,6 +228,53 @@ fn gnerate_payload(args: &mut Args) -> Result<PayloadBuffer> {
let image = Image::new(&image_raw, Point::zero());
payload.add_message_drawable(style, &image);
}
Content::ImageFile { img_file } => {
let img_reader = ImageReader::open(img_file)?;
let img = img_reader
.decode()?
.resize(u32::MAX, 11, FilterType::Nearest)
.into_luma8();
let (width, height) = img.dimensions();
let mut buffer = payload.add_message(style, (width as usize + 7) / 8);
for y in 0..height {
for x in 0..width {
if img.get_pixel(x, y).0 > [31] {
Pixel(Point::new(x.try_into()?, y.try_into()?), BinaryColor::On)
.draw(&mut buffer)?;
}
}
}
}
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)?;
}
}
}
}
}
}
}

Expand Down