image_webp/lossless/encoder/
mod.rs1use std::io::{self, Write};
2use std::slice::ChunksExact;
3
4use crate::{ColorType, EncodingError};
5use huffman::{write_huffman_tree, write_single_entry_huffman_tree};
6
7mod huffman;
8
9struct BitWriter<W> {
10 writer: W,
11 buffer: u64,
12 nbits: u8,
13}
14
15impl<W: Write> BitWriter<W> {
16 #[inline(always)]
17 fn write_bits(&mut self, bits: u64, nbits: u8) -> io::Result<()> {
18 debug_assert!(nbits <= 64);
19
20 self.buffer |= bits << self.nbits;
21 self.nbits += nbits;
22
23 if self.nbits >= 64 {
24 self.write_bits_cold(bits, nbits)?;
25 }
26 debug_assert!(self.nbits < 64);
27 Ok(())
28 }
29
30 #[inline(never)]
31 fn write_bits_cold(&mut self, bits: u64, nbits: u8) -> io::Result<()> {
32 self.writer.write_all(&self.buffer.to_le_bytes())?;
33 self.nbits -= 64;
34 self.buffer = bits.checked_shr(u32::from(nbits - self.nbits)).unwrap_or(0);
35 Ok(())
36 }
37
38 fn flush(&mut self) -> io::Result<()> {
39 if self.nbits % 8 != 0 {
40 self.write_bits(0, 8 - self.nbits % 8)?;
41 }
42 if self.nbits > 0 {
43 self.writer
44 .write_all(&self.buffer.to_le_bytes()[..self.nbits as usize / 8])
45 .unwrap();
46 self.buffer = 0;
47 self.nbits = 0;
48 }
49 Ok(())
50 }
51}
52
53const fn length_to_symbol(len: u16) -> (u16, u8) {
54 let len = len - 1;
55 let highest_bit = len.ilog2() as u16;
56 let second_highest_bit = (len >> (highest_bit - 1)) & 1;
57 let extra_bits = highest_bit - 1;
58 let symbol = 2 * highest_bit + second_highest_bit;
59 (symbol, extra_bits as u8)
60}
61
62#[inline(always)]
63fn count_run(
64 pixel: &[u8],
65 it: &mut std::iter::Peekable<ChunksExact<u8>>,
66 frequencies1: &mut [u32; 280],
67) {
68 let mut run_length = 0;
69 while run_length < 4096 && it.peek() == Some(&pixel) {
70 run_length += 1;
71 it.next();
72 }
73 if run_length > 0 {
74 if run_length <= 4 {
75 let symbol = 256 + run_length - 1;
76 frequencies1[symbol] += 1;
77 } else {
78 let (symbol, _extra_bits) = length_to_symbol(run_length as u16);
79 frequencies1[256 + symbol as usize] += 1;
80 }
81 }
82}
83
84#[inline(always)]
85fn write_run<W: Write>(
86 w: &mut BitWriter<W>,
87 pixel: &[u8],
88 it: &mut std::iter::Peekable<ChunksExact<u8>>,
89 codes1: &[u16; 280],
90 lengths1: &[u8; 280],
91) -> io::Result<()> {
92 let mut run_length = 0;
93 while run_length < 4096 && it.peek() == Some(&pixel) {
94 run_length += 1;
95 it.next();
96 }
97 if run_length > 0 {
98 if run_length <= 4 {
99 let symbol = 256 + run_length - 1;
100 w.write_bits(u64::from(codes1[symbol]), lengths1[symbol])?;
101 } else {
102 let (symbol, extra_bits) = length_to_symbol(run_length as u16);
103 w.write_bits(
104 u64::from(codes1[256 + symbol as usize]),
105 lengths1[256 + symbol as usize],
106 )?;
107 w.write_bits(
108 (run_length as u64 - 1) & ((1 << extra_bits) - 1),
109 extra_bits,
110 )?;
111 }
112 }
113 Ok(())
114}
115
116#[non_exhaustive]
120#[derive(Clone, Debug)]
121pub struct EncoderParams {
122 pub use_predictor_transform: bool,
124 pub use_lossy: bool,
126 pub lossy_quality: u8,
128}
129
130impl Default for EncoderParams {
131 fn default() -> Self {
132 Self {
133 use_predictor_transform: true,
134 use_lossy: false,
135 lossy_quality: 95,
136 }
137 }
138}
139
140pub(crate) fn encode_frame_lossless<W: Write>(
146 writer: W,
147 data: &[u8],
148 width: u32,
149 height: u32,
150 color: ColorType,
151 params: EncoderParams,
152 implicit_dimensions: bool,
153) -> Result<(), EncodingError> {
154 let w = &mut BitWriter {
155 writer,
156 buffer: 0,
157 nbits: 0,
158 };
159
160 let (is_color, is_alpha, bytes_per_pixel) = match color {
161 ColorType::L8 => (false, false, 1),
162 ColorType::La8 => (false, true, 2),
163 ColorType::Rgb8 => (true, false, 3),
164 ColorType::Rgba8 => (true, true, 4),
165 };
166
167 assert_eq!(
168 (u64::from(width) * u64::from(height)).saturating_mul(bytes_per_pixel),
169 data.len() as u64
170 );
171
172 if width == 0 || width > 16384 || height == 0 || height > 16384 {
173 return Err(EncodingError::InvalidDimensions);
174 }
175
176 if !implicit_dimensions {
177 w.write_bits(0x2f, 8)?; w.write_bits(u64::from(width) - 1, 14)?;
179 w.write_bits(u64::from(height) - 1, 14)?;
180
181 w.write_bits(u64::from(is_alpha), 1)?; w.write_bits(0x0, 3)?; }
184 w.write_bits(0b101, 3)?;
186
187 if params.use_predictor_transform {
189 w.write_bits(0b111001, 6)?;
190 w.write_bits(0x0, 1)?; write_single_entry_huffman_tree(w, 2)?;
192 for _ in 0..4 {
193 write_single_entry_huffman_tree(w, 0)?;
194 }
195 }
196
197 w.write_bits(0x0, 1)?;
199
200 w.write_bits(0x0, 1)?;
202
203 w.write_bits(0x0, 1)?;
205
206 let mut pixels = match color {
208 ColorType::L8 => data.iter().flat_map(|&p| [p, p, p, 255]).collect(),
209 ColorType::La8 => data
210 .chunks_exact(2)
211 .flat_map(|p| [p[0], p[0], p[0], p[1]])
212 .collect(),
213 ColorType::Rgb8 => data
214 .chunks_exact(3)
215 .flat_map(|p| [p[0], p[1], p[2], 255])
216 .collect(),
217 ColorType::Rgba8 => data.to_vec(),
218 };
219
220 for pixel in pixels.chunks_exact_mut(4) {
222 pixel[0] = pixel[0].wrapping_sub(pixel[1]);
223 pixel[2] = pixel[2].wrapping_sub(pixel[1]);
224 }
225
226 if params.use_predictor_transform {
228 let row_bytes = width as usize * 4;
229 for y in (1..height as usize).rev() {
230 let (prev, current) =
231 pixels[(y - 1) * row_bytes..][..row_bytes * 2].split_at_mut(row_bytes);
232 for (c, p) in current.iter_mut().zip(prev) {
233 *c = c.wrapping_sub(*p);
234 }
235 }
236 for i in (4..row_bytes).rev() {
237 pixels[i] = pixels[i].wrapping_sub(pixels[i - 4]);
238 }
239 pixels[3] = pixels[3].wrapping_sub(255);
240 }
241
242 let mut frequencies0 = [0u32; 256];
244 let mut frequencies1 = [0u32; 280];
245 let mut frequencies2 = [0u32; 256];
246 let mut frequencies3 = [0u32; 256];
247 let mut it = pixels.chunks_exact(4).peekable();
248 match color {
249 ColorType::L8 => {
250 frequencies0[0] = 1;
251 frequencies2[0] = 1;
252 frequencies3[0] = 1;
253 while let Some(pixel) = it.next() {
254 frequencies1[pixel[1] as usize] += 1;
255 count_run(pixel, &mut it, &mut frequencies1);
256 }
257 }
258 ColorType::La8 => {
259 frequencies0[0] = 1;
260 frequencies2[0] = 1;
261 while let Some(pixel) = it.next() {
262 frequencies1[pixel[1] as usize] += 1;
263 frequencies3[pixel[3] as usize] += 1;
264 count_run(pixel, &mut it, &mut frequencies1);
265 }
266 }
267 ColorType::Rgb8 => {
268 frequencies3[0] = 1;
269 while let Some(pixel) = it.next() {
270 frequencies0[pixel[0] as usize] += 1;
271 frequencies1[pixel[1] as usize] += 1;
272 frequencies2[pixel[2] as usize] += 1;
273 count_run(pixel, &mut it, &mut frequencies1);
274 }
275 }
276 ColorType::Rgba8 => {
277 while let Some(pixel) = it.next() {
278 frequencies0[pixel[0] as usize] += 1;
279 frequencies1[pixel[1] as usize] += 1;
280 frequencies2[pixel[2] as usize] += 1;
281 frequencies3[pixel[3] as usize] += 1;
282 count_run(pixel, &mut it, &mut frequencies1);
283 }
284 }
285 }
286
287 let mut lengths0 = [0u8; 256];
289 let mut lengths1 = [0u8; 280];
290 let mut lengths2 = [0u8; 256];
291 let mut lengths3 = [0u8; 256];
292 let mut codes0 = [0u16; 256];
293 let mut codes1 = [0u16; 280];
294 let mut codes2 = [0u16; 256];
295 let mut codes3 = [0u16; 256];
296 write_huffman_tree(w, &frequencies1, &mut lengths1, &mut codes1)?;
297 if is_color {
298 write_huffman_tree(w, &frequencies0, &mut lengths0, &mut codes0)?;
299 write_huffman_tree(w, &frequencies2, &mut lengths2, &mut codes2)?;
300 } else {
301 write_single_entry_huffman_tree(w, 0)?;
302 write_single_entry_huffman_tree(w, 0)?;
303 }
304 if is_alpha {
305 write_huffman_tree(w, &frequencies3, &mut lengths3, &mut codes3)?;
306 } else if params.use_predictor_transform {
307 write_single_entry_huffman_tree(w, 0)?;
308 } else {
309 write_single_entry_huffman_tree(w, 255)?;
310 }
311 write_single_entry_huffman_tree(w, 1)?;
312
313 let mut it = pixels.chunks_exact(4).peekable();
315 match color {
316 ColorType::L8 => {
317 while let Some(pixel) = it.next() {
318 w.write_bits(
319 u64::from(codes1[pixel[1] as usize]),
320 lengths1[pixel[1] as usize],
321 )?;
322 write_run(w, pixel, &mut it, &codes1, &lengths1)?;
323 }
324 }
325 ColorType::La8 => {
326 while let Some(pixel) = it.next() {
327 let len1 = lengths1[pixel[1] as usize];
328 let len3 = lengths3[pixel[3] as usize];
329
330 let code = u64::from(codes1[pixel[1] as usize])
331 | (u64::from(codes3[pixel[3] as usize]) << len1);
332
333 w.write_bits(code, len1 + len3)?;
334 write_run(w, pixel, &mut it, &codes1, &lengths1)?;
335 }
336 }
337 ColorType::Rgb8 => {
338 while let Some(pixel) = it.next() {
339 let len1 = lengths1[pixel[1] as usize];
340 let len0 = lengths0[pixel[0] as usize];
341 let len2 = lengths2[pixel[2] as usize];
342
343 let code = u64::from(codes1[pixel[1] as usize])
344 | (u64::from(codes0[pixel[0] as usize]) << len1)
345 | (u64::from(codes2[pixel[2] as usize]) << (len1 + len0));
346
347 w.write_bits(code, len1 + len0 + len2)?;
348 write_run(w, pixel, &mut it, &codes1, &lengths1)?;
349 }
350 }
351 ColorType::Rgba8 => {
352 while let Some(pixel) = it.next() {
353 let len1 = lengths1[pixel[1] as usize];
354 let len0 = lengths0[pixel[0] as usize];
355 let len2 = lengths2[pixel[2] as usize];
356 let len3 = lengths3[pixel[3] as usize];
357
358 let code = u64::from(codes1[pixel[1] as usize])
359 | (u64::from(codes0[pixel[0] as usize]) << len1)
360 | (u64::from(codes2[pixel[2] as usize]) << (len1 + len0))
361 | (u64::from(codes3[pixel[3] as usize]) << (len1 + len0 + len2));
362
363 w.write_bits(code, len1 + len0 + len2 + len3)?;
364 write_run(w, pixel, &mut it, &codes1, &lengths1)?;
365 }
366 }
367 }
368
369 w.flush()?;
370 Ok(())
371}