Skip to content

Commit 9ad1ce3

Browse files
committed
perf: Optimize black border detector
1 parent 5364d1e commit 9ad1ce3

File tree

1 file changed

+78
-57
lines changed

1 file changed

+78
-57
lines changed

src/instance/black_border_detector.rs

+78-57
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,8 @@ impl BlackBorder {
1818
}
1919
}
2020

21-
fn is_black(&self, color: Option<models::Color>) -> bool {
22-
color
23-
.map(|color| {
24-
color.red < self.threshold
25-
&& color.green < self.threshold
26-
&& color.blue < self.threshold
27-
})
28-
.unwrap_or(true)
21+
fn is_black(&self, color: models::Color) -> bool {
22+
color.red < self.threshold && color.green < self.threshold && color.blue < self.threshold
2923
}
3024

3125
fn update(&mut self, xy: (Option<u32>, Option<u32>)) {
@@ -53,19 +47,22 @@ impl BlackBorder {
5347
let width = width - 1;
5448
let height = height - 1;
5549

56-
let first_non_black_x = (0..width33).find(|x| {
57-
!self.is_black(image.color_at(width - *x, y_center))
58-
|| !self.is_black(image.color_at(*x, height33))
59-
|| !self.is_black(image.color_at(*x, height66))
60-
});
61-
62-
let first_non_black_y = (0..height33).find(|y| {
63-
!self.is_black(image.color_at(x_center, height - *y))
64-
|| !self.is_black(image.color_at(width33, *y))
65-
|| !self.is_black(image.color_at(width66, *y))
66-
});
67-
68-
self.update((first_non_black_x, first_non_black_y));
50+
// Safety: width33 < width && height33 < height so x and y are in range
51+
unsafe {
52+
let first_non_black_x = (0..width33).find(|x| {
53+
!self.is_black(image.color_at_unchecked(width - *x, y_center))
54+
|| !self.is_black(image.color_at_unchecked(*x, height33))
55+
|| !self.is_black(image.color_at_unchecked(*x, height66))
56+
});
57+
58+
let first_non_black_y = (0..height33).find(|y| {
59+
!self.is_black(image.color_at_unchecked(x_center, height - *y))
60+
|| !self.is_black(image.color_at_unchecked(width33, *y))
61+
|| !self.is_black(image.color_at_unchecked(width66, *y))
62+
});
63+
64+
self.update((first_non_black_x, first_non_black_y));
65+
}
6966
}
7067

7168
fn process_classic(&mut self, image: &impl Image) {
@@ -80,23 +77,41 @@ impl BlackBorder {
8077
let x = i.min(width);
8178
let y = i.min(height);
8279

83-
if !self.is_black(image.color_at(x, y)) {
84-
first_non_black_x = x as _;
85-
first_non_black_y = y as _;
80+
// Safety: x and y are in range, since width < image.width()
81+
unsafe {
82+
if !self.is_black(image.color_at_unchecked(x, y)) {
83+
first_non_black_x = x as _;
84+
first_non_black_y = y as _;
85+
}
8686
}
8787
}
8888

8989
while first_non_black_x > 0 {
90-
if self.is_black(image.color_at((first_non_black_x - 1) as _, first_non_black_y as _)) {
91-
break;
90+
// Safety: first_non_black_x > 0 && first_non_black_x <= width
91+
unsafe {
92+
if first_non_black_y < 0
93+
|| self.is_black(
94+
image.color_at_unchecked(
95+
(first_non_black_x - 1) as _,
96+
first_non_black_y as _,
97+
),
98+
)
99+
{
100+
break;
101+
}
92102
}
93103

94104
first_non_black_x -= 1;
95105
}
96106

97107
while first_non_black_y > 0 {
98-
if self.is_black(image.color_at(first_non_black_x as _, (first_non_black_y - 1) as _)) {
99-
break;
108+
// Safety: first_non_black_x >= 0 && first_non_black_y > 0
109+
unsafe {
110+
if self.is_black(
111+
image.color_at_unchecked(first_non_black_x as _, (first_non_black_y - 1) as _),
112+
) {
113+
break;
114+
}
100115
}
101116

102117
first_non_black_y -= 1;
@@ -127,22 +142,25 @@ impl BlackBorder {
127142
let width = width - 1;
128143
let height = height - 1;
129144

130-
let first_non_black_x = (0..width33).find(|x| {
131-
!self.is_black(image.color_at(width - *x, y_center))
132-
|| !self.is_black(image.color_at(*x, height33))
133-
|| !self.is_black(image.color_at(*x, height66))
134-
});
145+
// Safety: all operations are in range of the image dimensions
146+
unsafe {
147+
let first_non_black_x = (0..width33).find(|x| {
148+
!self.is_black(image.color_at_unchecked(width - *x, y_center))
149+
|| !self.is_black(image.color_at_unchecked(*x, height33))
150+
|| !self.is_black(image.color_at_unchecked(*x, height66))
151+
});
135152

136-
let x = first_non_black_x.unwrap_or(width33);
153+
let x = first_non_black_x.unwrap_or(width33);
137154

138-
let first_non_black_y = (0..height33).find(|y| {
139-
!self.is_black(image.color_at(x, *y))
140-
|| !self.is_black(image.color_at(x, height - *y))
141-
|| !self.is_black(image.color_at(width - x, *y))
142-
|| !self.is_black(image.color_at(width - x, height - *y))
143-
});
155+
let first_non_black_y = (0..height33).find(|y| {
156+
!self.is_black(image.color_at_unchecked(x, *y))
157+
|| !self.is_black(image.color_at_unchecked(x, height - *y))
158+
|| !self.is_black(image.color_at_unchecked(width - x, *y))
159+
|| !self.is_black(image.color_at_unchecked(width - x, height - *y))
160+
});
144161

145-
self.update((first_non_black_x, first_non_black_y));
162+
self.update((first_non_black_x, first_non_black_y));
163+
}
146164
}
147165

148166
fn process_letterbox(&mut self, image: &impl Image) {
@@ -155,22 +173,25 @@ impl BlackBorder {
155173

156174
let height = height - 1;
157175

158-
let first_non_black_y = (0..height33).find(|y| {
159-
!self.is_black(image.color_at(x_center, *y))
160-
|| !self.is_black(image.color_at(width25, *y))
161-
|| !self.is_black(image.color_at(width75, *y))
162-
|| !self.is_black(image.color_at(width25, height - *y))
163-
|| !self.is_black(image.color_at(width75, height - *y))
164-
});
165-
166-
self.update((
167-
first_non_black_y,
168-
if first_non_black_y.is_none() {
169-
None
170-
} else {
171-
Some(0)
172-
},
173-
));
176+
// Safety: all operations are in range of the image dimensions
177+
unsafe {
178+
let first_non_black_y = (0..height33).find(|y| {
179+
!self.is_black(image.color_at_unchecked(x_center, *y))
180+
|| !self.is_black(image.color_at_unchecked(width25, *y))
181+
|| !self.is_black(image.color_at_unchecked(width75, *y))
182+
|| !self.is_black(image.color_at_unchecked(width25, height - *y))
183+
|| !self.is_black(image.color_at_unchecked(width75, height - *y))
184+
});
185+
186+
self.update((
187+
first_non_black_y,
188+
if first_non_black_y.is_none() {
189+
None
190+
} else {
191+
Some(0)
192+
},
193+
));
194+
}
174195
}
175196

176197
pub fn process(&mut self, image: &impl Image, mode: models::BlackBorderDetectorMode) {

0 commit comments

Comments
 (0)