1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Image filter selection algorithms.

use Options;
use std::io::{self, Write};

/// A filter selection algorithm.
pub trait Filter: for<'a> From<&'a Options> {
    /// Apply a filter and write the result to the sink.
    fn apply<W: Write>(&mut self, sink: W, prior: &[u8], line: &[u8])
        -> io::Result<()>;
    /// Reset the filter to encode an image with the given options.
    fn reset(&mut self, opts: &Options);
}

/// A filter that just encodes the actual byte value every time.
///
/// This method is recommended for images that are indexed or with low bit-depth.

pub struct None;

impl<'a> From<&'a Options> for None {
    fn from(_: &Options) -> Self { None }
}

impl Filter for None {
    fn apply<W: Write>(&mut self, mut sink: W, _: &[u8], line: &[u8])
        -> io::Result<()>
    {
        sink.write_all(&[0])?;
        sink.write_all(line)?;
        Ok(())
    }

    fn reset(&mut self, _opts: &Options) {}
}

/// A filter that picks the method with the smallest squared sum of deltas.
///
/// This option is recommended for most images.

pub struct Standard {
    bpp: usize,
    len: usize,
    buf: Vec<u8>,
}

impl<'a> From<&'a Options> for Standard {
    fn from(opts: &Options) -> Self {
        let len = opts.stride();
        Self {
            bpp: (opts.format.channels() * opts.depth as usize + 7) / 8,
            len: len,
            buf: vec![0; len * 5]
        }
    }
}

impl Filter for Standard {
    fn apply<W: Write>(&mut self, mut sink: W, prior: &[u8], line: &[u8])
        -> io::Result<()>
    {
        let funcs: [fn(u8, u8, u8) -> u8; 5] = [
            |_, _, _| 0,
            |a, _, _| a,
            |_, b, _| b,
            |a, b, _| ((a as u16 + b as u16) / 2) as u8,
            |a, b, c| {
                let (i, j, k) = (a as i16, b as i16, c as i16);
                let (x, y) = (j - k, i - k);
                let (pa, pb, pc) = (x.abs(), y.abs(), (x + y).abs());

                if pa <= pb && pa <= pc { a }
                else if pb <= pc { b }
                else { c }
            },
        ];

        let mut scores: [usize; 5] = [0; 5];

        for i in 0..line.len() {
            let (b, d) = (prior[i], line[i]);
            let (a, c) =
                if self.bpp <= i {
                    (line[i - self.bpp], prior[i - self.bpp])
                } else {
                    (0, 0)
                };

            for j in 0..5 {
                let v = funcs[j](a, b, c);
                let delta = d as isize - v as isize;
                self.buf[j * self.len + i] = delta as u8;
                scores[j] += (delta * delta) as usize;
            }
        }

        let mut best = 0;
        for j in 1..5 {
            if scores[j] < scores[best] {
                best = j;
            }
        }

        sink.write_all(&[best as u8])?;
        sink.write_all(&self.buf[best * self.len .. (best + 1) * self.len])?;
        Ok(())
    }

    fn reset(&mut self, opts: &Options) {
        let len = opts.stride();
        self.bpp = (opts.format.channels() * opts.depth as usize + 7) / 8;
        self.len = len;
        self.buf.clear();
        self.buf.resize(len * 5, 0);
    }
}