/rust/registry/src/index.crates.io-1949cf8c6b5b557f/loop9-0.1.5/src/lib.rs
Line | Count | Source |
1 | | use core::ops::Deref; |
2 | | use imgref::ImgRef; |
3 | | |
4 | | /// Previous, current, and next pixel or row |
5 | | #[derive(Copy,Clone,Debug,Eq,PartialEq)] |
6 | | #[repr(C)] |
7 | | pub struct Triple<T> { |
8 | | pub prev: T, |
9 | | pub curr: T, |
10 | | pub next: T, |
11 | | } |
12 | | |
13 | | impl<T> Triple<T> { |
14 | | #[must_use] |
15 | | #[inline(always)] |
16 | 0 | pub fn new(prev: T, curr: T, next: T) -> Self { |
17 | 0 | Triple { prev, curr, next } |
18 | 0 | } |
19 | | } |
20 | | |
21 | | impl<T> AsRef<[T]> for Triple<T> { |
22 | | #[inline(always)] |
23 | 0 | fn as_ref(&self) -> &[T] { |
24 | | unsafe { |
25 | 0 | std::slice::from_raw_parts(self as *const Triple<T> as *const T, 3) |
26 | | } |
27 | 0 | } |
28 | | } |
29 | | |
30 | | impl<T> Deref for Triple<T> { |
31 | | type Target = [T]; |
32 | | |
33 | | #[inline(always)] |
34 | 0 | fn deref(&self) -> &Self::Target { |
35 | 0 | self.as_ref() |
36 | 0 | } |
37 | | } |
38 | | |
39 | | impl<T: Copy> Triple<T> { |
40 | | /// Add the next item, and shift others (prev is gone, prev = current) |
41 | | /// If the item is `None`, it'll copy the last one instead. |
42 | | #[must_use] |
43 | | #[inline(always)] |
44 | 0 | pub fn advance(self, next: Option<T>) -> Self { |
45 | 0 | Triple { |
46 | 0 | prev: self.curr, |
47 | 0 | curr: self.next, |
48 | 0 | next: next.unwrap_or(self.next), |
49 | 0 | } |
50 | 0 | } |
51 | | } |
52 | | |
53 | | /// Loop over 9 neighboring pixels in the image described by [`ImgRef`] (`Img.as_ref()`) |
54 | | /// |
55 | | /// The callback is: (`x`, `y`, `previous_row`, `current_row`, `next_row`) |
56 | | /// |
57 | | /// This function will never panic, if your callback doesn't panic. |
58 | | #[inline(always)] |
59 | 0 | pub fn loop9_img<Pixel, Callback>(img: ImgRef<'_, Pixel>, cb: Callback) |
60 | 0 | where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>) |
61 | | { |
62 | 0 | loop9(img, 0, 0, img.width(), img.height(), cb); |
63 | 0 | } Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::bleed_opaque_color::{closure#0}>Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blurred_dirty_alpha::{closure#0}>Unexecuted instantiation: loop9::loop9_img::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blur_transparent_pixels::{closure#0}> |
64 | | |
65 | | /// Loop over 9 neighboring pixels in the left/top/width/height fragment of the image described by [`ImgRef`] (`Img.as_ref()`) |
66 | | /// |
67 | | /// The callback is: (`x`, `y`, `previous_row`, `current_row`, `next_row`) |
68 | | /// |
69 | | /// This function will never panic, if your callback doesn't panic. |
70 | 0 | pub fn loop9<Pixel, Callback>(img: ImgRef<'_, Pixel>, left: usize, top: usize, width: usize, height: usize, mut cb: Callback) |
71 | 0 | where Pixel: Copy, Callback: FnMut(usize, usize, Triple<Pixel>,Triple<Pixel>,Triple<Pixel>) |
72 | | { |
73 | 0 | let max_width = img.width(); |
74 | 0 | let max_height = img.height(); |
75 | 0 | let stride = img.stride(); |
76 | 0 | if stride == 0 || max_height == 0 || max_width == 0 { |
77 | 0 | return; |
78 | 0 | } |
79 | 0 | let data = img.buf(); |
80 | 0 | let t = top.min(max_height-1) * stride; |
81 | 0 | let start_row = if let Some(r) = data.get(t..t+max_width) { r } else { return }; |
82 | 0 | if start_row.is_empty() { return; } |
83 | 0 | let mut row = Triple { |
84 | 0 | prev: start_row, |
85 | 0 | curr: start_row, |
86 | 0 | next: start_row, |
87 | 0 | }; |
88 | 0 | for y in top..top+height { |
89 | 0 | row = row.advance({ |
90 | 0 | let t = (y+1) * stride; |
91 | 0 | data.get(t..t+max_width) |
92 | 0 | }); |
93 | 0 | if row.prev.is_empty() || row.curr.is_empty() || row.next.is_empty() { |
94 | 0 | return; |
95 | 0 | } |
96 | | let mut tp; |
97 | 0 | let mut tn = row.prev[left.min(row.prev.len()-1)]; |
98 | 0 | let mut tc = row.prev[left.saturating_sub(1).min(row.prev.len()-1)]; |
99 | | let mut mp; |
100 | 0 | let mut mn = row.curr[left.min(row.curr.len()-1)]; |
101 | 0 | let mut mc = row.curr[left.saturating_sub(1).min(row.curr.len()-1)]; |
102 | | let mut bp; |
103 | 0 | let mut bn = row.next[left.min(row.next.len()-1)]; |
104 | 0 | let mut bc = row.next[left.saturating_sub(1).min(row.next.len()-1)]; |
105 | 0 | for x in left..left+width { |
106 | 0 | tp = tc; |
107 | 0 | tc = tn; |
108 | 0 | tn = row.prev.get(x+1).copied().unwrap_or(tc); |
109 | 0 | mp = mc; |
110 | 0 | mc = mn; |
111 | 0 | mn = row.curr.get(x+1).copied().unwrap_or(mc); |
112 | 0 | bp = bc; |
113 | 0 | bc = bn; |
114 | 0 | bn = row.next.get(x+1).copied().unwrap_or(bc); |
115 | 0 | cb(x-left, y-top, Triple::new(tp, tc, tn), Triple::new(mp, mc, mn), Triple::new(bp, bc, bn)); |
116 | 0 | } |
117 | | } |
118 | 0 | } Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::bleed_opaque_color::{closure#0}>Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blurred_dirty_alpha::{closure#0}>Unexecuted instantiation: loop9::loop9::<rgb::formats::rgba::Rgba<u8>, ravif::dirtyalpha::blur_transparent_pixels::{closure#0}> |
119 | | |
120 | | |
121 | | #[test] |
122 | | fn 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] |
139 | | fn 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 | | } |