Skip to content

Commit

Permalink
Adding send-gif support in divoom-cli. (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
r12f authored Jul 21, 2022
1 parent 69fde5e commit 5724dec
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 39 deletions.
15 changes: 7 additions & 8 deletions divoom/src/animation/animation_builder.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::animation::animation_builder_error::*;
use crate::animation::animation_frame_builder::DivoomAnimationFrameBuilder;
use crate::dto::*;
use std::collections::BTreeMap;
Expand All @@ -15,12 +14,12 @@ pub struct DivoomAnimationBuilder {

// Ctor and basic functions
impl DivoomAnimationBuilder {
pub fn new(
canvas_size: u32,
speed: Duration,
) -> DivoomAnimationBuilderResult<DivoomAnimationBuilder> {
pub fn new(canvas_size: u32, speed: Duration) -> DivoomAPIResult<DivoomAnimationBuilder> {
if canvas_size != 16 && canvas_size != 32 && canvas_size != 64 {
return Err(DivoomAnimationBuilderError::UnsupportedCanvasSize);
return Err(DivoomAPIError::ParameterError(format!(
"Invalid canvas size: {}. Only 16, 32 and 64 are supported.",
canvas_size
)));
}

Ok(DivoomAnimationBuilder {
Expand Down Expand Up @@ -123,7 +122,7 @@ impl DivoomAnimationBuilder {
#[cfg(test)]
mod tests {
use crate::animation::*;
use crate::test_utils;
use crate::{test_utils, DivoomAPIError};
use std::time::Duration;

#[test]
Expand All @@ -139,7 +138,7 @@ mod tests {
match result {
Ok(_) => panic!("Canvas size is incorrect and we shall not create builder here."),
Err(e) => match e {
DivoomAnimationBuilderError::UnsupportedCanvasSize => (),
DivoomAPIError::ParameterError(_) => (),
_ => panic!("Incorrect error code!"),
},
}
Expand Down
24 changes: 0 additions & 24 deletions divoom/src/animation/animation_builder_error.rs

This file was deleted.

10 changes: 8 additions & 2 deletions divoom/src/animation/animation_resource_loader.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::animation::animation_builder_error::DivoomAnimationBuilderResult;
use crate::{DivoomAPIError, DivoomAPIResult};
use std::fs::File;
use tiny_skia::Pixmap;

pub struct DivoomAnimationResourceLoader {}

impl DivoomAnimationResourceLoader {
pub fn gif(file_path: &str) -> DivoomAnimationBuilderResult<Vec<Pixmap>> {
pub fn gif(file_path: &str) -> DivoomAPIResult<Vec<Pixmap>> {
let mut frames = vec![];
let input = File::open(file_path)?;

Expand All @@ -24,6 +24,12 @@ impl DivoomAnimationResourceLoader {
}
}

impl From<gif::DecodingError> for DivoomAPIError {
fn from(err: gif::DecodingError) -> Self {
DivoomAPIError::ResourceDecodeError(err.to_string())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
2 changes: 0 additions & 2 deletions divoom/src/animation/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
mod animation_builder;
mod animation_builder_error;
mod animation_frame_builder;
mod animation_resource_loader;

pub use animation_builder::*;
pub use animation_builder_error::*;
pub use animation_frame_builder::*;
pub use animation_resource_loader::*;
24 changes: 24 additions & 0 deletions divoom/src/clients/pixoo/pixoo_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ use crate::divoom_contracts::pixoo::system::*;
use crate::divoom_contracts::pixoo::tool::*;
use crate::dto::*;
use std::rc::Rc;
use std::time::Duration;

#[cfg(feature = "animation-builder")]
use crate::animation::*;

/// Pixoo device client
///
Expand Down Expand Up @@ -300,6 +304,26 @@ impl PixooClient {
()
);

/// Send GIF to the device to play as an animation.
///
/// This API is different from `play_gif_file`, which is provided by divoom device directly. This API will try to leverage the animation API,
/// create a new animation, load the gif files and draw all the frames into the animation, and send the to device to play.
///
/// The API `play_gif_file` doesn't seems to be very stable when the package is published, hence `send_gif_as_animation` is more preferred
/// as of now.
#[cfg(feature = "animation-builder")]
pub async fn send_gif_as_animation(
&self,
canvas_size: u32,
speed: Duration,
file_path: &str,
) -> DivoomAPIResult<()> {
let animation_builder = DivoomAnimationBuilder::new(canvas_size, speed)?;
let gif = DivoomAnimationResourceLoader::gif(file_path)?;
let animation = animation_builder.draw_frames(&gif, 0).build();
self.send_image_animation(animation).await
}

#[doc = include_str!("../../divoom_contracts/pixoo/animation/api_send_image_animation_frame.md")]
pub async fn send_image_animation(
&self,
Expand Down
10 changes: 10 additions & 0 deletions divoom/src/dto/divoom_api_error.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::io;
use thiserror::Error;

/// This represents the error that returned from Divoom online service or Divoom devices.
Expand Down Expand Up @@ -54,6 +55,15 @@ pub enum DivoomAPIError {
#[error("Invalid parameter.")]
ParameterError(String),

#[error("Failed to load resource")]
ResourceLoadError {
#[from]
source: io::Error,
},

#[error("Failed to decode resource")]
ResourceDecodeError(String),

#[error("Failed to send request")]
RequestError {
#[from]
Expand Down
17 changes: 14 additions & 3 deletions divoom_cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,22 @@ brightness: 67
# Set channel to clock with id 100
> divoom-cli 192.168.0.164 channel set-clock 100

# Play a gif from Internet by calling the API provided by Divoom Device.
# Please note that: this API can be unstable and only accepts GIF with 16x16, 32x32 and 64x64 image size.
> divoom-cli 192.168.0.123 animation gif play --url https://www.gifandgif.eu/animated_gif/Planets/Animated%20Gif%20Planets%20(16).GIF

# To help playing GIF in a more stable way, we can use the image animation API to craft an animation and draw the GIF
# frames into it and send to device to play, e.g.:
> divoom-cli 192.168.0.123 animation image send-gif "logo-16-rotate-4-frames.gif" 16 -s 100

# Create a text animation
> divoom-cli 192.168.0.123 animation text set 1 "The gray fox jumped over the lazy dog"
# Please note that: this API only works after we use "animation image send-gif" API to draw anything. This API call will be ignored,
# when the device is showing other things, like clock or channel.
> divoom-cli 192.168.0.123 animation text set 1 "Hello world!"
> divoom-cli 192.168.0.123 animation text set 2 "The gray fox jumped over the lazy dog" -y 20

# Play a gif from Internet
> divoom-cli 192.168.0.123 animation gif play --url https://www.gifandgif.eu/animated_gif/Planets/Animated%20Gif%20Planets%20(16).GIF
# Modify existing text animation. E.g. changing "Hello world!" above to "Hello Divoom!"
> divoom-cli 192.168.0.123 animation text set 1 "Hello Divoom!"

# Send a raw request
#
Expand Down
11 changes: 11 additions & 0 deletions divoom_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod opt;
use crate::opt::*;
use divoom::*;
use serde::Serialize;
use std::time::Duration;
use structopt::StructOpt;

#[tokio::main]
Expand Down Expand Up @@ -278,6 +279,16 @@ async fn handle_image_animation_api(
}

DivoomCliImageAnimationCommand::ResetId => pixoo.reset_next_animation_id().await,

DivoomCliImageAnimationCommand::SendGif {
file_path,
size,
speed_in_ms,
} => {
pixoo
.send_gif_as_animation(size, Duration::from_millis(speed_in_ms), &file_path)
.await
}
}
}

Expand Down
22 changes: 22 additions & 0 deletions divoom_cli/src/opt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,28 @@ pub enum DivoomCliImageAnimationCommand {

#[structopt(about = "Reset next animation id")]
ResetId,

#[structopt(
about = "Send gif as animation. This is different from \"gif play\" command, which is provided directly by Divoom device. This command will create a regular animation and load the gif file and draw the frames into it in order to play it."
)]
SendGif {
#[structopt(help = "Gif file path")]
file_path: String,

#[structopt(
default_value = "64",
help = "Animation size in pixels. Only 16 and 32 and 64 are allowed."
)]
size: u32,

#[structopt(
short,
long = "speed",
default_value = "100",
help = "Animation play speed in milliseconds"
)]
speed_in_ms: u64,
},
}

#[derive(StructOpt, Debug)]
Expand Down

0 comments on commit 5724dec

Please sign in to comment.