mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 14:22:39 +00:00
Images: pick a reduced JPEG's scale by its long side
The JPEG decoder takes the smallest scale that meets either requested side. A short side rounds up to the same size at several scales, so a 100 x 2 JPEG asked for at a half decoded at an eighth (13 x 1). The long side alone now picks the scale, and a decode whose size differs from the requested reduction is refused, which falls back to the full decode.
This commit is contained in:
1 parent
113319e3e1
commit
55963c4918
2 files changed
+21
-1
No files matched your search
@@ -100,7 +100,14 @@ pub(crate) fn decode_reduced(bytes: &[u8], shrink: u8) -> Option<(image::RgbaIma
|
||||
}
|
||||
}
|
||||
let reduced = |n: u16| u16::try_from(u32::from(n).div_ceil(1 << shrink)).ok();
|
||||
let (w, h) = d.scale(reduced(info.width)?, reduced(info.height)?).ok()?;
|
||||
let expected = (reduced(info.width)?, reduced(info.height)?);
|
||||
// The decoder takes the smallest scale that meets either requested side, and a short side
|
||||
// rounds up to the same size at several scales, so only the long side is requested.
|
||||
let request = if info.width >= info.height { (expected.0, u16::MAX) } else { (u16::MAX, expected.1) };
|
||||
let (w, h) = d.scale(request.0, request.1).ok()?;
|
||||
if (w, h) != expected {
|
||||
return None;
|
||||
}
|
||||
let px = d.decode().ok()?;
|
||||
let pixels = usize::from(w).checked_mul(usize::from(h))?;
|
||||
let rgba: Vec<u8> = if colour {
|
||||
|
||||
@@ -596,6 +596,19 @@ fn reduced_jpegs_decode_at_a_half_quarter_or_eighth_rounded_up() {
|
||||
assert!(decode_rgba_reduced(&jpeg, 4).is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_thin_reduced_jpeg_keeps_its_long_side_at_the_requested_reduction() {
|
||||
// The short side rounds up to 1 at every reduction, so it cannot pick the scale.
|
||||
for (w, h) in [(100, 2), (2, 100)] {
|
||||
let jpeg = gradient_jpeg(w, h, false);
|
||||
for (shrink, long) in [(1, 50), (2, 25), (3, 13)] {
|
||||
let img = decode_rgba_reduced(&jpeg, shrink).unwrap();
|
||||
let size = if w > h { (long, 1) } else { (1, long) };
|
||||
assert_eq!(img.dimensions(), size, "{w} × {h}, shrink {shrink}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reduced_decoding_is_for_jpegs_and_survives_damaged_ones() {
|
||||
let gray = decode_rgba_reduced(&gradient_jpeg(64, 64, true), 2).unwrap();
|
||||
|
||||
Reference in new issue
Block a user