libbitsub_core/pgs/
rle.rs1#[inline]
18pub fn decode_rle_to_indexed(data: &[u8], target: &mut [u8]) -> usize {
19 let mut idx = 0;
20 let mut pos = 0;
21 let len = data.len();
22 let target_len = target.len();
23
24 while pos < len && idx < target_len {
25 let byte1 = data[pos];
26 pos += 1;
27
28 if byte1 != 0 {
30 target[idx] = byte1;
31 idx += 1;
32 continue;
33 }
34
35 if pos >= len {
37 break;
38 }
39
40 let byte2 = data[pos];
41 pos += 1;
42
43 if byte2 == 0 {
45 continue;
46 }
47
48 let (count, value) = if byte2 & 0xC0 == 0xC0 {
50 let high = (byte2 & 0x3F) as usize;
52 let low = data.get(pos).copied().unwrap_or(0) as usize;
53 pos += 1;
54 let color = data.get(pos).copied().unwrap_or(0);
55 pos += 1;
56 ((high << 8) | low, color)
57 } else if byte2 & 0x80 != 0 {
58 let count = (byte2 & 0x3F) as usize;
60 let color = data.get(pos).copied().unwrap_or(0);
61 pos += 1;
62 (count, color)
63 } else if byte2 & 0x40 != 0 {
64 let high = (byte2 & 0x3F) as usize;
66 let low = data.get(pos).copied().unwrap_or(0) as usize;
67 pos += 1;
68 ((high << 8) | low, 0)
69 } else {
70 ((byte2 & 0x3F) as usize, 0)
72 };
73
74 let end = (idx + count).min(target_len);
76 if count > 8 {
77 target[idx..end].fill(value);
78 } else {
79 while idx < end {
81 target[idx] = value;
82 idx += 1;
83 }
84 }
85 idx = end;
86 }
87
88 idx
89}
90
91#[inline]
96pub fn decode_rle_to_rgba(data: &[u8], palette: &[u32], target: &mut [u32]) -> usize {
97 let mut idx = 0;
98 let mut pos = 0;
99 let len = data.len();
100 let target_len = target.len();
101 let palette_len = palette.len();
102
103 let transparent = if palette_len > 0 { palette[0] } else { 0 };
105
106 while pos < len && idx < target_len {
107 let byte1 = data[pos];
108 pos += 1;
109
110 if byte1 != 0 {
112 let color = if (byte1 as usize) < palette_len {
113 palette[byte1 as usize]
114 } else {
115 0
116 };
117 target[idx] = color;
118 idx += 1;
119 continue;
120 }
121
122 if pos >= len {
124 break;
125 }
126
127 let byte2 = data[pos];
128 pos += 1;
129
130 if byte2 == 0 {
132 continue;
133 }
134
135 let (count, color) = if byte2 & 0xC0 == 0xC0 {
137 let high = (byte2 & 0x3F) as usize;
139 let low = data.get(pos).copied().unwrap_or(0) as usize;
140 pos += 1;
141 let color_idx = data.get(pos).copied().unwrap_or(0) as usize;
142 pos += 1;
143 let color = if color_idx < palette_len {
144 palette[color_idx]
145 } else {
146 0
147 };
148 ((high << 8) | low, color)
149 } else if byte2 & 0x80 != 0 {
150 let count = (byte2 & 0x3F) as usize;
152 let color_idx = data.get(pos).copied().unwrap_or(0) as usize;
153 pos += 1;
154 let color = if color_idx < palette_len {
155 palette[color_idx]
156 } else {
157 0
158 };
159 (count, color)
160 } else if byte2 & 0x40 != 0 {
161 let high = (byte2 & 0x3F) as usize;
163 let low = data.get(pos).copied().unwrap_or(0) as usize;
164 pos += 1;
165 ((high << 8) | low, transparent)
166 } else {
167 ((byte2 & 0x3F) as usize, transparent)
169 };
170
171 let end = (idx + count).min(target_len);
173 if count > 8 {
174 target[idx..end].fill(color);
175 } else {
176 while idx < end {
177 target[idx] = color;
178 idx += 1;
179 }
180 }
181 idx = end;
182 }
183
184 idx
185}
186
187#[inline]
190pub fn apply_palette(indexed: &[u8], palette: &[u32], target: &mut [u32]) {
191 let len = indexed.len().min(target.len());
192
193 if palette.len() >= 256 {
195 let chunks = len / 8;
198 let remainder = len % 8;
199
200 for chunk in 0..chunks {
201 let base = chunk * 8;
202 target[base] = palette[indexed[base] as usize];
204 target[base + 1] = palette[indexed[base + 1] as usize];
205 target[base + 2] = palette[indexed[base + 2] as usize];
206 target[base + 3] = palette[indexed[base + 3] as usize];
207 target[base + 4] = palette[indexed[base + 4] as usize];
208 target[base + 5] = palette[indexed[base + 5] as usize];
209 target[base + 6] = palette[indexed[base + 6] as usize];
210 target[base + 7] = palette[indexed[base + 7] as usize];
211 }
212
213 let base = chunks * 8;
215 for i in 0..remainder {
216 target[base + i] = palette[indexed[base + i] as usize];
217 }
218 } else {
219 let palette_len = palette.len();
221 for i in 0..len {
222 let idx = indexed[i] as usize;
223 target[i] = if idx < palette_len { palette[idx] } else { 0 };
224 }
225 }
226}
227
228#[inline]
230pub fn apply_palette_rgba_bytes(indexed: &[u8], palette: &[u32], target: &mut [u8]) {
231 let len = indexed.len().min(target.len() / 4);
232
233 if palette.len() >= 256 {
234 for (pixel_index, &palette_index) in indexed.iter().take(len).enumerate() {
235 let start = pixel_index * 4;
236 target[start..start + 4]
237 .copy_from_slice(&palette[palette_index as usize].to_le_bytes());
238 }
239 } else {
240 let palette_len = palette.len();
241 for (pixel_index, &palette_index) in indexed.iter().take(len).enumerate() {
242 let start = pixel_index * 4;
243 let rgba = if (palette_index as usize) < palette_len {
244 palette[palette_index as usize]
245 } else {
246 0
247 };
248 target[start..start + 4].copy_from_slice(&rgba.to_le_bytes());
249 }
250 }
251}
252
253#[cfg(test)]
254mod tests {
255 use super::*;
256
257 #[test]
258 fn test_decode_literal() {
259 let data = [1, 2, 3, 4, 5];
261 let mut target = vec![0u8; 10];
262 let count = decode_rle_to_indexed(&data, &mut target);
263 assert_eq!(count, 5);
264 assert_eq!(&target[..5], &[1, 2, 3, 4, 5]);
265 }
266
267 #[test]
268 fn test_decode_short_run_transparent() {
269 let data = [0x00, 0x05];
271 let mut target = vec![0xFFu8; 10];
272 let count = decode_rle_to_indexed(&data, &mut target);
273 assert_eq!(count, 5);
274 assert_eq!(&target[..5], &[0, 0, 0, 0, 0]);
275 }
276
277 #[test]
278 fn test_decode_short_run_color() {
279 let data = [0x00, 0x85, 0x07];
281 let mut target = vec![0u8; 10];
282 let count = decode_rle_to_indexed(&data, &mut target);
283 assert_eq!(count, 5);
284 assert_eq!(&target[..5], &[7, 7, 7, 7, 7]);
285 }
286
287 #[test]
288 fn test_decode_end_of_line() {
289 let data = [0x01, 0x00, 0x00, 0x02];
291 let mut target = vec![0u8; 10];
292 let count = decode_rle_to_indexed(&data, &mut target);
293 assert_eq!(count, 2);
294 assert_eq!(&target[..2], &[1, 2]);
295 }
296}