webp_animation/
frame.rs

1use std::fmt::Debug;
2
3#[cfg(feature = "image")]
4use image::ImageBuffer;
5
6#[allow(unused_imports)]
7use crate::{ColorMode, Decoder, Error};
8
9/// An animation frame containing data and metadata produced by [`Decoder`]
10///
11/// Getting metadata:
12/// ```rust
13/// # use webp_animation::{Decoder, ColorMode};
14/// #
15/// # let buffer = std::fs::read("./data/animated.webp").unwrap();
16/// # let decoder = Decoder::new(&buffer).unwrap();
17/// # let frame = decoder.into_iter().next().unwrap();
18/// #
19/// assert_eq!(frame.dimensions(), (400, 400));
20/// assert_eq!(frame.color_mode(), ColorMode::Rgba);
21/// ```
22///
23/// Accessing frame data in raw [`ColorMode`] -encoded bytes:
24/// ```rust
25/// # use webp_animation::{Decoder, ColorMode};
26/// #
27/// # let buffer = std::fs::read("./data/animated.webp").unwrap();
28/// # let decoder = Decoder::new(&buffer).unwrap();
29/// # let frame = decoder.into_iter().next().unwrap();
30/// #
31/// assert_eq!(frame.data().len(), (400 * 400 * 4));
32/// assert_eq!(frame.data()[0..4], [0, 0, 0, 255]);
33/// ```
34///
35/// If `image` feature is enabled, frame can be converted into [`image::ImageBuffer`]:
36/// ```rust
37/// # use webp_animation::{Decoder, ColorMode};
38/// #
39/// # let buffer = std::fs::read("./data/animated.webp").unwrap();
40/// # let decoder = Decoder::new(&buffer).unwrap();
41/// # let frame = decoder.into_iter().next().unwrap();
42/// #
43/// ##[cfg(feature = "image")]
44/// let image = frame.into_image().unwrap();
45/// ##[cfg(feature = "image")]
46/// assert_eq!(image.dimensions(), (400, 400));
47/// ##[cfg(feature = "image")]
48/// assert_eq!(image.height(), 400);
49/// // image.save("frame.png");
50/// ```
51pub struct Frame {
52    timestamp: i32,
53    frame_data: Vec<u8>,
54
55    #[allow(dead_code)]
56    color_mode: ColorMode,
57    dimensions: (u32, u32),
58}
59
60impl Frame {
61    pub(crate) fn new_from_decoder(
62        timestamp: i32,
63        color_mode: ColorMode,
64        frame_data: Vec<u8>,
65        dimensions: (u32, u32),
66    ) -> Self {
67        Self {
68            timestamp,
69            color_mode,
70            frame_data,
71            dimensions,
72        }
73    }
74
75    /// Get dimensions of the frame (`width`, `height`)
76    pub fn dimensions(&self) -> (u32, u32) {
77        self.dimensions
78    }
79
80    /// Get [`ColorMode`] of the frame (consistent accross frames)
81    pub fn color_mode(&self) -> ColorMode {
82        self.color_mode
83    }
84
85    /// Get timestamp of the frame in milliseconds
86    pub fn timestamp(&self) -> i32 {
87        self.timestamp
88    }
89
90    /// Get decoded frame data, size `width` * `height` * 4, pixels in [`ColorMode`] format
91    pub fn data(&self) -> &[u8] {
92        &self.frame_data
93    }
94
95    /// Convert the frame to [`image::ImageBuffer`] in `Rgba<u8>` format
96    ///
97    /// Must have [`ColorMode`] set to [`ColorMode::Rgba`] (default) when creating
98    /// [`Decoder`]
99    ///
100    /// Requires feature `image` to be enabled
101    ///
102    /// ```
103    /// # use webp_animation::{Decoder, DecoderOptions, ColorMode};
104    /// #
105    /// let buffer = std::fs::read("./data/animated.webp").unwrap();
106    /// let decoder = Decoder::new(&buffer).unwrap();
107    /// let frame = decoder.into_iter().next().unwrap();
108    /// let _image = frame.into_image().unwrap();
109    /// // _image.save("my_frame.jpg");
110    /// ```
111    #[cfg(feature = "image")]
112    pub fn into_image(self) -> Result<ImageBuffer<image::Rgba<u8>, Vec<u8>>, Error> {
113        self.into_rgba_image()
114    }
115
116    /// Convert the frame to [`image::ImageBuffer`] in `Rgba<u8>` format
117    ///
118    /// Must have [`ColorMode`] set to [`ColorMode::Rgba`] (default) when creating
119    /// [`Decoder`]
120    #[cfg(feature = "image")]
121    pub fn into_rgba_image(self) -> Result<ImageBuffer<image::Rgba<u8>, Vec<u8>>, Error> {
122        if self.color_mode != ColorMode::Rgba {
123            return Err(Error::WrongColorMode(self.color_mode, ColorMode::Rgba));
124        }
125
126        Ok(ImageBuffer::from_vec(self.dimensions.0, self.dimensions.1, self.frame_data).unwrap())
127    }
128}
129
130impl Debug for Frame {
131    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
132        write!(
133            f,
134            "Frame {{ timestamp: {}, frame_data: {}b }}",
135            self.timestamp,
136            self.frame_data.len()
137        )
138    }
139}