use image::codecs::gif::{GifEncoder, Repeat};
use image::{Frame, RgbaImage};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use std::collections::BTreeMap;
use std::fmt;
use std::io::Write;
use std::str::FromStr;
#[derive(Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct DivoomImageAnimation {
pub size: u32,
pub frame_count: usize,
pub speed_in_ms: i32,
pub frames: BTreeMap<u32, DivoomImageAnimationFrameData>,
}
pub const DIVOOM_IMAGE_ANIMATION_ID_AUTO: i32 = -1;
pub type DivoomImageAnimationFrameData = Vec<u8>;
#[derive(Debug, PartialOrd, PartialEq, Copy, Clone)]
pub enum DivoomFileAnimationSourceType {
LocalFile,
LocalFolder,
Url,
Raw(i32),
}
impl_divoom_dto_enum_traits!(DivoomFileAnimationSourceType, LocalFile: "file", LocalFolder: "folder", Url: "url");
impl DivoomImageAnimation {
pub fn save_gif<W: Write>(&self, image: W) -> anyhow::Result<()> {
let mut encoder = GifEncoder::new(image);
encoder.set_repeat(Repeat::Infinite)?;
for frame_data in self.frames.values() {
let frame_image = RgbaImage::from_fn(self.size, self.size, |x, y| {
let pixel_start = 3 * (x + y * self.size) as usize;
image::Rgba::from([
frame_data[pixel_start],
frame_data[pixel_start + 1],
frame_data[pixel_start + 2],
255,
])
});
encoder.encode_frame(Frame::new(frame_image))?
}
Ok(())
}
}