Skip to main content

oxframe_core/
frame.rs

1//! Frames as pixels, and the one interface through which the editor, the
2//! CLI and the exporter get them: [`FrameSource`]. None of them needs to
3//! know what draws the frames (2D nodes today, other modules later).
4
5/// 8-bit sRGB RGBA, straight alpha, row-major, no padding.
6#[derive(Clone, PartialEq, Eq)]
7pub struct Image {
8    /// Width in pixels.
9    pub width: u32,
10    /// Height in pixels.
11    pub height: u32,
12    /// `width * height * 4` bytes.
13    pub data: Vec<u8>,
14}
15
16impl Image {
17    /// Encodes the image as PNG (8-bit RGBA, straight alpha).
18    ///
19    /// # Panics
20    ///
21    /// If `data` is not `width * height * 4` bytes — a bug in whoever
22    /// built the image.
23    #[must_use]
24    pub fn encode_png(&self) -> Vec<u8> {
25        assert_eq!(
26            self.data.len(),
27            self.width as usize * self.height as usize * 4,
28            "Image data must be width * height * 4 bytes"
29        );
30        let mut out = Vec::new();
31        let mut encoder = png::Encoder::new(&mut out, self.width, self.height);
32        encoder.set_color(png::ColorType::Rgba);
33        encoder.set_depth(png::BitDepth::Eight);
34        let mut writer = encoder.write_header().expect("in-memory PNG header");
35        writer
36            .write_image_data(&self.data)
37            .expect("in-memory PNG data");
38        writer.finish().expect("in-memory PNG");
39        out
40    }
41}
42
43impl std::fmt::Debug for Image {
44    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45        write!(f, "Image({}x{})", self.width, self.height)
46    }
47}
48
49/// A timeline that can draw any of its frames: "give me frame `n`".
50///
51/// Frames are addressed by index (time `n / fps`) so that every caller
52/// gets exactly the same pixels for the same frame, in any order.
53pub trait FrameSource {
54    /// Frames per second.
55    fn fps(&self) -> u32;
56    /// Native size in pixels.
57    fn size(&self) -> (u32, u32);
58    /// Length in frames.
59    fn total_frames(&self) -> u32;
60    /// Draws `frame` at `size` pixels (scaled to fit and centered).
61    fn render(&mut self, frame: u32, size: (u32, u32)) -> Image;
62}