1use std;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4#[repr(u8)]
5pub enum FilterType {
6 NoFilter = 0,
7 Sub = 1,
8 Up = 2,
9 Avg = 3,
10 Paeth = 4
11}
12
13 impl FilterType {
14 pub fn from_u8(n: u8) -> Option<FilterType> {
16 match n {
17 0 => Some(FilterType::NoFilter),
18 1 => Some(FilterType::Sub),
19 2 => Some(FilterType::Up),
20 3 => Some(FilterType::Avg),
21 4 => Some(FilterType::Paeth),
22 _ => None
23 }
24 }
25}
26
27fn filter_paeth(a: u8, b: u8, c: u8) -> u8 {
28 let ia = a as i16;
29 let ib = b as i16;
30 let ic = c as i16;
31
32 let p = ia + ib - ic;
33
34 let pa = (p - ia).abs();
35 let pb = (p - ib).abs();
36 let pc = (p - ic).abs();
37
38 if pa <= pb && pa <= pc {
39 a
40 } else if pb <= pc {
41 b
42 } else {
43 c
44 }
45}
46
47pub fn unfilter(filter: FilterType, bpp: usize, previous: &[u8], current: &mut [u8]) -> std::result::Result<(), &'static str> {
48 use self::FilterType::*;
49 assert!(bpp > 0);
50 let len = current.len();
51
52 match filter {
53 NoFilter => Ok(()),
54 Sub => {
55 for i in bpp..len {
56 current[i] = current[i].wrapping_add(
57 current[i - bpp]
58 );
59 }
60 Ok(())
61 }
62 Up => {
63 if previous.len() < len {
64 Err("Filtering failed: not enough data in previous row")
65 } else {
66 for i in 0..len {
67 current[i] = current[i].wrapping_add(
68 previous[i]
69 );
70 }
71 Ok(())
72 }
73 }
74 Avg => {
75 if previous.len() < len {
76 Err("Filtering failed: not enough data in previous row")
77 } else if bpp > len {
78 Err("Filtering failed: bytes per pixel is greater than length of row")
79 } else {
80 for i in 0..bpp {
81 current[i] = current[i].wrapping_add(
82 previous[i] / 2
83 );
84 }
85
86 for i in bpp..len {
87 current[i] = current[i].wrapping_add(
88 ((current[i - bpp] as i16 + previous[i] as i16) / 2) as u8
89 );
90 }
91 Ok(())
92 }
93 }
94 Paeth => {
95 if previous.len() < len {
96 Err("Filtering failed: not enough data in previous row")
97 } else if bpp > len {
98 Err("Filtering failed: bytes per pixel is greater than length of row")
99 } else {
100 for i in 0..bpp {
101 current[i] = current[i].wrapping_add(
102 filter_paeth(0, previous[i], 0)
103 );
104 }
105
106 for i in bpp..len {
107 current[i] = current[i].wrapping_add(
108 filter_paeth(current[i - bpp], previous[i], previous[i - bpp])
109 );
110 }
111 Ok(())
112 }
113 }
114 }
115}
116
117pub fn filter(method: FilterType, bpp: usize, previous: &[u8], current: &mut [u8]) {
118 use self::FilterType::*;
119 assert!(bpp > 0);
120 let len = current.len();
121
122 match method {
123 NoFilter => (),
124 Sub => {
125 for i in (bpp..len).rev() {
126 current[i] = current[i].wrapping_sub(current[i - bpp]);
127 }
128 }
129 Up => {
130 for i in 0..len {
131 current[i] = current[i].wrapping_sub(previous[i]);
132 }
133 }
134 Avg => {
135 for i in (bpp..len).rev() {
136 current[i] = current[i].wrapping_sub(current[i - bpp].wrapping_add(previous[i]) / 2);
137 }
138
139 for i in 0..bpp {
140 current[i] = current[i].wrapping_sub(previous[i] / 2);
141 }
142 }
143 Paeth => {
144 for i in (bpp..len).rev() {
145 current[i] = current[i].wrapping_sub(filter_paeth(current[i - bpp], previous[i], previous[i - bpp]));
146 }
147
148 for i in 0..bpp {
149 current[i] = current[i].wrapping_sub(filter_paeth(0, previous[i], 0));
150 }
151 }
152 }
153}