1use core::ops::Deref;
2use imgref::ImgRef;
3
4#[derive(Copy,Clone,Debug,Eq,PartialEq)]
6#[repr(C)]
7pub struct Triple<T> {
8 pub prev: T,
9 pub curr: T,
10 pub next: T,
11}
12
13impl<T> Triple<T> {
14 #[must_use]
15 #[inline(always)]
16 pub fn new(prev: T, curr: T, next: T) -> Self {
17 Triple { prev, curr, next }
18 }
19}
20
21impl<T> AsRef<[T]> for Triple<T> {
22 #[inline(always)]
23 fn as_ref(&self) -> &[T] {
24 unsafe {
25 std::slice::from_raw_parts(self as *const Triple<T> as *const T, 3)
26 }
27 }
28}
29
30impl<T> Deref for Triple<T> {
31 type Target = [T];
32
33 #[inline(always)]
34 fn deref(&self) -> &Self::Target {
35 self.as_ref()
36 }
37}
38
39impl<T: Copy> Triple<T> {
40 #[must_use]
43 #[inline(always)]
44 pub fn advance(self, next: Option<T>) -> Self {
45 Triple {
46 prev: self.curr,
47 curr: self.next,
48 next: next.unwrap_or(self.next),
49 }
50 }
51}
52
53#[inline(always)]
59pub fn loop9_img<Pixel, Callback>(img: ImgRef<'_, Pixel>, cb: Callback)
60 where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
61{
62 loop9(img, 0, 0, img.width(), img.height(), cb);
63}
64
65pub fn loop9<Pixel, Callback>(img: ImgRef<'_, Pixel>, left: usize, top: usize, width: usize, height: usize, mut cb: Callback)
71 where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>)
72{
73 let max_width = img.width();
74 let max_height = img.height();
75 let stride = img.stride();
76 if stride == 0 || max_height == 0 || max_width == 0 {
77 return;
78 }
79 let data = img.buf();
80 let t = top.min(max_height-1) * stride;
81 let start_row = if let Some(r) = data.get(t..t+max_width) { r } else { return };
82 if start_row.is_empty() { return; }
83 let mut row = Triple {
84 prev: start_row,
85 curr: start_row,
86 next: start_row,
87 };
88 for y in top..top+height {
89 row = row.advance({
90 let t = (y+1) * stride;
91 data.get(t..t+max_width)
92 });
93 if row.prev.is_empty() || row.curr.is_empty() || row.next.is_empty() {
94 return;
95 }
96 let mut tp;
97 let mut tn = row.prev[left.min(row.prev.len()-1)];
98 let mut tc = row.prev[left.saturating_sub(1).min(row.prev.len()-1)];
99 let mut mp;
100 let mut mn = row.curr[left.min(row.curr.len()-1)];
101 let mut mc = row.curr[left.saturating_sub(1).min(row.curr.len()-1)];
102 let mut bp;
103 let mut bn = row.next[left.min(row.next.len()-1)];
104 let mut bc = row.next[left.saturating_sub(1).min(row.next.len()-1)];
105 for x in left..left+width {
106 tp = tc;
107 tc = tn;
108 tn = row.prev.get(x+1).copied().unwrap_or(tc);
109 mp = mc;
110 mc = mn;
111 mn = row.curr.get(x+1).copied().unwrap_or(mc);
112 bp = bc;
113 bc = bn;
114 bn = row.next.get(x+1).copied().unwrap_or(bc);
115 cb(x-left, y-top, Triple::new(tp, tc, tn), Triple::new(mp, mc, mn), Triple::new(bp, bc, bn));
116 }
117 }
118}
119
120
121#[test]
122fn test_oob() {
123 use imgref::Img;
124 let img = Img::new(vec![0; 5*4], 5, 4);
125 for w in 1..8 {
126 for h in 1..8 {
127 for x in 0..8 {
128 for y in 0..8 {
129 let mut n = 0;
130 loop9(img.as_ref(), x,y,w,h, |_x,_y,_top,_mid,_bot| { n += 1 });
131 assert_eq!(n, w*h, "{x},{y},{w},{h}");
132 }
133 }
134 }
135 }
136}
137
138#[test]
139fn test_loop9() {
140 use imgref::Img;
141
142 let src = vec![
143 1, 2, 3, 4, 0,
144 5, 6, 7, 8, 0,
145 9,10,11,12, 0,
146 13,14,15,16, 0,
147 ];
148 let img = Img::new_stride(src.clone(), 4, 4, 5);
149 assert_eq!(4, img.width());
150 assert_eq!(5, img.stride());
151 assert_eq!(4, img.height());
152
153 let check = |l,t,w,h,exp: &[_]|{
154 let mut res = Vec::new();
155 loop9(img.as_ref(), l,t,w,h, |_x,_y,_top,mid,_bot| res.push(mid.curr));
156 assert_eq!(exp, res);
157 };
158
159 check(0,0,4,4, &[
160 1, 2, 3, 4,
161 5, 6, 7, 8,
162 9,10,11,12,
163 13,14,15,16,
164 ]);
165
166 check(0,0,4,1, &[1, 2, 3, 4]);
167
168 check(0,3,4,1, &[13,14,15,16]);
169
170 check(0,0,3,3, &[
171 1, 2, 3,
172 5, 6, 7,
173 9,10,11,
174 ]);
175
176 check(0,0,1,1, &[1]);
177 check(1,0,1,1, &[2]);
178 check(2,0,1,1, &[3]);
179 check(3,0,1,1, &[4]);
180
181 check(1,0,3,4,&[
182 2, 3, 4,
183 6, 7, 8,
184 10,11,12,
185 14,15,16,
186 ]);
187}