diff --git a/README.md b/README.md index 7d30dc6..cf2d042 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,13 @@ clock ## How to use +To use this library, please add the following into the dependencies in the `Cargo.toml` file: + +```toml +[dependencies] +divoom = "0.1" +``` + The library contains 2 major parts: - Divoom service APIs, that is used for talking to Divoom's backend service for device discovery etc. @@ -131,7 +138,7 @@ all the GIF frames into it one by one. To help with this process, we created a r use divoom::*; // Load the resource. -let frames = DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-rotate-4-frames.gif").unwrap(); +let frames = DivoomAnimationResourceLoader::gif_file("test_data/animation_builder_tests/logo-16-rotate-4-frames.gif").unwrap(); // Build animation with 16 pixel canvas and 100ms frame play speed. let builder = DivoomAnimationBuilder::new(16, Duration::from_millis(100)).unwrap(); @@ -150,9 +157,9 @@ let pixoo = PixooClient::new("192.168.0.123"); pixoo.send_gif_as_animation(16, Duration::from_millis(100), "test_data/animation_builder_tests/logo-16-rotate-4-frames.gif").await ``` -For more on how to use it, feel free to check our doc here: . +Besides gif, we also support png and jpeg format. And besides reading from file, we also support loading resource from any `Read` trait. For more on how to use it, feel free to check our doc here: . -And if you don't want this animation builder, we can exclude it by specifying the features with: +And for any reason, if you don't want the builtin animation builder, we can exclude it by specifying the features with: ```toml [dependencies] diff --git a/divoom/src/animation/animation_builder.rs b/divoom/src/animation/animation_builder.rs index f019a8b..e6ab5ce 100644 --- a/divoom/src/animation/animation_builder.rs +++ b/divoom/src/animation/animation_builder.rs @@ -206,17 +206,19 @@ mod tests { let mut frame = frame_builder.canvas_mut(); assert_eq!(frame.width(), 64); - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); frame_builder = frame_builder.draw_frame(&frames[0]); } #[test] fn divoom_animation_builder_can_build_single_frame_animation() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(16, Duration::from_millis(100)).unwrap(); @@ -229,9 +231,10 @@ mod tests { #[test] fn divoom_animation_builder_can_build_animation_with_fit() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(32, Duration::from_millis(100)).unwrap(); @@ -278,9 +281,10 @@ mod tests { #[test] fn divoom_animation_builder_can_build_animation_with_rotation() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(32, Duration::from_millis(100)).unwrap(); @@ -303,9 +307,10 @@ mod tests { #[test] fn divoom_animation_builder_can_build_animation_with_opacity() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(32, Duration::from_millis(100)).unwrap(); @@ -328,9 +333,10 @@ mod tests { #[test] fn divoom_animation_builder_can_build_animation_with_sized() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(32, Duration::from_millis(100)).unwrap(); @@ -346,9 +352,10 @@ mod tests { #[test] fn divoom_animation_builder_can_build_animation_with_scaled() { - let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo-16-0.gif") - .unwrap(); + let frames = DivoomAnimationResourceLoader::gif_file( + "test_data/animation_builder_tests/logo-16-0.gif", + ) + .unwrap(); assert_eq!(frames.len(), 1); let builder = DivoomAnimationBuilder::new(32, Duration::from_millis(100)).unwrap(); @@ -364,7 +371,7 @@ mod tests { #[test] fn divoom_animation_builder_can_build_multi_frame_animation() { - let frames = DivoomAnimationResourceLoader::gif( + let frames = DivoomAnimationResourceLoader::gif_file( "test_data/animation_builder_tests/logo-16-rotate-4-frames.gif", ) .unwrap(); diff --git a/divoom/src/animation/animation_resource_loader.rs b/divoom/src/animation/animation_resource_loader.rs index 33d05ec..d5ec798 100644 --- a/divoom/src/animation/animation_resource_loader.rs +++ b/divoom/src/animation/animation_resource_loader.rs @@ -1,23 +1,43 @@ use crate::{DivoomAPIError, DivoomAPIResult}; use std::fs::File; -use std::io::BufReader; +use std::io::{BufReader, Read}; use tiny_skia::Pixmap; /// Load resources into a series of `tiny_skia::Pixmap`, so we can use them to build the animations. pub struct DivoomAnimationResourceLoader {} impl DivoomAnimationResourceLoader { - /// Load from local png file - pub fn png(file_path: &str) -> DivoomAPIResult { + /// Load png resource from local file + pub fn png_file(file_path: &str) -> DivoomAPIResult { let frame = Pixmap::load_png(file_path)?; Ok(frame) } - /// Load from jpeg file + /// Load png resource from a memory buffer + pub fn png_buf(buf: &[u8]) -> DivoomAPIResult { + let frame = Pixmap::decode_png(buf)?; + Ok(frame) + } + + /// Load png resource from Read trait + pub fn png(reader: R) -> DivoomAPIResult { + let mut buffer = Vec::new(); + let mut buf_reader = BufReader::new(reader); + buf_reader.read_to_end(&mut buffer)?; + DivoomAnimationResourceLoader::png_buf(&buffer) + } + + /// Load jpeg resource from local file #[cfg(feature = "resource-loader-jpeg")] - pub fn jpeg(file_path: &str) -> DivoomAPIResult { + pub fn jpeg_file(file_path: &str) -> DivoomAPIResult { let file = File::open(file_path)?; - let mut decoder = jpeg_decoder::Decoder::new(BufReader::new(file)); + DivoomAnimationResourceLoader::jpeg(file) + } + + /// Load jpeg resource from Read trait + #[cfg(feature = "resource-loader-jpeg")] + pub fn jpeg(reader: R) -> DivoomAPIResult { + let mut decoder = jpeg_decoder::Decoder::new(BufReader::new(reader)); let pixels = decoder.decode()?; let metadata = decoder.info().unwrap(); @@ -80,16 +100,22 @@ impl DivoomAnimationResourceLoader { Ok(frame) } - /// Load from local gif file + /// Load gif resource from local file #[cfg(feature = "resource-loader-gif")] - pub fn gif(file_path: &str) -> DivoomAPIResult> { - let mut frames = vec![]; + pub fn gif_file(file_path: &str) -> DivoomAPIResult> { let input = File::open(file_path)?; + DivoomAnimationResourceLoader::gif(input) + } + + /// Load gif resource from Read trait + #[cfg(feature = "resource-loader-gif")] + pub fn gif(reader: R) -> DivoomAPIResult> { + let mut frames = vec![]; let mut options = gif::DecodeOptions::new(); options.set_color_output(gif::ColorOutput::RGBA); - let mut decoder = options.read_info(input)?; + let mut decoder = options.read_info(reader)?; while let Some(frame) = decoder.read_next_frame()? { let mut frame_pixmap = Pixmap::new(frame.width as u32, frame.height as u32).unwrap(); assert_eq!(frame_pixmap.data().len(), frame.buffer.len()); @@ -128,7 +154,7 @@ mod tests { #[test] fn divoom_resource_loader_can_load_png_file() { let frame = - DivoomAnimationResourceLoader::png("test_data/animation_builder_tests/logo.png") + DivoomAnimationResourceLoader::png_file("test_data/animation_builder_tests/logo.png") .unwrap(); let non_zero_bits_count = frame.data().as_ref().iter().filter(|x| **x != 0u8).count(); @@ -137,7 +163,7 @@ mod tests { #[test] fn divoom_resource_loader_can_load_jpeg_grayscale_file() { - let frame = DivoomAnimationResourceLoader::jpeg( + let frame = DivoomAnimationResourceLoader::jpeg_file( "test_data/animation_builder_tests/logo_grayscale.jpg", ) .unwrap(); @@ -148,9 +174,10 @@ mod tests { #[test] fn divoom_resource_loader_can_load_jpeg_rgb_file() { - let frame = - DivoomAnimationResourceLoader::jpeg("test_data/animation_builder_tests/logo_rgb.jpg") - .unwrap(); + let frame = DivoomAnimationResourceLoader::jpeg_file( + "test_data/animation_builder_tests/logo_rgb.jpg", + ) + .unwrap(); let non_zero_bits_count = frame.data().as_ref().iter().filter(|x| **x != 0u8).count(); assert_ne!(non_zero_bits_count, 0); @@ -158,9 +185,10 @@ mod tests { #[test] fn divoom_resource_loader_can_load_jpeg_cmyk_file() { - let frame = - DivoomAnimationResourceLoader::jpeg("test_data/animation_builder_tests/logo_cmyk.jpg") - .unwrap(); + let frame = DivoomAnimationResourceLoader::jpeg_file( + "test_data/animation_builder_tests/logo_cmyk.jpg", + ) + .unwrap(); let non_zero_bits_count = frame.data().as_ref().iter().filter(|x| **x != 0u8).count(); assert_ne!(non_zero_bits_count, 0); @@ -169,7 +197,7 @@ mod tests { #[test] fn divoom_resource_loader_can_load_gif_file() { let frames = - DivoomAnimationResourceLoader::gif("test_data/animation_builder_tests/logo.gif") + DivoomAnimationResourceLoader::gif_file("test_data/animation_builder_tests/logo.gif") .unwrap(); assert_eq!(frames.len(), 1); diff --git a/divoom/src/clients/pixoo/pixoo_client.rs b/divoom/src/clients/pixoo/pixoo_client.rs index 0235cf4..c867c76 100644 --- a/divoom/src/clients/pixoo/pixoo_client.rs +++ b/divoom/src/clients/pixoo/pixoo_client.rs @@ -328,7 +328,7 @@ impl PixooClient { file_path: &str, ) -> DivoomAPIResult<()> { let animation_builder = DivoomAnimationBuilder::new(canvas_size, speed)?; - let gif = DivoomAnimationResourceLoader::gif(file_path)?; + let gif = DivoomAnimationResourceLoader::gif_file(file_path)?; let animation = animation_builder .draw_frames_fit( &gif, @@ -361,7 +361,7 @@ impl PixooClient { blend: BlendMode, ) -> DivoomAPIResult<()> { let animation_builder = DivoomAnimationBuilder::new(canvas_size, speed)?; - let gif = DivoomAnimationResourceLoader::gif(file_path)?; + let gif = DivoomAnimationResourceLoader::gif_file(file_path)?; let animation = animation_builder .draw_frames_fit(&gif, 0, fit, rotation, opacity, blend) .build(); diff --git a/divoom_cli/src/main.rs b/divoom_cli/src/main.rs index 06cbd58..446b46a 100644 --- a/divoom_cli/src/main.rs +++ b/divoom_cli/src/main.rs @@ -303,9 +303,7 @@ fn new_pixoo_client(common: &DivoomCliDeviceCommandCommonOpts) -> PixooClient { .device_address .as_ref() .expect("Device Address is not set!"), - common - .timeout - .map_or(None, |x| Some(Duration::from_millis(x))), + common.timeout.map(|x| Duration::from_millis(x)), ) }