use alloc::vec;
use alloc::vec::Vec;
#[allow(unused_imports)]
use whereat::at;
use crate::decoder::{DecodeConfig, DecodeError, LoopCount, UpsamplingMethod, WebPDecoder};
#[derive(Debug, Clone, Copy)]
pub struct FrameInfo {
pub width: u32,
pub height: u32,
pub timestamp_ms: u32,
pub duration_ms: u32,
}
#[derive(Debug, Clone)]
pub struct AnimFrame {
pub data: Vec<u8>,
pub width: u32,
pub height: u32,
pub timestamp_ms: u32,
pub duration_ms: u32,
}
#[derive(Debug, Clone)]
pub struct AnimationInfo {
pub canvas_width: u32,
pub canvas_height: u32,
pub frame_count: u32,
pub loop_count: LoopCount,
pub background_color: [u8; 4],
pub has_alpha: bool,
}
pub struct AnimationDecoder<'a> {
decoder: WebPDecoder<'a>,
buf: Vec<u8>,
cumulative_ms: u32,
frames_read: u32,
total_frames: u32,
stop: Option<&'a dyn enough::Stop>,
}
impl<'a> AnimationDecoder<'a> {
pub fn new(data: &'a [u8]) -> Result<Self, DecodeError> {
Ok(Self::new_with_config(data, &DecodeConfig::default())?)
}
pub fn new_with_config(
data: &'a [u8],
config: &DecodeConfig,
) -> Result<Self, whereat::At<DecodeError>> {
let mut decoder = WebPDecoder::new_with_options(data, config.to_options())?;
decoder.set_limits(config.limits.clone());
if !decoder.is_animated() {
return Err(at!(DecodeError::InvalidParameter(
alloc::string::String::from("not an animated WebP"),
)));
}
let total_frames = decoder.num_frames();
let buf_size = decoder
.output_buffer_size()
.ok_or_else(|| at!(DecodeError::ImageTooLarge))?;
let buf = vec![0u8; buf_size];
Ok(Self {
decoder,
buf,
cumulative_ms: 0,
frames_read: 0,
total_frames,
stop: None,
})
}
pub fn info(&self) -> AnimationInfo {
let (w, h) = self.decoder.dimensions();
AnimationInfo {
canvas_width: w,
canvas_height: h,
frame_count: self.total_frames,
loop_count: self.decoder.loop_count(),
background_color: self.decoder.background_color_hint().unwrap_or([0, 0, 0, 0]),
has_alpha: self.decoder.has_alpha(),
}
}
pub fn has_more_frames(&self) -> bool {
self.frames_read < self.total_frames
}
pub fn frames_read(&self) -> u32 {
self.frames_read
}
pub fn set_memory_limit(&mut self, limit: usize) {
self.decoder.set_memory_limit(limit);
}
pub fn set_background_color(&mut self, color: [u8; 4]) -> Result<(), DecodeError> {
Ok(self.decoder.set_background_color(color)?)
}
pub fn set_stop(&mut self, stop: &'a dyn enough::Stop) {
self.stop = Some(stop);
self.decoder.set_stop(Some(stop));
}
pub fn set_lossy_upsampling(&mut self, method: UpsamplingMethod) {
self.decoder.set_lossy_upsampling(method);
}
pub fn icc_profile(&mut self) -> Result<Option<Vec<u8>>, DecodeError> {
Ok(self.decoder.icc_profile()?)
}
pub fn exif_metadata(&mut self) -> Result<Option<Vec<u8>>, DecodeError> {
Ok(self.decoder.exif_metadata()?)
}
pub fn xmp_metadata(&mut self) -> Result<Option<Vec<u8>>, DecodeError> {
Ok(self.decoder.xmp_metadata()?)
}
pub fn loop_duration(&self) -> u64 {
self.decoder.loop_duration()
}
pub fn next_frame(&mut self) -> Result<Option<AnimFrame>, DecodeError> {
let info = match self.decode_next()? {
Some(info) => info,
None => return Ok(None),
};
Ok(Some(AnimFrame {
data: self.buf.clone(),
width: info.width,
height: info.height,
timestamp_ms: info.timestamp_ms,
duration_ms: info.duration_ms,
}))
}
pub fn decode_next(&mut self) -> Result<Option<FrameInfo>, DecodeError> {
if let Some(stop) = self.stop {
stop.check()?;
}
match self.decoder.read_frame(&mut self.buf) {
Ok(duration_ms) => {
let timestamp_ms = self.cumulative_ms;
self.cumulative_ms = self.cumulative_ms.saturating_add(duration_ms);
self.frames_read += 1;
let (w, h) = self.decoder.dimensions();
Ok(Some(FrameInfo {
width: w,
height: h,
timestamp_ms,
duration_ms,
}))
}
Err(ref e) if matches!(e.error(), DecodeError::NoMoreFrames) => Ok(None),
Err(e) => Err(e.into()),
}
}
#[inline]
pub fn current_frame_data(&self) -> &[u8] {
&self.buf
}
pub fn reset(&mut self) -> Result<(), DecodeError> {
self.decoder.reset_animation()?;
self.cumulative_ms = 0;
self.frames_read = 0;
Ok(())
}
pub fn decode_all(&mut self) -> Result<Vec<AnimFrame>, DecodeError> {
self.reset()?;
let mut frames = Vec::with_capacity(self.total_frames as usize);
while let Some(frame) = self.next_frame()? {
frames.push(frame);
}
Ok(frames)
}
}
impl Iterator for AnimationDecoder<'_> {
type Item = Result<AnimFrame, DecodeError>;
fn next(&mut self) -> Option<Self::Item> {
match self.next_frame() {
Ok(Some(frame)) => Some(Ok(frame)),
Ok(None) => None,
Err(e) => Some(Err(e)),
}
}
}