Skip to main content

libbitsub_core/pgs/
palette.rs

1//! Palette Definition Segment parsing.
2
3use crate::utils::{BigEndianReader, ycbcr_to_rgba};
4
5/// Palette Definition Segment contains color palette entries.
6#[derive(Debug, Clone)]
7pub struct PaletteDefinitionSegment {
8    /// Palette ID (0-7)
9    pub id: u8,
10    /// Version number for this palette
11    pub version: u8,
12    /// RGBA colors indexed by palette entry ID (up to 256 entries)
13    /// Stored as packed u32: [R, G, B, A] in little-endian byte order
14    pub rgba: Vec<u32>,
15}
16
17impl PaletteDefinitionSegment {
18    /// Parse a palette definition segment from binary data.
19    pub fn parse(reader: &mut BigEndianReader, length: usize) -> Option<Self> {
20        let id = reader.read_u8()?;
21        let version = reader.read_u8()?;
22
23        // Each palette entry is 5 bytes: ID, Y, Cr, Cb, A
24        let entry_count = (length - 2) / 5;
25
26        // Pre-allocate with default transparent (256 possible entries)
27        let mut rgba = vec![0u32; 256];
28
29        for _ in 0..entry_count {
30            let entry_id = reader.read_u8()? as usize;
31            let y = reader.read_u8()?;
32            let cr = reader.read_u8()?; // PGS stores Cr before Cb
33            let cb = reader.read_u8()?;
34            let a = reader.read_u8()?;
35
36            // Convert YCbCr to RGBA and store at entry index
37            // PGS palette order is: Y, Cr, Cb, A
38            // ycbcr_to_rgba expects: y, cb, cr, a
39            if entry_id < 256 {
40                rgba[entry_id] = ycbcr_to_rgba(y, cb, cr, a);
41            }
42        }
43
44        Some(Self { id, version, rgba })
45    }
46
47    /// Create an empty palette with default transparent values.
48    pub fn empty() -> Self {
49        Self {
50            id: 0,
51            version: 0,
52            rgba: vec![0u32; 256],
53        }
54    }
55}