Skip to content

Commit

Permalink
Render frames onto new Surface struct (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
msrd0 authored Apr 3, 2022
1 parent df4343d commit 7b6ccdb
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 49 deletions.
17 changes: 9 additions & 8 deletions lottie2gif/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Convert lottie animations to GIF files.

#![warn(rust_2018_idioms)]
#![deny(unreachable_pub)]
#![deny(elided_lifetimes_in_paths, unreachable_pub)]

use gif::{DisposalMethod, Encoder, EncodingError, Frame, Repeat};
use rgb::{alt::BGRA8, RGBA8};
use rlottie::Surface;
use std::{
fmt::{self, Display, Formatter},
io::Write,
Expand Down Expand Up @@ -139,16 +140,16 @@ pub fn convert<W: Write>(
let size = player.size();
let framerate = player.framerate();
let delay = (100.0 / framerate).round() as u16;
let buffer_len = size.width() as usize * size.height() as usize;
let mut buffer_argb = Vec::with_capacity(buffer_len);
let buffer_len = size.width * size.height;
let mut surface = Surface::new(size);
let mut buffer_rgba = vec![RGBA8::default(); buffer_len];
let frame_count = player.totalframe();

let mut gif = Encoder::new(out, size.width() as _, size.height() as _, &[])?;
let mut gif = Encoder::new(out, size.width as _, size.height as _, &[])?;
gif.set_repeat(Repeat::Infinite)?;
for frame in 0 .. frame_count {
player.render(frame, &mut buffer_argb, size).unwrap();
argb_to_rgba(bg, &buffer_argb, &mut buffer_rgba);
player.render(frame, &mut surface);
argb_to_rgba(bg, surface.data(), &mut buffer_rgba);

let mut frame = {
// Safety: The pointer is valid and aligned since it comes from a vec, and we don't
Expand All @@ -160,8 +161,8 @@ pub fn convert<W: Write>(
)
};
Frame::from_rgba_speed(
size.width() as _,
size.height() as _,
size.width as _,
size.height as _,
buffer_rgba,
10
)
Expand Down
19 changes: 13 additions & 6 deletions lottie2webp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
//! Convert lottie animations to WEBP files.

#![warn(rust_2018_idioms)]
#![deny(elided_lifetimes_in_paths, unreachable_pub)]

use rgb::{alt::BGRA8, RGBA8};
use rlottie::Animation;
use rlottie::Surface;
use std::slice;
use webp_animation::{Encoder, WebPData};

pub use rlottie::Animation;

#[macro_use]
mod util;

Expand All @@ -21,16 +28,16 @@ pub fn convert(mut player: Animation) -> Result<WebPData, webp_animation::Error>
let size = player.size();
let framerate = player.framerate();
let delay = 1000.0 / framerate;
let buffer_len = size.width() as usize * size.height() as usize;
let mut buffer_argb = Vec::with_capacity(buffer_len);
let buffer_len = size.width * size.height;
let mut surface = Surface::new(size);
let mut buffer_rgba = vec![RGBA8::default(); buffer_len];
let frame_count = player.totalframe();

let mut webp = Encoder::new((size.width() as u32, size.height() as u32))?;
let mut webp = Encoder::new((size.width as _, size.height as _))?;
let mut timestamp: f64 = 0.0;
for frame in 0 .. frame_count {
player.render(frame, &mut buffer_argb, size).unwrap();
bgra_to_rgba(&buffer_argb, &mut buffer_rgba);
player.render(frame, &mut surface);
bgra_to_rgba(surface.data(), &mut buffer_rgba);

{
// Safety: The pointer is valid and aligned since it comes from a vec, and we don't
Expand Down
89 changes: 54 additions & 35 deletions rlottie/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ impl Size {
pub const fn new(width: usize, height: usize) -> Self {
Self { width, height }
}

pub const fn width(&self) -> usize {
self.width
}

pub const fn height(&self) -> usize {
self.height
}
}

/// It is very important that [`BGRA8`] and `u32` have exactly the same size. This
Expand Down Expand Up @@ -67,6 +59,53 @@ mod bgra8_size {
};
}

/// A surface has a fixed size and contains pixel data for it. You can render frames onto
/// the surface.
pub struct Surface {
data: Vec<BGRA8>,
size: Size
}

impl Surface {
/// Create a new surface with a fixed size.
pub fn new(size: Size) -> Self {
Self {
data: Vec::with_capacity(size.width * size.height),
size
}
}

/// Return the size of the surface.
pub fn size(&self) -> Size {
self.size
}

/// Return the width of the surface.
pub fn width(&self) -> usize {
self.size.width
}

/// Return the height of the surface.
pub fn height(&self) -> usize {
self.size.height
}

/// Return the pixel data of the surface.
pub fn data(&self) -> &[BGRA8] {
&self.data
}

/// Return a pointer to the pixel data.
fn as_mut_ptr(&mut self) -> *mut u32 {
self.data.as_mut_ptr() as *mut u32
}

/// Set the length of the pixel data to `width * height`.
unsafe fn set_len(&mut self) {
self.data.set_len(self.width() * self.height())
}
}

/// A lottie animation.
pub struct Animation(*mut Lottie_Animation_S);

Expand Down Expand Up @@ -147,38 +186,18 @@ impl Animation {
unsafe { lottie_animation_get_frame_at_pos(self.0, pos) }
}

/// Render the contents of a frame into the buffer at a certain viewport size.
///
/// The buffer's capacity must be at least `size.width * size.height`. It's
/// initial length or content doesn't matter. The first `size.width * size.height`
/// bytes of the buffer will be written to; and it's length will be set exactly
/// to `size.width * size.height`.
///
/// This operation will fail only if the buffer's capacity isn't large enough.
pub fn render(
&mut self,
frame_num: usize,
buffer: &mut Vec<BGRA8>,
size: Size
) -> Result<(), RenderError> {
let buffer_len = (size.width * size.height) as usize;
if buffer.capacity() < buffer_len {
return Err(RenderError);
}
/// Render the contents of a frame onto the surface.
pub fn render(&mut self, frame_num: usize, surface: &mut Surface) {
unsafe {
lottie_animation_render(
self.0,
frame_num,
buffer.as_mut_ptr() as *mut u32,
size.width,
size.height,
size.width * 4
surface.as_mut_ptr(),
surface.width(),
surface.height(),
surface.width() * 4
);
buffer.set_len(buffer_len);
surface.set_len();
}
Ok(())
}
}

#[derive(Debug)]
pub struct RenderError;

0 comments on commit 7b6ccdb

Please sign in to comment.