fix(images): resize over-cap attachments even when the re-encode saves no bytes

An attachment over the side or area caps whose re-encode did not shrink
the byte count was returned unchanged at its original dimensions, so the
provider still received an over-cap image. The byte-saving short-circuit
now applies only within the caps; a resize that would fall under the
vision minimums keeps the original on the existing fallback path.

Ported from upstream 1.0.13 (grok-build session/image_normalize.rs).

Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
This commit is contained in:
雷电芽衣 committed 2026-09-13 09:53:11 -04:00
1 parent a7b8438881
commit d8609267a1
1 file changed
+62 -1
@@ -467,7 +467,24 @@ fn compute_normalized_blocking(
});
}
};
if buf.len() >= original_bytes {
// A resize that falls under the vision floors cannot be sent; keep the original with the fallback note.
if new_w < MIN_VISION_SIDE_PX
|| new_h < MIN_VISION_SIDE_PX
|| u64::from(new_w) * u64::from(new_h) < MIN_VISION_TOTAL_PX
{
tracing::warn!(
index,
width = new_w,
height = new_h,
"image resize fell under the minimum dimensions; keeping original attachment"
);
return Ok(NormalizedEntry::ReEncodingOversized {
bytes: Bytes::from(raw_bytes),
mime: Cow::Borrowed(orig_mime),
});
}
// An image over the dimension caps is resized even when that saves no bytes.
if !exceeded_dimensions && buf.len() >= original_bytes {
return Ok(NormalizedEntry::Unchanged {
bytes: Bytes::from(raw_bytes),
mime: Cow::Borrowed(orig_mime),
@@ -551,6 +568,50 @@ mod tests {
image::ImageFormat::Png
);
}
/// A flat image at the best PNG compression is tinier than any re-encode the fast encoder produces.
fn make_best_compressed_png_content(width: u32, height: u32) -> ImageContent {
use image::codecs::png::{CompressionType, FilterType, PngEncoder};
use image::{ImageBuffer, ImageEncoder, Rgba};
let img: ImageBuffer<Rgba<u8>, Vec<u8>> =
ImageBuffer::from_pixel(width, height, Rgba([128, 64, 32, 255]));
let mut buf = Vec::new();
PngEncoder::new_with_quality(&mut buf, CompressionType::Best, FilterType::Adaptive)
.write_image(img.as_raw(), width, height, image::ExtendedColorType::Rgba8)
.unwrap();
ImageContent::new(
base64::engine::general_purpose::STANDARD.encode(&buf),
"image/png",
)
}
/// Over the dimension caps, a re-encode that saves no bytes is still a resize.
#[tokio::test]
async fn over_dimension_image_is_resized_even_when_re_encode_saves_no_bytes() {
let img = make_best_compressed_png_content(3000, 2000);
let cache = fresh_cache();
match normalize_one_in(img, 1, false, &cache).await {
Outcome::Compressed { info, .. } => {
assert!(
info.compressed_bytes >= info.original_bytes,
"test premise: the re-encode must not shrink ({} vs {})",
info.compressed_bytes,
info.original_bytes
);
assert!(info.compressed_width <= MAX_ENCODE_SIDE_PX);
assert!(info.compressed_height <= MAX_ENCODE_SIDE_PX);
}
other => panic!("expected the oversized image to be downscaled, got {other:?}"),
}
}
/// A 3000x8 strip resizes to 2000x5, under the 8 px floor: it is kept with the fallback note.
#[tokio::test]
async fn resize_under_the_minimum_side_keeps_the_original() {
let img = make_best_compressed_png_content(3000, 8);
let cache = fresh_cache();
match normalize_one_in(img, 1, false, &cache).await {
Outcome::ReEncodingOversized(content) => assert_eq!(content.mime_type, "image/png"),
other => panic!("expected the strip to be kept with a fallback note, got {other:?}"),
}
}
fn make_gif_content(width: u32, height: u32) -> ImageContent {
use image::{ImageBuffer, Rgba};
let img: ImageBuffer<Rgba<u8>, Vec<u8>> =