lottieconv 0.2.2

Convert lottie files to WEBP or GIF
Documentation
use crate::{convert::Convert, Rgba};
use gif_crate::{DisposalMethod, Encoder, EncodingError, Frame, Repeat};
use rgb::{alt::BGRA8, RGBA8};
use rlottie::Size;
use std::io::Write;

auto_vectorize! {
	pub(crate) fn argb_to_rgba(bg: Rgba, buffer_argb: &[BGRA8], buffer_rgba: &mut [RGBA8]) {
		let bg_r = bg.r as u32;
		let bg_g = bg.g as u32;
		let bg_b = bg.b as u32;

		buffer_argb
			.iter()
			.map(|color| (color.r as u32, color.g as u32, color.b as u32, color.a))
			.map(|(mut r, mut g, mut b, mut a)| {
				if a == 0 {
					r = 0;
					g = 0;
					b = 0;
				}

				let a_neg = (255 - a) as u32;
				r += (bg_r * a_neg) / 255;
				g += (bg_g * a_neg) / 255;
				b += (bg_b * a_neg) / 255;

				if !bg.a || a != 0 {
					a = 255;
				}

				(r, g, b, a)
			})
			.zip(buffer_rgba.iter_mut())
			.for_each(|((r, g, b, a), rgba)| {
				rgba.r = r as u8;
				rgba.g = g as u8;
				rgba.b = b as u8;
				rgba.a = a;
			});
	}
}

pub(super) type Result<T> = std::result::Result<T, EncodingError>;

pub struct Convert2Gif<W: Write> {
	bg: Rgba,
	width: u16,
	height: u16,
	encoder: Encoder<W>,
	delay: u16
}

impl<W: Write> Convert2Gif<W> {
	pub(super) fn new(bg: Rgba, out: W, size: Size, framerate: f64) -> Result<Self> {
		let width = size.width as u16;
		let height = size.height as u16;
		let mut encoder = Encoder::new(out, width, height, &[])?;
		encoder.set_repeat(Repeat::Infinite)?;
		Ok(Self {
			bg,
			width,
			height,
			encoder,
			delay: (100.0 / framerate).round() as _
		})
	}
}

impl<W: Write> Convert for Convert2Gif<W> {
	type Out = ();
	type Err = EncodingError;

	fn convert_frame(&self, from: &[BGRA8], to: &mut [RGBA8]) {
		argb_to_rgba(self.bg, from, to)
	}

	fn add_frame(&mut self, data: &mut [u8]) -> Result<()> {
		let mut frame = Frame::from_rgba_speed(self.width, self.height, data, 10);
		frame.delay = self.delay;
		if self.bg.a {
			frame.dispose = DisposalMethod::Background;
		}
		self.encoder.write_frame(&frame)
	}

	fn finish(self) -> Result<Self::Out> {
		Ok(())
	}
}