/rust/registry/src/index.crates.io-1949cf8c6b5b557f/fax-0.2.7/src/lib.rs
Line | Count | Source |
1 | | #![deny(unsafe_code)] |
2 | | use std::convert::Infallible; |
3 | | use std::fmt; |
4 | | use std::io::{self, Read}; |
5 | | use std::iter::Map; |
6 | | use std::ops::Not; |
7 | | |
8 | | #[cfg(feature = "debug")] |
9 | | macro_rules! debug { |
10 | | ($($arg:expr),*) => ( |
11 | | println!($($arg),*) |
12 | | ) |
13 | | } |
14 | | #[cfg(not(feature = "debug"))] |
15 | | macro_rules! debug { |
16 | | ($($arg:expr),*) => { |
17 | | () |
18 | | }; |
19 | | } |
20 | | |
21 | | pub mod maps; |
22 | | |
23 | | /// Decoder module |
24 | | pub mod decoder; |
25 | | |
26 | | /// Encoder module |
27 | | pub mod encoder; |
28 | | |
29 | | /// TIFF helper functions |
30 | | pub mod tiff; |
31 | | |
32 | | /// Trait used to read data bitwise. |
33 | | /// |
34 | | /// For lazy people `ByteReader` is provided which implements this trait. |
35 | | pub trait BitReader { |
36 | | type Error; |
37 | | |
38 | | /// look at the next (up to 16) bits of data |
39 | | /// |
40 | | /// Data is returned in the lower bits of the `u16`. |
41 | | fn peek(&self, bits: u8) -> Option<u16>; |
42 | | |
43 | | /// Consume the given amount of bits from the input. |
44 | | fn consume(&mut self, bits: u8) -> Result<(), Self::Error>; |
45 | | |
46 | | /// Assert that the next bits matches the given pattern. |
47 | | /// |
48 | | /// If it does not match, the found pattern is returned if enough bits are aviable. |
49 | | /// Otherwise None is returned. |
50 | 0 | fn expect(&mut self, bits: Bits) -> Result<(), Option<Bits>> { |
51 | 0 | match self.peek(bits.len) { |
52 | 0 | None => Err(None), |
53 | 0 | Some(val) if val == bits.data => Ok(()), |
54 | 0 | Some(val) => Err(Some(Bits { |
55 | 0 | data: val, |
56 | 0 | len: bits.len, |
57 | 0 | })), |
58 | | } |
59 | 0 | } |
60 | | |
61 | | fn bits_to_byte_boundary(&self) -> u8; |
62 | | } |
63 | | |
64 | | /// Trait to write data bitwise |
65 | | /// |
66 | | /// The `VecWriter` struct is provided for convinience. |
67 | | pub trait BitWriter { |
68 | | type Error; |
69 | | fn write(&mut self, bits: Bits) -> Result<(), Self::Error>; |
70 | | } |
71 | | pub struct VecWriter { |
72 | | data: Vec<u8>, |
73 | | partial: u32, |
74 | | len: u8, |
75 | | } |
76 | | impl BitWriter for VecWriter { |
77 | | type Error = Infallible; |
78 | 0 | fn write(&mut self, bits: Bits) -> Result<(), Self::Error> { |
79 | 0 | self.partial |= (bits.data as u32) << (32 - self.len - bits.len); |
80 | 0 | self.len += bits.len; |
81 | 0 | while self.len >= 8 { |
82 | 0 | self.data.push((self.partial >> 24) as u8); |
83 | 0 | self.partial <<= 8; |
84 | 0 | self.len -= 8; |
85 | 0 | } |
86 | 0 | Ok(()) |
87 | 0 | } |
88 | | } |
89 | | impl VecWriter { |
90 | 0 | pub fn new() -> Self { |
91 | 0 | VecWriter { |
92 | 0 | data: Vec::new(), |
93 | 0 | partial: 0, |
94 | 0 | len: 0, |
95 | 0 | } |
96 | 0 | } |
97 | | // with capacity of `n` bits. |
98 | 0 | pub fn with_capacity(n: usize) -> Self { |
99 | 0 | VecWriter { |
100 | 0 | data: Vec::with_capacity((n + 7) / 8), |
101 | 0 | partial: 0, |
102 | 0 | len: 0, |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | /// Pad the output with `0` bits until it is at a byte boundary. |
107 | 0 | pub fn pad(&mut self) { |
108 | 0 | if self.len > 0 { |
109 | 0 | self.data.push((self.partial >> 24) as u8); |
110 | 0 | self.partial = 0; |
111 | 0 | self.len = 0; |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | /// pad and return the accumulated bytes |
116 | 0 | pub fn finish(mut self) -> Vec<u8> { |
117 | 0 | self.pad(); |
118 | 0 | self.data |
119 | 0 | } |
120 | | } |
121 | | |
122 | | pub struct ByteReader<R> { |
123 | | read: R, |
124 | | partial: u32, |
125 | | valid: u8, |
126 | | } |
127 | | impl<E, R: Iterator<Item = Result<u8, E>>> ByteReader<R> { |
128 | | /// Construct a new `ByteReader` from an iterator of `u8` |
129 | 0 | pub fn new(read: R) -> Result<Self, E> { |
130 | 0 | let mut bits = ByteReader { |
131 | 0 | read, |
132 | 0 | partial: 0, |
133 | 0 | valid: 0, |
134 | 0 | }; |
135 | 0 | bits.fill()?; |
136 | 0 | Ok(bits) |
137 | 0 | } Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>>>::new Unexecuted instantiation: <fax::ByteReader<core::iter::adapters::map::Map<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<u8>>, core::result::Result<u8, core::convert::Infallible>::Ok>>>::new |
138 | 0 | fn fill(&mut self) -> Result<(), E> { |
139 | 0 | while self.valid < 16 { |
140 | 0 | match self.read.next() { |
141 | 0 | Some(Ok(byte)) => { |
142 | 0 | self.partial = self.partial << 8 | byte as u32; |
143 | 0 | self.valid += 8; |
144 | 0 | } |
145 | 0 | Some(Err(e)) => return Err(e), |
146 | 0 | None => break, |
147 | | } |
148 | | } |
149 | 0 | Ok(()) |
150 | 0 | } Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>>>::fill Unexecuted instantiation: <fax::ByteReader<core::iter::adapters::map::Map<core::iter::adapters::cloned::Cloned<core::slice::iter::Iter<u8>>, core::result::Result<u8, core::convert::Infallible>::Ok>>>::fill |
151 | | /// Print the remaining data |
152 | | /// |
153 | | /// Note: For debug purposes only, not part of the API. |
154 | 0 | pub fn print_remaining(&mut self) { |
155 | 0 | println!( |
156 | 0 | "partial: {:0w$b}, valid: {}", |
157 | 0 | self.partial & ((1 << self.valid) - 1), |
158 | | self.valid, |
159 | 0 | w = self.valid as usize |
160 | | ); |
161 | 0 | while let Some(Ok(b)) = self.read.next() { |
162 | 0 | print!("{:08b} ", b); |
163 | 0 | } |
164 | 0 | println!(); |
165 | 0 | } |
166 | 0 | pub fn print_peek(&self) { |
167 | 0 | println!( |
168 | 0 | "partial: {:0w$b}, valid: {}", |
169 | 0 | self.partial & ((1 << self.valid) - 1), |
170 | | self.valid, |
171 | 0 | w = self.valid as usize |
172 | | ); |
173 | 0 | } |
174 | | } |
175 | | |
176 | 0 | pub fn slice_reader(slice: &[u8]) -> ByteReader<impl Iterator<Item = Result<u8, Infallible>> + '_> { |
177 | 0 | ByteReader::new(slice.iter().cloned().map(Ok)).unwrap() |
178 | 0 | } |
179 | 0 | pub fn slice_bits(slice: &[u8]) -> impl Iterator<Item = bool> + '_ { |
180 | 0 | slice |
181 | 0 | .iter() |
182 | 0 | .flat_map(|&b| [7, 6, 5, 4, 3, 2, 1, 0].map(|i| (b >> i) & 1 != 0)) |
183 | 0 | } |
184 | | |
185 | | impl<E, R: Iterator<Item = Result<u8, E>>> BitReader for ByteReader<R> { |
186 | | type Error = E; |
187 | | |
188 | 0 | fn peek(&self, bits: u8) -> Option<u16> { |
189 | 0 | if bits > 16 { |
190 | 0 | return None; |
191 | 0 | } |
192 | 0 | if self.valid >= bits { |
193 | 0 | let shift = self.valid - bits; |
194 | 0 | let mask = if bits >= 16 { |
195 | 0 | u16::MAX |
196 | | } else { |
197 | 0 | (1u16 << bits) - 1 |
198 | | }; |
199 | 0 | let out = (self.partial >> shift) as u16 & mask; |
200 | 0 | Some(out) |
201 | | } else { |
202 | 0 | None |
203 | | } |
204 | 0 | } Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>> as fax::BitReader>::peek Unexecuted instantiation: <fax::ByteReader<_> as fax::BitReader>::peek |
205 | 0 | fn consume(&mut self, bits: u8) -> Result<(), E> { |
206 | 0 | self.valid = self.valid.saturating_sub(bits); |
207 | 0 | self.fill() |
208 | 0 | } Unexecuted instantiation: <fax::ByteReader<std::io::Bytes<std::io::buffered::bufreader::BufReader<std::io::Take<&mut std::io::cursor::Cursor<&[u8]>>>>> as fax::BitReader>::consume Unexecuted instantiation: <fax::ByteReader<_> as fax::BitReader>::consume |
209 | 0 | fn bits_to_byte_boundary(&self) -> u8 { |
210 | 0 | self.valid & 7 |
211 | 0 | } |
212 | | } |
213 | | |
214 | | #[test] |
215 | | fn test_bits() { |
216 | | let mut bits = slice_reader(&[0b0000_1101, 0b1010_0000]); |
217 | | assert_eq!(maps::black::decode(&mut bits), Some(42)); |
218 | | } |
219 | | |
220 | | #[test] |
221 | | fn test_peek_over_16_returns_none() { |
222 | | let bits = slice_reader(&[0xFF, 0xFF, 0xFF]); |
223 | | // peek(17) should return None, not panic |
224 | | assert_eq!(bits.peek(17), None); |
225 | | assert_eq!(bits.peek(255), None); |
226 | | // peek(16) should still work |
227 | | assert!(bits.peek(16).is_some()); |
228 | | } |
229 | | |
230 | | #[test] |
231 | | fn test_consume_more_than_valid_saturates() { |
232 | | let mut bits = slice_reader(&[0xAB]); |
233 | | // consume more bits than available — should not panic |
234 | | let _ = bits.consume(200); |
235 | | // after saturating to 0, peek should return None for any nonzero request |
236 | | assert_eq!(bits.peek(1), None); |
237 | | } |
238 | | |
239 | | #[cfg(test)] |
240 | | mod tests { |
241 | | use super::*; |
242 | | |
243 | | /// Build a Group 3 bitstream from a sequence of bits. |
244 | | fn bits_to_bytes(bits: &[u8]) -> Vec<u8> { |
245 | | let mut bytes = Vec::new(); |
246 | | let mut byte = 0u8; |
247 | | let mut count = 0; |
248 | | for &b in bits { |
249 | | byte = (byte << 1) | (b & 1); |
250 | | count += 1; |
251 | | if count == 8 { |
252 | | bytes.push(byte); |
253 | | byte = 0; |
254 | | count = 0; |
255 | | } |
256 | | } |
257 | | if count > 0 { |
258 | | byte <<= 8 - count; |
259 | | bytes.push(byte); |
260 | | } |
261 | | bytes |
262 | | } |
263 | | |
264 | | #[test] |
265 | | fn test_group3_all_white_line() { |
266 | | // Build a minimal Group 3 stream: |
267 | | // - Initial EOL (000000000001) |
268 | | // - Line 1: white(8) = 10011, EOL |
269 | | // - RTC: 5 more EOLs |
270 | | let mut stream_bits = Vec::new(); |
271 | | |
272 | | // Initial EOL |
273 | | let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; |
274 | | stream_bits.extend_from_slice(eol); |
275 | | |
276 | | // Line 1: white run of 8 pixels = 10011 |
277 | | stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]); |
278 | | // EOL after line 1 |
279 | | stream_bits.extend_from_slice(eol); |
280 | | |
281 | | // RTC: 5 more EOLs |
282 | | for _ in 0..5 { |
283 | | stream_bits.extend_from_slice(eol); |
284 | | } |
285 | | |
286 | | let data = bits_to_bytes(&stream_bits); |
287 | | let mut lines = Vec::new(); |
288 | | decoder::decode_g3(data.into_iter(), |transitions| { |
289 | | lines.push(transitions.to_vec()); |
290 | | }); |
291 | | |
292 | | assert_eq!(lines.len(), 1, "expected 1 line, got {}", lines.len()); |
293 | | // All-white line: single transition at position 8 (white→black at the end) |
294 | | // Actually, the run-length is 8 white pixels. The transitions list shows |
295 | | // color change positions. For an all-white line, there are no transitions |
296 | | // (white runs the full width). But the decoder adds a0 += p after each code, |
297 | | // and pushes a0. For white(8), a0 = 8, pushed once. That's one transition. |
298 | | assert_eq!(lines[0], vec![8]); |
299 | | } |
300 | | |
301 | | #[test] |
302 | | fn test_group3_mixed_line() { |
303 | | // Width 16: 4 white, 4 black, 8 white |
304 | | // white(4) = 1011, black(4) = 011, white(8) = 10011 |
305 | | let mut stream_bits = Vec::new(); |
306 | | |
307 | | let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; |
308 | | |
309 | | // Initial EOL |
310 | | stream_bits.extend_from_slice(eol); |
311 | | |
312 | | // Line: white(4)=1011, black(4)=011, white(8)=10011 |
313 | | stream_bits.extend_from_slice(&[1, 0, 1, 1]); // white 4 |
314 | | stream_bits.extend_from_slice(&[0, 1, 1]); // black 4 |
315 | | stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]); // white 8 |
316 | | stream_bits.extend_from_slice(eol); |
317 | | |
318 | | // RTC |
319 | | for _ in 0..5 { |
320 | | stream_bits.extend_from_slice(eol); |
321 | | } |
322 | | |
323 | | let data = bits_to_bytes(&stream_bits); |
324 | | let mut lines = Vec::new(); |
325 | | decoder::decode_g3(data.into_iter(), |transitions| { |
326 | | lines.push(transitions.to_vec()); |
327 | | }); |
328 | | |
329 | | assert_eq!(lines.len(), 1); |
330 | | // Transitions: white(4) -> position 4, black(4) -> position 8, white(8) -> position 16 |
331 | | assert_eq!(lines[0], vec![4, 8, 16]); |
332 | | } |
333 | | |
334 | | #[test] |
335 | | fn test_group3_with_fill_bits() { |
336 | | // T.4 allows 0-7 fill bits (zeros) before each EOL for byte |
337 | | // alignment. Test all fill counts to verify is_eol_ahead detects |
338 | | // fill+EOL without the prefix tree consuming fill bits. |
339 | | let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; |
340 | | |
341 | | for fill_count in 0u8..=7 { |
342 | | let mut stream_bits = Vec::new(); |
343 | | |
344 | | // Initial EOL with fill |
345 | | for _ in 0..fill_count { |
346 | | stream_bits.push(0); |
347 | | } |
348 | | stream_bits.extend_from_slice(eol); |
349 | | |
350 | | // Line: white(4) = 1011 |
351 | | stream_bits.extend_from_slice(&[1, 0, 1, 1]); |
352 | | |
353 | | // EOL with fill |
354 | | for _ in 0..fill_count { |
355 | | stream_bits.push(0); |
356 | | } |
357 | | stream_bits.extend_from_slice(eol); |
358 | | |
359 | | // RTC: 5 more EOLs with fill |
360 | | for _ in 0..5 { |
361 | | for _ in 0..fill_count { |
362 | | stream_bits.push(0); |
363 | | } |
364 | | stream_bits.extend_from_slice(eol); |
365 | | } |
366 | | |
367 | | let data = bits_to_bytes(&stream_bits); |
368 | | let mut lines = Vec::new(); |
369 | | decoder::decode_g3(data.into_iter(), |transitions| { |
370 | | lines.push(transitions.to_vec()); |
371 | | }); |
372 | | |
373 | | assert_eq!( |
374 | | lines.len(), |
375 | | 1, |
376 | | "fill={fill_count}: expected 1 line, got {}", |
377 | | lines.len() |
378 | | ); |
379 | | assert_eq!( |
380 | | lines[0], |
381 | | vec![4], |
382 | | "fill={fill_count}: expected [4], got {:?}", |
383 | | lines[0] |
384 | | ); |
385 | | } |
386 | | } |
387 | | |
388 | | #[test] |
389 | | fn test_group3_multiple_lines() { |
390 | | let mut stream_bits = Vec::new(); |
391 | | let eol: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; |
392 | | |
393 | | // Initial EOL |
394 | | stream_bits.extend_from_slice(eol); |
395 | | |
396 | | // Line 1: white(4)=1011 |
397 | | stream_bits.extend_from_slice(&[1, 0, 1, 1]); |
398 | | stream_bits.extend_from_slice(eol); |
399 | | |
400 | | // Line 2: white(8)=10011 |
401 | | stream_bits.extend_from_slice(&[1, 0, 0, 1, 1]); |
402 | | stream_bits.extend_from_slice(eol); |
403 | | |
404 | | // Line 3: white(2)=0111, black(3)=10 |
405 | | stream_bits.extend_from_slice(&[0, 1, 1, 1]); // white 2 |
406 | | stream_bits.extend_from_slice(&[1, 0]); // black 3 |
407 | | stream_bits.extend_from_slice(eol); |
408 | | |
409 | | // RTC |
410 | | for _ in 0..5 { |
411 | | stream_bits.extend_from_slice(eol); |
412 | | } |
413 | | |
414 | | let data = bits_to_bytes(&stream_bits); |
415 | | let mut lines = Vec::new(); |
416 | | decoder::decode_g3(data.into_iter(), |transitions| { |
417 | | lines.push(transitions.to_vec()); |
418 | | }); |
419 | | |
420 | | assert_eq!(lines.len(), 3); |
421 | | assert_eq!(lines[0], vec![4]); |
422 | | assert_eq!(lines[1], vec![8]); |
423 | | assert_eq!(lines[2], vec![2, 5]); // white 2, then black 3 = positions 2, 5 |
424 | | } |
425 | | } |
426 | | |
427 | | /// Enum used to signal black/white. |
428 | | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
429 | | pub enum Color { |
430 | | Black, |
431 | | White, |
432 | | } |
433 | | impl Not for Color { |
434 | | type Output = Self; |
435 | 0 | fn not(self) -> Self { |
436 | 0 | match self { |
437 | 0 | Color::Black => Color::White, |
438 | 0 | Color::White => Color::Black, |
439 | | } |
440 | 0 | } |
441 | | } |
442 | | |
443 | | struct Transitions<'a> { |
444 | | edges: &'a [u16], |
445 | | pos: usize, |
446 | | } |
447 | | impl<'a> Transitions<'a> { |
448 | 0 | fn new(edges: &'a [u16]) -> Self { |
449 | 0 | Transitions { edges, pos: 0 } |
450 | 0 | } |
451 | 0 | fn seek_back(&mut self, start: u16) { |
452 | 0 | self.pos = self.pos.min(self.edges.len().saturating_sub(1)); |
453 | 0 | while self.pos > 0 { |
454 | 0 | if start < self.edges[self.pos - 1] { |
455 | 0 | self.pos -= 1; |
456 | 0 | } else { |
457 | 0 | break; |
458 | | } |
459 | | } |
460 | 0 | } |
461 | 0 | fn next_color(&mut self, start: u16, color: Color, start_of_row: bool) -> Option<u16> { |
462 | 0 | if start_of_row { |
463 | 0 | if color == Color::Black { |
464 | 0 | self.pos = 1; |
465 | 0 | return self.edges.get(0).cloned(); |
466 | | } else { |
467 | 0 | self.pos = 2; |
468 | 0 | return self.edges.get(1).cloned(); |
469 | | } |
470 | 0 | } |
471 | 0 | while self.pos < self.edges.len() { |
472 | 0 | if self.edges[self.pos] <= start { |
473 | 0 | self.pos += 1; |
474 | 0 | continue; |
475 | 0 | } |
476 | | |
477 | 0 | if (self.pos % 2 == 0) != (color == Color::Black) { |
478 | 0 | self.pos += 1; |
479 | 0 | } |
480 | | |
481 | 0 | break; |
482 | | } |
483 | 0 | if self.pos < self.edges.len() { |
484 | 0 | let val = self.edges[self.pos]; |
485 | 0 | self.pos += 1; |
486 | 0 | Some(val) |
487 | | } else { |
488 | 0 | None |
489 | | } |
490 | 0 | } |
491 | 0 | fn next(&mut self) -> Option<u16> { |
492 | 0 | if self.pos < self.edges.len() { |
493 | 0 | let val = self.edges[self.pos]; |
494 | 0 | self.pos += 1; |
495 | 0 | Some(val) |
496 | | } else { |
497 | 0 | None |
498 | | } |
499 | 0 | } |
500 | 0 | fn peek(&self) -> Option<u16> { |
501 | 0 | self.edges.get(self.pos).cloned() |
502 | 0 | } |
503 | 0 | fn skip(&mut self, n: usize) { |
504 | 0 | self.pos += n; |
505 | 0 | } |
506 | | } |
507 | | |
508 | | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] |
509 | | pub struct Bits { |
510 | | pub data: u16, |
511 | | pub len: u8, |
512 | | } |
513 | | |
514 | | impl fmt::Debug for Bits { |
515 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
516 | 0 | write!(f, "d={:0b} w={}", self.data, self.len) |
517 | 0 | } |
518 | | } |
519 | | impl fmt::Display for Bits { |
520 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
521 | 0 | write!( |
522 | 0 | f, |
523 | 0 | "{:0w$b}", |
524 | 0 | self.data & ((1 << self.len) - 1), |
525 | 0 | w = self.len as usize |
526 | | ) |
527 | 0 | } |
528 | | } |