Count progressive JPEG buffers in warm budget

This commit is contained in:
Dylan M. Taylor committed 2026-11-12 17:55:11 -05:00
1 parent 067fc97128
commit 1c3285d8a3
3 files changed
+17 -10

No files matched your search

+11 -5
View File
@@ -67,7 +67,7 @@ pub(crate) const MAX_SHRINK: u8 = 3;
/// Output size of a JPEG reduction without decoding pixels. `None` when the reduced decoder
/// cannot handle the JPEG, including its full-size resource limits.
pub(crate) fn reduced_size(bytes: &[u8], shrink: u8) -> Option<(u32, u32)> {
pub(crate) fn reduced_size(bytes: &[u8], shrink: u8) -> Option<(u32, u32, usize)> {
use jpeg_decoder::{CodingProcess, PixelFormat};
if !bytes.starts_with(&[0xFF, 0xD8]) || shrink == 0 || shrink > MAX_SHRINK {
return None;
@@ -84,15 +84,21 @@ pub(crate) fn reduced_size(bytes: &[u8], shrink: u8) -> Option<(u32, u32)> {
if crate::over_rgba_budget(u32::from(info.width), u32::from(info.height)) {
return None;
}
if info.coding_process == CodingProcess::DctProgressive {
let progressive_bytes = if info.coding_process == CodingProcess::DctProgressive {
let side = |n: u16| u64::from(n).next_multiple_of(32);
let components: u64 = if colour { 3 } else { 1 };
if side(info.width) * side(info.height) * components * 2 > MAX_BYTES as u64 {
let bytes = side(info.width) * side(info.height) * components * 2;
if bytes > MAX_BYTES as u64 {
return None;
}
}
usize::try_from(bytes).ok()?
} else {
0
};
let reduced = |n: u16| u32::from(n).div_ceil(1 << shrink);
Some((reduced(info.width), reduced(info.height)))
let (width, height) = (reduced(info.width), reduced(info.height));
let output_bytes = width as usize * height as usize * 8;
Some((width, height, progressive_bytes.saturating_add(output_bytes)))
}
/// A YCbCr, RGB or grayscale JPEG decoded at 1/2^`shrink` of its size, each side rounded up, for
+4 -3
View File
@@ -510,9 +510,10 @@ pub fn decode_rgba_reduced(bytes: &[u8], shrink: u8) -> Option<image::RgbaImage>
to_display_rgba(px, Some(&icc), &DisplayColour::active())
}
/// Dimensions of a JPEG decoded at `1/2^shrink`, without decoding its pixels. `None` when the
/// reduced decoder cannot handle the image.
pub fn reduced_jpeg_size(bytes: &[u8], shrink: u8) -> Option<(u32, u32)> {
/// Dimensions and estimated peak bytes for a JPEG decoded at `1/2^shrink`, without decoding its
/// pixels. Progressive JPEG coefficient buffers are included. `None` when the reduced decoder
/// cannot handle the image.
pub fn reduced_jpeg_size(bytes: &[u8], shrink: u8) -> Option<(u32, u32, usize)> {
jpeg::reduced_size(bytes, shrink)
}
+2 -2
View File
@@ -200,11 +200,11 @@ fn reduced_estimates(wants: &[Want]) -> Option<(usize, usize)> {
return None;
}
let shrink = level.min(usize::from(designcraft_images::MAX_REDUCED_SHRINK));
let (decoded_w, decoded_h) = designcraft_images::reduced_jpeg_size(&w.bytes, shrink as u8)?;
let (_, _, decode_peak) = designcraft_images::reduced_jpeg_size(&w.bytes, shrink as u8)?;
for cached in levels.iter_mut().take(level + 1).skip(shrink) {
*cached = true;
}
peak = peak.max(decoded_w as usize * decoded_h as usize * 8);
peak = peak.max(decode_peak);
if dims.as_ref().is_none_or(|d: &Vec<(u32, u32)>| d.len() < sizes.len()) {
dims = Some(sizes);
}