cpclib_image/
ocp.rs

1use crate::ga::{Ink, Palette};
2use crate::image::Mode;
3
4/// ! Utility code related to OCP
5
6pub fn compress<D: as_slice::AsSlice<Element = u8>>(data: D) -> Vec<u8> {
7    eprintln!("[WARNING] OCP compression has never been tested");
8
9    let data = data.as_slice();
10    const MARKER: u8 = 1;
11
12    let mut res = Vec::new();
13
14    res.push(b'M');
15    res.push(b'J');
16    res.push(b'H');
17
18    let length = data.len();
19    let high = (length >> 8) as u8;
20    let low = (length % 256) as u8;
21
22    res.push(low);
23    res.push(high);
24
25    let mut previous = 0;
26    let mut count = 0;
27
28    for current in &data[1..] {
29        let current = *current;
30
31        if current == MARKER {
32            if count != 0 {
33                res.push(MARKER);
34                res.push(count);
35                res.push(previous);
36            }
37
38            res.push(MARKER);
39            res.push(1);
40            res.push(MARKER);
41        }
42        else if previous == current {
43            if count == 255 {
44                res.push(MARKER);
45                res.push(0);
46                res.push(current);
47                count = 0;
48            }
49            else {
50                count += 1;
51            }
52        }
53        else {
54            if count == 1 {
55                debug_assert!(MARKER != current);
56                res.push(current);
57            }
58            else {
59                res.push(MARKER);
60                res.push(count);
61                res.push(current);
62            }
63            count = 0;
64        }
65
66        previous = current;
67    }
68
69    if count == 1 {
70        res.push(previous);
71    }
72    else if count > 1 {
73        res.push(MARKER);
74        res.push(count);
75        res.push(previous);
76    }
77
78    res
79}
80
81const NB_PAL: usize = 12;
82
83pub struct OcpPal {
84    screen_mode: Mode,
85    cycling: bool,
86    cycling_delay: u8,
87    palettes: [Palette; NB_PAL],
88
89    excluded: [u8; 16],
90    projected: [u8; 16]
91}
92
93impl OcpPal {
94    /// Get the palette of interest (0..12)
95    pub fn palette(&self, nb: usize) -> &Palette {
96        assert!(nb < 12);
97        &self.palettes[nb]
98    }
99
100    pub fn from_buffer(data: &[u8]) -> Self {
101        let mut data = data.iter().cloned();
102
103        let screen_mode: Mode = (data.next().unwrap()).into();
104        let cycling = data.next().unwrap() == 0xFF;
105        let cycling_delay = data.next().unwrap();
106
107        let mut palettes: [Palette; NB_PAL] = Default::default(); // arrays::from_iter((0..NB_PAL).into_iter().map(|_| Palette::default())).unwrap();
108        for pen in 0..=16i32 {
109            for idx in 0..NB_PAL {
110                let ga_ink = data.next().unwrap();
111                let ink = Ink::from_gate_array_color_number(ga_ink);
112                dbg!(pen, idx, ink);
113                palettes[idx].set(pen, ink);
114            }
115        }
116
117        let excluded = data.next_chunk().unwrap();
118        let projected = data.next_chunk().unwrap();
119
120        assert!(data.next().is_none());
121
122        Self {
123            screen_mode,
124            cycling,
125            cycling_delay,
126            palettes,
127            excluded,
128            projected
129        }
130    }
131}