Initial rudimentary Lottie parsing code

This commit is contained in:
Patrick Walton 2019-05-23 18:03:09 -07:00
parent cd23d62f3d
commit 8c4f05ce39
6 changed files with 378 additions and 0 deletions

18
Cargo.lock generated
View File

@ -957,6 +957,13 @@ dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "lottie_basic"
version = "0.1.0"
dependencies = [
"pathfinder_lottie 0.1.0",
]
[[package]]
name = "lyon_geom"
version = "0.12.4"
@ -1256,6 +1263,14 @@ dependencies = [
"rustache 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pathfinder_lottie"
version = "0.1.0"
dependencies = [
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "pathfinder_magicleap_demo"
version = "0.1.0"
@ -1753,6 +1768,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "serde"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"

View File

@ -8,9 +8,11 @@ members = [
"examples/canvas_minimal",
"examples/canvas_moire",
"examples/canvas_text",
"examples/lottie_basic",
"geometry",
"gl",
"gpu",
"lottie",
"renderer",
"simd",
"svg",

View File

@ -0,0 +1,10 @@
[package]
name = "lottie_basic"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
[dependencies.pathfinder_lottie]
path = "../../lottie"

View File

@ -0,0 +1,23 @@
// pathfinder/examples/lottie_basic/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Experimental example for reading Lottie animations. This is very incomplete.
use pathfinder_lottie::Lottie;
use std::env;
use std::fs::File;
use std::io::BufReader;
fn main() {
let path = env::args().skip(1).next().unwrap();
let file = BufReader::new(File::open(path).unwrap());
let lottie = Lottie::from_reader(file).unwrap();
println!("{:#?}", lottie);
}

12
lottie/Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "pathfinder_lottie"
version = "0.1.0"
authors = ["Patrick Walton <pcwalton@mimiga.net>"]
edition = "2018"
[dependencies]
serde_json = "1.0"
[dependencies.serde]
version = "1.0"
features = ["derive"]

313
lottie/src/lib.rs Normal file
View File

@ -0,0 +1,313 @@
// pathfinder/lottie/src/lib.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Experimental support for Lottie. This is very incomplete.
use serde::{Deserialize, Serialize};
use serde_json::Error as JSONError;
use std::io::Read;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Lottie {
#[serde(rename = "v")]
pub version: String,
#[serde(rename = "fr")]
pub frame_rate: i64,
#[serde(rename = "ip")]
pub in_point: i64,
#[serde(rename = "op")]
pub out_point: i64,
#[serde(rename = "w")]
pub width: f64,
#[serde(rename = "h")]
pub height: f64,
#[serde(rename = "ddd")]
pub three_d: i64,
pub assets: Vec<Asset>,
pub layers: Vec<Layer>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Asset {}
// FIXME(pcwalton): Using an untagged enum is a botch here. There actually is a tag: it's just an
// integer, which `serde_json` doesn't support natively.
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum Layer {
Shape {
#[serde(rename = "ddd")]
three_d: i64,
#[serde(rename = "ind")]
index: i64,
#[serde(rename = "nm")]
name: String,
#[serde(rename = "ks")]
transform: Transform,
#[serde(rename = "ao")]
auto_orient: i64,
#[serde(rename = "ip")]
in_point: i64,
#[serde(rename = "op")]
out_point: i64,
#[serde(rename = "st")]
start_time: i64,
#[serde(rename = "bm")]
blend_mode: i64,
#[serde(rename = "sr")]
stretch: i64,
#[serde(rename = "ln")]
#[serde(default)]
layer_id: Option<String>,
shapes: Vec<Shape>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Transform {
#[serde(rename = "p")]
pub position: MultidimensionalPropertyValue,
#[serde(rename = "a")]
pub anchor_point: MultidimensionalPropertyValue,
#[serde(rename = "s")]
pub scale: MultidimensionalPropertyValue,
#[serde(rename = "r")]
pub rotation: PropertyValue,
#[serde(rename = "o")]
#[serde(default)]
pub opacity: Option<PropertyValue>,
#[serde(rename = "px")]
#[serde(default)]
pub position_x: Option<PropertyValue>,
#[serde(rename = "py")]
#[serde(default)]
pub position_y: Option<PropertyValue>,
#[serde(rename = "pz")]
#[serde(default)]
pub position_z: Option<PropertyValue>,
#[serde(rename = "sk")]
#[serde(default)]
pub skew: Option<PropertyValue>,
#[serde(rename = "sa")]
#[serde(default)]
pub skew_axis: Option<PropertyValue>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum PropertyValue {
Value {
#[serde(rename = "k")]
value: f32,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
},
KeyframedValue {
#[serde(rename = "k")]
keyframes: Vec<KeyframeValue>,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KeyframeValue {
#[serde(rename = "s")]
#[serde(default)]
pub start: Option<Vec<f32>>,
#[serde(rename = "t")]
pub time: i64,
#[serde(rename = "i")]
#[serde(default)]
pub interpolation: Option<OffsetInterpolation>,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Interpolation {
pub x: f32,
pub y: f32,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OffsetInterpolation {
pub x: Vec<f32>,
pub y: Vec<f32>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct OffsetKeyframe {
#[serde(rename = "s")]
#[serde(default)]
pub start: Option<Vec<f32>>,
#[serde(rename = "t")]
pub time: i64,
#[serde(rename = "i")]
#[serde(default)]
pub in_value: Option<OffsetInterpolation>,
#[serde(rename = "o")]
#[serde(default)]
pub out_value: Option<OffsetInterpolation>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum MultidimensionalPropertyValue {
Value {
#[serde(rename = "k")]
value: Vec<f32>,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
},
KeyframedValue {
#[serde(rename = "k")]
keyframes: Vec<OffsetKeyframe>,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
#[serde(rename = "ti")]
#[serde(default)]
in_tangent: Option<i64>,
#[serde(rename = "to")]
#[serde(default)]
out_tangent: Option<i64>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "ty")]
pub enum Shape {
#[serde(rename = "gr")]
Group {
#[serde(rename = "it")]
items: Vec<Shape>,
#[serde(rename = "nm")]
name: String,
},
#[serde(rename = "sh")]
Shape {
#[serde(rename = "ks")]
vertices: ShapeVertices,
#[serde(rename = "d")]
#[serde(default)]
direction: Option<i64>,
},
#[serde(rename = "fl")]
Fill {
#[serde(rename = "nm")]
#[serde(default)]
name: Option<String>,
#[serde(rename = "o")]
#[serde(default)]
opacity: Option<PropertyValue>,
#[serde(rename = "c")]
color: MultidimensionalPropertyValue,
},
#[serde(rename = "tr")]
Transform {
#[serde(rename = "r")]
rotation: PropertyValue,
#[serde(rename = "sk")]
skew: PropertyValue,
#[serde(rename = "sa")]
skew_axis: PropertyValue,
#[serde(rename = "p")]
position: MultidimensionalPropertyValue,
#[serde(rename = "a")]
anchor_point: MultidimensionalPropertyValue,
#[serde(rename = "s")]
scale: MultidimensionalPropertyValue,
},
#[serde(other)]
Unimplemented,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ShapeVertices {
Shape {
#[serde(rename = "k")]
value: ShapeProperty,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
#[serde(rename = "a")]
animated: i64,
},
ShapeKeyframed {
#[serde(rename = "k")]
value: Vec<ShapeKeyframeProperty>,
#[serde(rename = "x")]
#[serde(default)]
expression: Option<String>,
#[serde(rename = "ix")]
#[serde(default)]
index: Option<i64>,
#[serde(rename = "a")]
animated: i64,
#[serde(rename = "ti")]
#[serde(default)]
in_tangent: Vec<i64>,
#[serde(rename = "to")]
#[serde(default)]
out_tangent: Vec<i64>,
},
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ShapeProperty {
#[serde(rename = "c")]
pub closed: bool,
#[serde(rename = "i")]
pub in_points: Vec<[f32; 2]>,
#[serde(rename = "o")]
pub out_points: Vec<[f32; 2]>,
#[serde(rename = "v")]
pub vertices: Vec<[f32; 2]>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct ShapeKeyframeProperty {
#[serde(rename = "s")]
#[serde(default)]
pub start: Vec<Option<ShapeProperty>>,
#[serde(rename = "t")]
pub time: i64,
#[serde(rename = "i")]
#[serde(default)]
pub in_value: Option<OffsetInterpolation>,
#[serde(rename = "o")]
#[serde(default)]
pub out_value: Option<OffsetInterpolation>,
}
impl Lottie {
#[inline]
pub fn from_reader<R>(reader: R) -> Result<Lottie, JSONError> where R: Read {
serde_json::from_reader(reader)
}
}