chess_corners_core/
imageview.rs1#[derive(Copy, Clone, Debug)]
3pub struct ImageView<'a> {
4 pub(crate) data: &'a [u8],
5 pub(crate) width: usize,
6 pub(crate) height: usize,
7 pub(crate) origin: [i32; 2],
12}
13
14impl<'a> ImageView<'a> {
15 pub fn from_u8_slice(width: usize, height: usize, data: &'a [u8]) -> Option<Self> {
19 if width.checked_mul(height)? != data.len() {
20 return None;
21 }
22 Some(Self {
23 data,
24 width,
25 height,
26 origin: [0, 0],
27 })
28 }
29
30 pub fn with_origin(
34 width: usize,
35 height: usize,
36 data: &'a [u8],
37 origin: [i32; 2],
38 ) -> Option<Self> {
39 Self::from_u8_slice(width, height, data).map(|mut view| {
40 view.origin = origin;
41 view
42 })
43 }
44
45 #[inline]
49 pub fn origin(&self) -> [i32; 2] {
50 self.origin
51 }
52
53 #[inline]
55 pub fn data(&self) -> &'a [u8] {
56 self.data
57 }
58
59 #[inline]
61 pub fn width(&self) -> usize {
62 self.width
63 }
64
65 #[inline]
67 pub fn height(&self) -> usize {
68 self.height
69 }
70
71 #[inline]
75 pub fn supports_patch(&self, cx: i32, cy: i32, radius: i32) -> bool {
76 if self.width == 0 || self.height == 0 {
77 return false;
78 }
79
80 let gx = cx + self.origin[0];
81 let gy = cy + self.origin[1];
82 let min_x = 0;
83 let min_y = 0;
84 let max_x = self.width as i32 - 1;
85 let max_y = self.height as i32 - 1;
86 gx - radius >= min_x && gy - radius >= min_y && gx + radius <= max_x && gy + radius <= max_y
87 }
88
89 #[inline]
93 pub fn sample(&self, gx: i32, gy: i32) -> f32 {
94 if self.width == 0 || self.height == 0 {
95 return 0.0;
96 }
97 let gx = gx + self.origin[0];
98 let gy = gy + self.origin[1];
99 let lx = gx.clamp(0, self.width.saturating_sub(1) as i32) as usize;
100 let ly = gy.clamp(0, self.height.saturating_sub(1) as i32) as usize;
101 self.data[ly * self.width + lx] as f32
102 }
103
104 #[inline]
108 pub fn sample_bilinear(&self, gx: f32, gy: f32) -> f32 {
109 if self.width == 0 || self.height == 0 {
110 return 0.0;
111 }
112
113 let fx = gx + self.origin[0] as f32;
114 let fy = gy + self.origin[1] as f32;
115
116 let max_x = self.width.saturating_sub(1) as i32;
117 let max_y = self.height.saturating_sub(1) as i32;
118
119 let x0 = (fx.floor() as i32).clamp(0, max_x);
120 let y0 = (fy.floor() as i32).clamp(0, max_y);
121 let x1 = (x0 + 1).clamp(0, max_x);
122 let y1 = (y0 + 1).clamp(0, max_y);
123
124 let tx = (fx - x0 as f32).clamp(0.0, 1.0);
127 let ty = (fy - y0 as f32).clamp(0.0, 1.0);
128
129 let w = self.width;
130 let i00 = self.data[y0 as usize * w + x0 as usize] as f32;
131 let i10 = self.data[y0 as usize * w + x1 as usize] as f32;
132 let i01 = self.data[y1 as usize * w + x0 as usize] as f32;
133 let i11 = self.data[y1 as usize * w + x1 as usize] as f32;
134
135 let a = i00 + (i10 - i00) * tx;
136 let b = i01 + (i11 - i01) * tx;
137 a + (b - a) * ty
138 }
139}