Skip to content

Commit 75fa317

Browse files
authored
Merge pull request #143 from awxkee/v703
Better limits check
2 parents b9dfbab + dc4677d commit 75fa317

5 files changed

Lines changed: 130 additions & 34 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ workspace = { members = ["app", "wasm", "app/accelerate", "speedtest"], exclude
22

33
[package]
44
name = "pic-scale"
5-
version = "0.7.5"
5+
version = "0.7.6"
66
edition = "2024"
77
description = "High performance image scaling"
88
readme = "README.md"

app/src/main.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -112,41 +112,37 @@ fn main() {
112112
// resize_rgba(0, 1, 256, 79, 256, ResamplingFunction::Bilinear, false);
113113
#[allow(overflowing_literals)]
114114
// test_fast_image();
115-
let img = ImageReader::open("./assets/sample_fhd.jpg")
115+
let img = ImageReader::open("./assets/asset_5.png")
116116
.unwrap()
117117
.decode()
118118
.unwrap();
119119
// img.save("top_right.tga").unwrap();
120120
let dimensions = img.dimensions();
121121
let transient = img.to_rgb8();
122-
let mut bytes = transient
123-
.to_vec()
124-
.iter()
125-
.map(|&x| x as f32 / 255.)
126-
.collect::<Vec<_>>();
122+
let mut bytes = transient.to_vec().iter().map(|&x| x).collect::<Vec<_>>();
127123

128124
// img.resize_exact(dimensions.0 as u32 / 4, dimensions.1 as u32 / 4, image::imageops::FilterType::Lanczos3).save("resized.png").unwrap();
129125

130-
let mut scaler = Scaler::new(ResamplingFunction::Bilinear)
131-
.set_threading_policy(ThreadingPolicy::Adaptive)
126+
let mut scaler = Scaler::new(ResamplingFunction::Lanczos3)
127+
.set_threading_policy(ThreadingPolicy::Single)
132128
.set_supersampling(false);
133129
// scaler.set_workload_strategy(WorkloadStrategy::PreferSpeed);
134130

135131
let mut store =
136-
RgbF32ImageStore::from_slice(&bytes, dimensions.0 as usize, dimensions.1 as usize).unwrap();
132+
Rgb8ImageStore::from_slice(&bytes, dimensions.0 as usize, dimensions.1 as usize).unwrap();
137133
store.bit_depth = 10;
138134

139-
let mut t_size = ImageSize::new(dimensions.0 as usize / 2, dimensions.1 as usize / 2);
135+
let mut t_size = ImageSize::new(dimensions.0 as usize / 6, dimensions.1 as usize / 6);
140136
// t_size.height += 1;
141137
let resizing_plan = scaler
142-
.plan_rgb_resampling_f32(
138+
.plan_rgb_resampling(
143139
ImageSize::new(dimensions.0 as usize, dimensions.1 as usize),
144140
t_size,
145141
)
146142
.unwrap();
147-
let mut dst_store = RgbF32ImageStoreMut::alloc_with_depth(
148-
dimensions.0 as usize / 2,
149-
dimensions.1 as usize / 2,
143+
let mut dst_store = Rgb8ImageStoreMut::alloc_with_depth(
144+
dimensions.0 as usize / 6,
145+
dimensions.1 as usize / 6,
150146
10,
151147
);
152148
resizing_plan.resample(&store, &mut dst_store).unwrap();
@@ -201,9 +197,9 @@ fn main() {
201197
let dst = dst_store
202198
.as_bytes()
203199
.iter()
204-
// .map(|&x| x)
200+
.map(|&x| x)
205201
// .map(|&x| (((x) >> 2) as u8).min(255))
206-
.map(|&x| (x as f32 * 255.).round() as u8)
202+
// .map(|&x| (x as f32 * 255.).round() as u8)
207203
.collect::<Vec<_>>();
208204

209205
if dst_store.channels == 4 {

src/colors/common_splitter.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2828
*/
2929
use crate::plan::Resampling;
30-
use crate::support::check_image_size_overflow;
30+
use crate::support::check_image_size_overflow_with_stride;
3131
use crate::validation::try_vec;
3232
use crate::{ImageSize, ImageStore, ImageStoreMut, PicScaleError, ResamplingPlan};
3333
use std::fmt::Debug;
@@ -81,11 +81,23 @@ impl<T: Default + Clone + Copy + Debug, R: Default + Clone + Copy + Debug, const
8181
return Err(PicScaleError::ZeroImageDimensions);
8282
}
8383

84-
if check_image_size_overflow(store.width, store.height, store.channels) {
84+
if check_image_size_overflow_with_stride(
85+
store.width,
86+
store.height,
87+
store.stride(),
88+
store.channels,
89+
size_of::<T>() as isize,
90+
) {
8591
return Err(PicScaleError::SourceImageIsTooLarge);
8692
}
8793

88-
if check_image_size_overflow(new_size.width, new_size.height, store.channels) {
94+
if check_image_size_overflow_with_stride(
95+
new_size.width,
96+
new_size.height,
97+
into.stride(),
98+
store.channels,
99+
size_of::<T>() as isize,
100+
) {
89101
return Err(PicScaleError::DestinationImageIsTooLarge);
90102
}
91103

src/image_store.rs

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use crate::alpha_handle_f16::{premultiply_alpha_rgba_f16, unpremultiply_alpha_rg
3232
use crate::alpha_handle_f32::{premultiply_alpha_rgba_f32, unpremultiply_alpha_rgba_f32};
3333
use crate::alpha_handle_u8::{premultiply_alpha_rgba, unpremultiply_alpha_rgba};
3434
use crate::alpha_handle_u16::{premultiply_alpha_rgba_u16, unpremultiply_alpha_rgba_u16};
35-
use crate::support::check_image_size_overflow;
35+
use crate::support::{check_image_size_overflow, check_image_size_overflow_with_stride};
3636
use crate::validation::{PicScaleBufferMismatch, PicScaleError, try_vec};
3737
use crate::{ImageSize, WorkloadStrategy};
3838
#[cfg(feature = "nightly_f16")]
@@ -226,6 +226,25 @@ impl<T, const N: usize> ImageStoreMut<'_, T, N> {
226226
return Err(PicScaleError::ZeroImageDimensions);
227227
}
228228

229+
if check_image_size_overflow(
230+
self.width,
231+
self.height,
232+
self.channels,
233+
size_of::<T>() as isize,
234+
) {
235+
return Err(PicScaleError::SourceImageIsTooLarge);
236+
}
237+
238+
if check_image_size_overflow_with_stride(
239+
self.width,
240+
self.height,
241+
self.stride(),
242+
self.channels,
243+
size_of::<T>() as isize,
244+
) {
245+
return Err(PicScaleError::SourceImageIsTooLarge);
246+
}
247+
229248
let valid_size = self.stride() * (self.height - 1) + self.width * N;
230249

231250
if self.stride() < self.width * N {
@@ -241,9 +260,6 @@ impl<T, const N: usize> ImageStoreMut<'_, T, N> {
241260
slice_len: self.buffer.borrow().len(),
242261
}));
243262
}
244-
if check_image_size_overflow(self.width, self.height, self.channels) {
245-
return Err(PicScaleError::SourceImageIsTooLarge);
246-
}
247263
Ok(())
248264
}
249265

@@ -262,6 +278,25 @@ where
262278
return Err(PicScaleError::ZeroImageDimensions);
263279
}
264280

281+
if check_image_size_overflow(
282+
self.width,
283+
self.height,
284+
self.channels,
285+
size_of::<T>() as isize,
286+
) {
287+
return Err(PicScaleError::DestinationImageIsTooLarge);
288+
}
289+
290+
if check_image_size_overflow_with_stride(
291+
self.width,
292+
self.height,
293+
self.stride(),
294+
self.channels,
295+
size_of::<T>() as isize,
296+
) {
297+
return Err(PicScaleError::DestinationImageIsTooLarge);
298+
}
299+
265300
let valid_size = self.stride() * (self.height - 1) + self.width * N;
266301

267302
if self.stride() < self.width * N {
@@ -278,10 +313,6 @@ where
278313
}));
279314
}
280315

281-
if check_image_size_overflow(self.width, self.height, self.channels) {
282-
return Err(PicScaleError::DestinationImageIsTooLarge);
283-
}
284-
285316
Ok(())
286317
}
287318

src/support.rs

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,68 @@
3030
pub(crate) const PRECISION: i32 = 15;
3131
pub(crate) const ROUNDING_CONST: i32 = 1 << (PRECISION - 1);
3232

33-
pub(crate) fn check_image_size_overflow(width: usize, height: usize, chan: usize) -> bool {
34-
let (stride, is_overflowed) = (width as isize).overflowing_mul(chan as isize);
35-
if is_overflowed {
33+
pub(crate) fn check_image_size_overflow(
34+
width: usize,
35+
height: usize,
36+
chan: usize,
37+
t_size: isize,
38+
) -> bool {
39+
let Ok(w) = isize::try_from(width) else {
3640
return true;
37-
}
38-
let (_, is_overflowed) = (height as isize).overflowing_mul(stride);
39-
is_overflowed
41+
};
42+
let Ok(h) = isize::try_from(height) else {
43+
return true;
44+
};
45+
let Ok(n) = isize::try_from(chan) else {
46+
return true;
47+
};
48+
let Some(stride) = w.checked_mul(n) else {
49+
return true;
50+
};
51+
52+
// stride * (height - 1) + width * N
53+
let Some(h_minus_1) = h.checked_sub(1) else {
54+
return true;
55+
};
56+
let Some(lhs) = stride.checked_mul(h_minus_1) else {
57+
return true;
58+
};
59+
lhs.checked_add(stride)
60+
.and_then(|x| x.checked_mul(t_size))
61+
.is_none()
62+
}
63+
64+
pub(crate) fn check_image_size_overflow_with_stride(
65+
width: usize,
66+
height: usize,
67+
stride: usize,
68+
chan: usize,
69+
t_size: isize,
70+
) -> bool {
71+
let Ok(w) = isize::try_from(width) else {
72+
return true;
73+
};
74+
let Ok(h) = isize::try_from(height) else {
75+
return true;
76+
};
77+
let Ok(n) = isize::try_from(chan) else {
78+
return true;
79+
};
80+
let Ok(stride) = isize::try_from(stride) else {
81+
return true;
82+
};
83+
84+
// stride * (height - 1) + width * N
85+
let Some(h_minus_1) = h.checked_sub(1) else {
86+
return true;
87+
};
88+
let Some(lhs) = stride.checked_mul(h_minus_1) else {
89+
return true;
90+
};
91+
let Some(rhs) = w.checked_mul(n) else {
92+
return true;
93+
};
94+
lhs.checked_add(rhs)
95+
.and_then(|x| x.checked_mul(t_size))
96+
.is_none()
4097
}

0 commit comments

Comments
 (0)