Skip to main content

fax/
encoder.rs

1use crate::{
2    maps::{black, mode, white, Mode, EDFB_HALF},
3    BitWriter, Color, Transitions,
4};
5
6fn absdiff(a: u16, b: u16) -> u16 {
7    if a > b {
8        a - b
9    } else {
10        b - a
11    }
12}
13
14pub struct Encoder<W> {
15    writer: W,
16    reference: Vec<u16>,
17    current: Vec<u16>,
18}
19fn encode_color<W: BitWriter>(writer: &mut W, color: Color, mut n: u16) -> Result<(), W::Error> {
20    let table = match color {
21        Color::White => &white::ENTRIES,
22        Color::Black => &black::ENTRIES,
23    };
24    let mut write = |n: u16| {
25        let idx = if n >= 64 { 63 + n / 64 } else { n } as usize;
26        let (v, bits) = table[idx];
27        assert_eq!(v, n);
28        //debug!("{}", n);
29        writer.write(bits)
30    };
31
32    while n >= 2560 {
33        write(2560)?;
34        n -= 2560;
35    }
36    if n >= 64 {
37        let d = n & !63;
38        write(d)?;
39        n -= d;
40    }
41
42    write(n)
43}
44impl<W: BitWriter> Encoder<W> {
45    pub fn new(writer: W) -> Self {
46        Encoder {
47            writer,
48            reference: vec![],
49            current: vec![],
50        }
51    }
52    pub fn encode_line(
53        &mut self,
54        pels: impl Iterator<Item = Color>,
55        width: u16,
56    ) -> Result<(), W::Error> {
57        let mut color = Color::White;
58        let mut transitions = Transitions::new(&self.reference);
59        let mut a0 = 0;
60        let mut start_of_line = true;
61        let mut pels = pels
62            .enumerate()
63            .scan(Color::White, |state, (i, c)| {
64                Some(if c != *state {
65                    debug!("  {i} {c:?}");
66                    *state = c;
67                    Some(i as u16)
68                } else {
69                    None
70                })
71            })
72            .filter_map(|x| x);
73        let writer = &mut self.writer;
74        self.current.clear();
75
76        while a0 < width {
77            let a1;
78            if let Some(a1_) = pels.next() {
79                self.current.push(a1_);
80                a1 = a1_;
81            } else {
82                a1 = width;
83            }
84            loop {
85                transitions.seek_back(a0);
86                let b1 = transitions
87                    .next_color(a0, !color, start_of_line)
88                    .unwrap_or(width);
89                let b2 = transitions.peek();
90                start_of_line = false;
91                debug!("  a0={a0}, a1={a1}, b1={:?}, b2={:?}", b1, b2);
92                match (b1, b2) {
93                    (_b1, Some(b2)) if b2 < a1 => {
94                        debug!("  Pass");
95                        let bits = mode::encode(Mode::Pass).unwrap();
96                        writer.write(bits)?;
97                        transitions.skip(1);
98                        a0 = b2;
99                        continue;
100                    }
101                    (b1, _) if absdiff(a1, b1) <= 3 => {
102                        let delta = a1 as i16 - b1 as i16;
103                        debug!("  Vertical({})", delta);
104                        let bits = mode::encode(Mode::Vertical(delta as i8)).unwrap();
105                        writer.write(bits)?;
106                        a0 = a1;
107                        color = !color;
108                    }
109                    _ => {
110                        let a2 = match pels.next() {
111                            Some(a2) => {
112                                self.current.push(a2);
113                                a2
114                            }
115                            None => width,
116                        };
117                        let a0a1 = a1.saturating_sub(a0);
118                        let a1a2 = a2.saturating_sub(a1);
119                        debug!("  Horizontal({}, {}) color={color:?}", a0a1, a1a2);
120                        let bits = mode::encode(Mode::Horizontal).unwrap();
121                        writer.write(bits)?;
122                        let c = if a0 + a1 == 0 { Color::White } else { color };
123                        encode_color(writer, c, a0a1)?;
124                        encode_color(writer, !c, a1a2)?;
125                        a0 = a2;
126                    }
127                }
128                break;
129            }
130        }
131
132        std::mem::swap(&mut self.reference, &mut self.current);
133        debug!("next line");
134        Ok(())
135    }
136    pub fn finish(mut self) -> Result<W, W::Error> {
137        self.writer.write(EDFB_HALF)?;
138        self.writer.write(EDFB_HALF)?;
139        Ok(self.writer)
140    }
141}