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