Prepare for user saving of anime sequences

This commit is contained in:
Luke D Jones
2021-04-05 21:06:53 +12:00
parent 6d746b21a5
commit d854f7da1b
49 changed files with 339 additions and 124 deletions

1
Cargo.lock generated
View File

@@ -958,6 +958,7 @@ checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
name = "rog_anime"
version = "1.0.0"
dependencies = [
"gif",
"glam",
"pix",
"png_pong",

View File

@@ -9,26 +9,17 @@ fn main() -> Result<(), Box<dyn Error>> {
let (client, _) = AuraDbusClient::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect();
if args.len() != 7 {
if args.len() != 3 {
println!(
"Usage: <filepath> <x scale> <y scale> <x pos> <y pos> <brightness>"
"Usage: <filepath> <brightness>"
);
println!("e.g, asusctl/examples/doom_large.png 0.9 0.9 0.4 0.0 0.0 0.8");
println!("All args except path and fineness are floats");
println!("e.g, asusctl/examples/doom_large.png 0.8");
exit(-1);
}
let matrix = AniMeDiagonal::from_png(
Path::new(&args[1]),
Vec2::new(
args[2].parse::<f32>().unwrap(),
args[3].parse::<f32>().unwrap(),
),
Vec2::new(
args[4].parse::<f32>().unwrap(),
args[5].parse::<f32>().unwrap(),
),
args[6].parse::<f32>().unwrap(),
args[2].parse::<f32>().unwrap(),
)?;
client

View File

@@ -10,7 +10,6 @@ use rog_dbus::AuraDbusClient;
fn main() {
let (client, _) = AuraDbusClient::new().unwrap();
for step in (2..50).rev() {
let mut matrix = AniMeDiagonal::new();

View File

@@ -1,60 +1,29 @@
use std::{env, fs::File, path::Path, thread::sleep, time::Duration};
use rog_anime::{AniMeDataBuffer, AniMeDiagonal};
use rog_anime::AniMeSequence;
use rog_dbus::AuraDbusClient;
struct AniMeFrame {
data: AniMeDataBuffer,
delay: Duration,
}
fn main() {
let (client, _) = AuraDbusClient::new().unwrap();
let args: Vec<String> = env::args().into_iter().collect();
// if args.len() != 7 {
// exit(-1);
// }
let mut frames = Vec::new();
let mut matrix = AniMeDiagonal::new();
let mut decoder = gif::DecodeOptions::new();
// Configure the decoder such that it will expand the image to RGBA.
decoder.set_color_output(gif::ColorOutput::RGBA);
// Read the file header
let file = File::open(Path::new(&args[1])).unwrap();
let mut decoder = decoder.read_info(file).unwrap();
while let Some(frame) = decoder.read_next_frame().unwrap() {
let wait = frame.delay;
for (y, row) in frame.buffer.chunks(frame.width as usize * 4).enumerate() {
for (x, px) in row.chunks(4).enumerate() {
if px[3] != 255 {
// should be t but not in some gifs? What, ASUS, what?
continue;
}
matrix.get_mut()[y + frame.top as usize][x + frame.left as usize] = px[0];
}
}
client
.proxies()
.anime()
.write(<AniMeDataBuffer>::from(&matrix))
.unwrap();
frames.push(AniMeFrame {
data: <AniMeDataBuffer>::from(&matrix),
delay: Duration::from_millis(wait as u64),
});
sleep(Duration::from_millis(wait as u64));
if args.len() != 3 {
println!("Please supply filepath and brightness");
return;
}
let path = Path::new(&args[1]);
let brightness = args[2].parse::<f32>().unwrap();
let gif = AniMeSequence::gif(path, brightness).unwrap();
loop {
for frame in frames.iter() {
client.proxies().anime().write(frame.data.clone()).unwrap();
sleep(frame.delay);
for frame in gif.get_animation().unwrap().frames() {
client
.proxies()
.anime()
.write(frame.frame().clone())
.unwrap();
sleep(frame.delay());
}
}
}

View File

@@ -1,7 +1,7 @@
use std::{env, error::Error, path::Path, process::exit};
use rog_anime::{
AniMeDataBuffer, {AnimeImage, Vec2},
AniMeDataBuffer, {AniMeImage, Vec2},
};
use rog_dbus::AuraDbusClient;
@@ -13,12 +13,11 @@ fn main() -> Result<(), Box<dyn Error>> {
println!(
"Usage: <filepath> <x scale> <y scale> <angle> <x pos> <y pos> <brightness>"
);
println!("e.g, asusctl/examples/doom_large.png 0.9 0.9 0.4 0.0 0.0, 0.8");
println!("All args except path and fineness are floats");
println!("e.g, asusctl/examples/doom_large.png 0.9 0.9 0.4 0.0 0.0,0.8");
exit(-1);
}
let matrix = AnimeImage::from_png(
let matrix = AniMeImage::from_png(
Path::new(&args[1]),
Vec2::new(
args[2].parse::<f32>().unwrap(),

View File

@@ -3,7 +3,7 @@ use std::{
};
use rog_anime::{
AniMeDataBuffer, {AnimeImage, Vec2},
AniMeDataBuffer, {AniMeImage, Vec2},
};
use rog_dbus::AuraDbusClient;
@@ -18,7 +18,7 @@ fn main() -> Result<(), Box<dyn Error>> {
exit(-1);
}
let mut matrix = AnimeImage::from_png(
let mut matrix = AniMeImage::from_png(
Path::new(&args[1]),
Vec2::new(
args[2].parse::<f32>().unwrap(),

View File

@@ -10,7 +10,7 @@ use daemon::{
use gumdrop::{Opt, Options};
use rog_anime::{
AniMeDataBuffer, ANIME_DATA_LEN,
AnimeImage, Vec2,
AniMeImage, Vec2,
};
use rog_dbus::AuraDbusClient;
use rog_types::{
@@ -178,7 +178,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
std::process::exit(1);
}
let matrix = AnimeImage::from_png(
let matrix = AniMeImage::from_png(
Path::new(&image.path),
Vec2::new(image.scale, image.scale),
image.angle,

View File

@@ -0,0 +1,15 @@
Language,String
en,Festive
zh-tw,節慶
zh-cn,节庆
nl,Feestelijk
fr,Festif
de,Festlich
ja,フェスティバル
pt,Festivo
ru,Праздники
es,Festivo
it,Feste
cs,Slavnostní
ko,축제
tr,Eğlence
1 Language String
2 en Festive
3 zh-tw 節慶
4 zh-cn 节庆
5 nl Feestelijk
6 fr Festif
7 de Festlich
8 ja フェスティバル
9 pt Festivo
10 ru Праздники
11 es Festivo
12 it Feste
13 cs Slavnostní
14 ko 축제
15 tr Eğlence

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@@ -0,0 +1,18 @@
Language,String
en,Festive
zh-tw,節慶
zh-cn,节庆
nl,Feestelijk
fr,Festif
de,Festlich
ja,フェスティバル
pt,Festivo
ru,Праздники
es,Festivo
it,Feste
cs,Slavnostní
ko,축제
tr,Eğlence
fi,Juhlava
nb,Festlig
sv,Festligt
1 Language String
2 en Festive
3 zh-tw 節慶
4 zh-cn 节庆
5 nl Feestelijk
6 fr Festif
7 de Festlich
8 ja フェスティバル
9 pt Festivo
10 ru Праздники
11 es Festivo
12 it Feste
13 cs Slavnostní
14 ko 축제
15 tr Eğlence
16 fi Juhlava
17 nb Festlig
18 sv Festligt

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

16
data/anime/Folder order.csv Executable file
View File

@@ -0,0 +1,16 @@
Language,Trend,Gaming,Festive,Music,ROG theme
cs,1,2,3,4,5
de,1,2,3,4,5
en,1,2,3,4,5
es,1,2,3,4,5
fr,1,2,3,4,5
it,1,2,3,4,5
ja,1,2,3,4,5
ko,1,2,3,4,5
nl,1,2,3,4,5
pt,1,2,3,4,5
ru,1,2,3,4,5
tr,1,2,3,4,5
zh-cn,1,2,3,4,5
zh-tw,1,2,3,4,5
default,1,2,3,4,5
1 Language Trend Gaming Festive Music ROG theme
2 cs 1 2 3 4 5
3 de 1 2 3 4 5
4 en 1 2 3 4 5
5 es 1 2 3 4 5
6 fr 1 2 3 4 5
7 it 1 2 3 4 5
8 ja 1 2 3 4 5
9 ko 1 2 3 4 5
10 nl 1 2 3 4 5
11 pt 1 2 3 4 5
12 ru 1 2 3 4 5
13 tr 1 2 3 4 5
14 zh-cn 1 2 3 4 5
15 zh-tw 1 2 3 4 5
16 default 1 2 3 4 5

BIN
data/anime/Gaming/0.0.1/Bird.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

View File

@@ -0,0 +1,15 @@
Language,String
en,Gaming
zh-tw,遊戲
zh-cn,游戏
nl,Gaming
fr,Jeu
de,Gaming
ja,ゲーム
pt,Jogos
ru,Игры
es,Juegos
it,Gaming
cs,Hraní
ko,게이밍
tr,Oyun
1 Language String
2 en Gaming
3 zh-tw 遊戲
4 zh-cn 游戏
5 nl Gaming
6 fr Jeu
7 de Gaming
8 ja ゲーム
9 pt Jogos
10 ru Игры
11 es Juegos
12 it Gaming
13 cs Hraní
14 ko 게이밍
15 tr Oyun

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
data/anime/Gaming/0.0.1/FPS.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
data/anime/Gaming/0.0.1/MOBA.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1,15 @@
Language,String
en,Gaming
zh-tw,遊戲
zh-cn,游戏
nl,Gaming
fr,Jeu
de,Gaming
ja,ゲーム
pt,Jogos
ru,Игры
es,Juegos
it,Gaming
cs,Hraní
ko,게이밍
tr,Oyun
1 Language String
2 en Gaming
3 zh-tw 遊戲
4 zh-cn 游戏
5 nl Gaming
6 fr Jeu
7 de Gaming
8 ja ゲーム
9 pt Jogos
10 ru Игры
11 es Juegos
12 it Gaming
13 cs Hraní
14 ko 게이밍
15 tr Oyun

BIN
data/anime/Gaming/0.0.2/Fight.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

BIN
data/anime/Gaming/0.0.2/UFO.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@@ -0,0 +1,17 @@
Language,String
en,Music
zh-tw,音樂
zh-cn,音乐
nl,Muziek
fr,Musique
de,Musik
ja,ミュージック
pt,Música
ru,Музыка
es,Música
it,Musica
cs,Hudba
ko,음악
tr,Müzik
,
,
1 Language String
2 en Music
3 zh-tw 音樂
4 zh-cn 音乐
5 nl Muziek
6 fr Musique
7 de Musik
8 ja ミュージック
9 pt Música
10 ru Музыка
11 es Música
12 it Musica
13 cs Hudba
14 ko 음악
15 tr Müzik
16
17

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

BIN
data/anime/Music/0.0.2/DJ.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

View File

@@ -0,0 +1,15 @@
Language,String
en,ROG Gallery
zh-tw,ROG 主題
zh-cn,ROG 主题
nl,ROG-thema
fr,Thème ROG
de,ROG-Thema
ja,ROG テーマ
pt,Tema ROG
ru,Тема ROG
es,Tema de ROG
it,Tema ROG
cs,Téma ROG
ko,ROG 테마
tr,ROG teması
1 Language String
2 en ROG Gallery
3 zh-tw ROG 主題
4 zh-cn ROG 主题
5 nl ROG-thema
6 fr Thème ROG
7 de ROG-Thema
8 ja ROG テーマ
9 pt Tema ROG
10 ru Тема ROG
11 es Tema de ROG
12 it Tema ROG
13 cs Téma ROG
14 ko ROG 테마
15 tr ROG teması

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,15 @@
Language,String
en,Trend
zh-tw,潮流
zh-cn,潮流
nl,Trend
fr,Tendance
de,Trend
ja,トレンド
pt,Tendência
ru,В тренде
es,Tendencia
it,Tendenza
cs,Trend
ko,트렌드
tr,Popüler
1 Language String
2 en Trend
3 zh-tw 潮流
4 zh-cn 潮流
5 nl Trend
6 fr Tendance
7 de Trend
8 ja トレンド
9 pt Tendência
10 ru В тренде
11 es Tendencia
12 it Tendenza
13 cs Trend
14 ko 트렌드
15 tr Popüler

BIN
data/anime/Trend/0.0.1/Dog.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

BIN
data/anime/Trend/0.0.1/Ski.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@@ -0,0 +1,15 @@
Language,String
en,Trend
zh-tw,潮流
zh-cn,潮流
nl,Trend
fr,Tendance
de,Trend
ja,トレンド
pt,Tendência
ru,В тренде
es,Tendencia
it,Tendenza
cs,Trend
ko,트렌드
tr,Popüler
1 Language String
2 en Trend
3 zh-tw 潮流
4 zh-cn 潮流
5 nl Trend
6 fr Tendance
7 de Trend
8 ja トレンド
9 pt Tendência
10 ru В тренде
11 es Tendencia
12 it Tendenza
13 cs Trend
14 ko 트렌드
15 tr Popüler

BIN
data/anime/Trend/0.0.2/Wave.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@@ -13,6 +13,7 @@ edition = "2018"
png_pong = "^0.8.0"
glam = "*"
pix = "0.13"
gif = "^0.11.2"
serde = "^1.0"
serde_derive = "^1.0"

View File

@@ -1,7 +1,5 @@
use std::path::Path;
use glam::Vec2;
use crate::{
anime_data::{AniMeDataBuffer, ANIME_DATA_LEN},
error::AnimeError,
@@ -28,11 +26,6 @@ impl AniMeDiagonal {
&mut self.0
}
// use with height - y
const fn dy(x: usize, y: usize) -> usize {
x / 2 + x % 2 + y
}
fn get_row(&self, x: usize, y: usize, len: usize) -> Vec<u8> {
let mut buf = Vec::with_capacity(len);
for i in 0..len {
@@ -46,8 +39,6 @@ impl AniMeDiagonal {
/// updated via scale, position, or angle then displayed again after `update()`.
pub fn from_png(
path: &Path,
scale: Vec2,
offset: Vec2,
bright: f32,
) -> Result<Self, AnimeError> {
use pix::el::Pixel;

View File

@@ -0,0 +1,61 @@
use serde_derive::{Deserialize, Serialize};
use std::{fs::File, path::{Path}, time::Duration};
use crate::{error::AnimeError, AniMeDataBuffer, AniMeDiagonal};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AniMeFrame {
data: AniMeDataBuffer,
delay: Duration,
}
impl AniMeFrame {
pub fn frame(&self) -> &AniMeDataBuffer {
&self.data
}
pub fn delay(&self) -> Duration {
self.delay
}
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AniMeGif(Vec<AniMeFrame>);
impl AniMeGif {
pub fn new(file_name: &Path, brightness: f32) -> Result<Self, AnimeError> {
let mut frames = Vec::new();
let mut matrix = AniMeDiagonal::new();
let mut decoder = gif::DecodeOptions::new();
// Configure the decoder such that it will expand the image to RGBA.
decoder.set_color_output(gif::ColorOutput::RGBA);
// Read the file header
let file = File::open(file_name)?;
let mut decoder = decoder.read_info(file)?;
while let Some(frame) = decoder.read_next_frame()? {
let wait = frame.delay * 10;
for (y, row) in frame.buffer.chunks(frame.width as usize * 4).enumerate() {
for (x, px) in row.chunks(4).enumerate() {
if px[3] != 255 {
// should be t but not in some gifs? What, ASUS, what?
continue;
}
matrix.get_mut()[y + frame.top as usize][x + frame.left as usize] =
(px[0] as f32 * brightness) as u8;
}
}
frames.push(AniMeFrame {
data: <AniMeDataBuffer>::from(&matrix),
delay: Duration::from_millis(wait as u64),
});
}
Ok(Self(frames))
}
pub fn frames(&self) -> &[AniMeFrame] {
&self.0
}
}

View File

@@ -49,7 +49,7 @@ impl Led {
/// Container of `Led`, each of which specifies a position within the image
/// The main use of this is to position and sample colours for the final image
/// to show on AniMe
pub struct AnimeImage {
pub struct AniMeImage {
pub scale: Vec2,
/// Angle in radians
pub angle: f32,
@@ -63,7 +63,7 @@ pub struct AnimeImage {
width: u32,
}
impl AnimeImage {
impl AniMeImage {
const fn new(
scale: Vec2,
angle: f32,
@@ -133,11 +133,11 @@ impl AnimeImage {
/// Really only used to generate the output for including as a full const in `LED_IMAGE_POSITIONS`
pub fn generate() -> Vec<Option<Led>> {
(0..AnimeImage::height())
(0..AniMeImage::height())
.flat_map(|y| {
(0..AnimeImage::pitch(y)).map(move |l| {
if l < AnimeImage::width(y) {
let x = AnimeImage::first_x(y) + l;
(0..AniMeImage::pitch(y)).map(move |l| {
if l < AniMeImage::width(y) {
let x = AniMeImage::first_x(y) + l;
Some(Led::new(x as f32 - 0.5 * (y % 2) as f32, y as f32))
} else {
None
@@ -203,8 +203,8 @@ impl AnimeImage {
// Center of image
let center = Mat3::from_translation(Vec2::new(-0.5 * bmp_w, -0.5 * bmp_h));
// Find the scale required for cleanly showing the image
let h = AnimeImage::phys_height() / bmp_h;
let mut base_scale = AnimeImage::phys_width() / bmp_w;
let h = AniMeImage::phys_height() / bmp_h;
let mut base_scale = AniMeImage::phys_width() / bmp_w;
if base_scale > h {
base_scale = h;
}
@@ -212,8 +212,8 @@ impl AnimeImage {
let cm_from_px = Mat3::from_scale(Vec2::new(base_scale, base_scale));
let led_from_cm = Mat3::from_scale(Vec2::new(
1.0 / AnimeImage::scale_x(),
1.0 / AnimeImage::scale_y(),
1.0 / AniMeImage::scale_x(),
1.0 / AniMeImage::scale_y(),
));
let transform =
@@ -258,18 +258,18 @@ impl AnimeImage {
_ => return Err(AnimeError::Format),
};
let mut matrix = AnimeImage::new(scale, angle, translation, bright, pixels, width);
let mut matrix = AniMeImage::new(scale, angle, translation, bright, pixels, width);
matrix.update();
Ok(matrix)
}
}
impl From<&AnimeImage> for AniMeDataBuffer {
impl From<&AniMeImage> for AniMeDataBuffer {
/// Do conversion from the nested Vec in AniMeMatrix to the two required
/// packets suitable for sending over USB
#[inline]
fn from(leds: &AnimeImage) -> Self {
fn from(leds: &AniMeImage) -> Self {
let mut l: Vec<u8> = leds
.led_pos
.iter()
@@ -1540,7 +1540,7 @@ mod tests {
#[test]
fn led_positions() {
let leds = AnimeImage::generate();
let leds = AniMeImage::generate();
assert_eq!(leds[0], Some(Led(0.0, 0.0, 0)));
assert_eq!(leds[1], Some(Led(1.0, 0.0, 0)));
assert_eq!(leds[2], Some(Led(2.0, 0.0, 0)));
@@ -1569,7 +1569,7 @@ mod tests {
#[test]
fn led_positions_const() {
let leds = AnimeImage::generate();
let leds = AniMeImage::generate();
assert_eq!(leds[1], LED_IMAGE_POSITIONS[1]);
assert_eq!(leds[34], LED_IMAGE_POSITIONS[34]);
assert_eq!(leds[69], LED_IMAGE_POSITIONS[69]);
@@ -1583,44 +1583,44 @@ mod tests {
#[test]
fn row_starts() {
assert_eq!(AnimeImage::first_x(5), 0);
assert_eq!(AnimeImage::first_x(6), 0);
assert_eq!(AnimeImage::first_x(7), 1);
assert_eq!(AnimeImage::first_x(8), 1);
assert_eq!(AnimeImage::first_x(9), 2);
assert_eq!(AnimeImage::first_x(10), 2);
assert_eq!(AnimeImage::first_x(11), 3);
assert_eq!(AniMeImage::first_x(5), 0);
assert_eq!(AniMeImage::first_x(6), 0);
assert_eq!(AniMeImage::first_x(7), 1);
assert_eq!(AniMeImage::first_x(8), 1);
assert_eq!(AniMeImage::first_x(9), 2);
assert_eq!(AniMeImage::first_x(10), 2);
assert_eq!(AniMeImage::first_x(11), 3);
}
#[test]
fn row_widths() {
assert_eq!(AnimeImage::width(5), 33);
assert_eq!(AnimeImage::width(6), 33);
assert_eq!(AnimeImage::width(7), 32);
assert_eq!(AnimeImage::width(8), 32);
assert_eq!(AnimeImage::width(9), 31);
assert_eq!(AnimeImage::width(10), 31);
assert_eq!(AnimeImage::width(11), 30);
assert_eq!(AnimeImage::width(12), 30);
assert_eq!(AnimeImage::width(13), 29);
assert_eq!(AnimeImage::width(14), 29);
assert_eq!(AnimeImage::width(15), 28);
assert_eq!(AnimeImage::width(16), 28);
assert_eq!(AnimeImage::width(17), 27);
assert_eq!(AnimeImage::width(18), 27);
assert_eq!(AniMeImage::width(5), 33);
assert_eq!(AniMeImage::width(6), 33);
assert_eq!(AniMeImage::width(7), 32);
assert_eq!(AniMeImage::width(8), 32);
assert_eq!(AniMeImage::width(9), 31);
assert_eq!(AniMeImage::width(10), 31);
assert_eq!(AniMeImage::width(11), 30);
assert_eq!(AniMeImage::width(12), 30);
assert_eq!(AniMeImage::width(13), 29);
assert_eq!(AniMeImage::width(14), 29);
assert_eq!(AniMeImage::width(15), 28);
assert_eq!(AniMeImage::width(16), 28);
assert_eq!(AniMeImage::width(17), 27);
assert_eq!(AniMeImage::width(18), 27);
}
#[test]
fn row_pitch() {
assert_eq!(AnimeImage::pitch(5), 34);
assert_eq!(AnimeImage::pitch(6), 33);
assert_eq!(AnimeImage::pitch(7), 33);
assert_eq!(AnimeImage::pitch(8), 32);
assert_eq!(AnimeImage::pitch(9), 32);
assert_eq!(AnimeImage::pitch(10), 31);
assert_eq!(AnimeImage::pitch(11), 31);
assert_eq!(AnimeImage::pitch(12), 30);
assert_eq!(AnimeImage::pitch(13), 30);
assert_eq!(AnimeImage::pitch(14), 29);
assert_eq!(AniMeImage::pitch(5), 34);
assert_eq!(AniMeImage::pitch(6), 33);
assert_eq!(AniMeImage::pitch(7), 33);
assert_eq!(AniMeImage::pitch(8), 32);
assert_eq!(AniMeImage::pitch(9), 32);
assert_eq!(AniMeImage::pitch(10), 31);
assert_eq!(AniMeImage::pitch(11), 31);
assert_eq!(AniMeImage::pitch(12), 30);
assert_eq!(AniMeImage::pitch(13), 30);
assert_eq!(AniMeImage::pitch(14), 29);
}
}

View File

@@ -1,5 +1,6 @@
use std::error::Error;
use std::fmt;
use gif::DecodingError;
use png_pong::decode::Error as PngError;
#[derive(Debug)]
@@ -7,6 +8,7 @@ pub enum AnimeError {
NoFrames,
Io(std::io::Error),
Png(PngError),
Gif(DecodingError),
Format
}
@@ -17,6 +19,7 @@ impl fmt::Display for AnimeError {
AnimeError::NoFrames => write!(f, "No frames in PNG"),
AnimeError::Io(e) => write!(f, "Could not open: {}", e),
AnimeError::Png(e) => write!(f, "PNG error: {}", e),
AnimeError::Gif(e) => write!(f, "GIF error: {}", e),
AnimeError::Format => write!(f, "PNG file is not 8bit greyscale"),
}
}
@@ -34,4 +37,10 @@ impl From<PngError> for AnimeError {
fn from(err: PngError) -> Self {
AnimeError::Png(err)
}
}
impl From<DecodingError> for AnimeError {
fn from(err: DecodingError) -> Self {
AnimeError::Gif(err)
}
}

View File

@@ -1,6 +1,9 @@
use serde_derive::{Deserialize, Serialize};
/// The main data conversion for transfering in shortform over dbus or other,
/// or writing directly to the USB device
mod anime_data;
use std::{path::Path, time::Duration};
pub use anime_data::*;
/// Useful for specialised effects that required a grid of data
@@ -14,5 +17,55 @@ pub use anime_image::*;
mod anime_diagonal;
pub use anime_diagonal::*;
mod anime_gif;
pub use anime_gif::*;
use error::AnimeError;
/// Base errors that are possible
pub mod error;
pub mod error;
// TODO: make schema to rebuild the full sequence without requiring saving the actual
// packet data
#[derive(Debug, Clone, Deserialize, Serialize)]
pub enum AniMeSequence {
/// Full gif sequence. Immutable.
Animation(AniMeGif),
/// Basic image, can have properties changed
Image(Box<AniMeDataBuffer>),
/// A pause to be used between sequences
Pause(Duration),
}
impl AniMeSequence {
pub fn gif(file: &Path, brightness: f32) -> Result<Self, AnimeError> {
let frames = AniMeGif::new(file, brightness)?;
Ok(Self::Animation(frames))
}
pub fn png(
file: &Path,
scale: Vec2,
angle: f32,
translation: Vec2,
brightness: f32,
) -> Result<Self, AnimeError> {
let image = AniMeImage::from_png(file, scale, angle, translation, brightness)?;
let data = <AniMeDataBuffer>::from(&image);
Ok(Self::Image(Box::new(data)))
}
pub fn get_animation(&self) -> Option<&AniMeGif> {
match self {
AniMeSequence::Animation(anim) => Some(anim),
_ => None,
}
}
pub fn get_image(&self) -> Option<&AniMeDataBuffer> {
match self {
AniMeSequence::Image(image) => Some(image),
_ => None,
}
}
}