Skip to content

Avoid trying to shrink indexed-color PNG files (BL-16424)#8032

Open
StephenMcConnel wants to merge 1 commit into
masterfrom
BL-16424-LargePngSlowness
Open

Avoid trying to shrink indexed-color PNG files (BL-16424)#8032
StephenMcConnel wants to merge 1 commit into
masterfrom
BL-16424-LargePngSlowness

Conversation

@StephenMcConnel

@StephenMcConnel StephenMcConnel commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

These are the primary source of files that don't shrink when the image dimensions are reduced. The code now tries to do this twice when pasting an image, causing a lot of slowdown when shrinking fails on nontrivial images.

Devin review


This change is Reviewable

These are the primary source of files that don't shrink when the image
dimensions are reduced.  The code now tries to do this twice when pasting
an image, causing a lot of slowdown when shrinking fails on nontrivial
images.
@greptile-apps

greptile-apps Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds an early-exit heuristic in TryResizeImageWithGraphicsMagick to skip GraphicsMagick processing for indexed-color PNG files, which lose their compact format on conversion to RGBA and therefore frequently end up larger after a resize operation.

  • IsIndexedColorPngFile reads the first 26 bytes of the PNG file to validate the signature and inspect the IHDR color-type byte (offset 25 = 3 for indexed color); it is called as a fallback when the in-memory PixelFormat.Indexed flag is absent (e.g., clipboard paste).
  • The guard bails out early (returning null) when the estimated uncompressed size of the converted RGBA output would not be smaller than the source, while still allowing GraphicsMagick through when the resolution reduction is large enough to justify the format change.

Important Files Changed

Filename Overview
src/BloomExe/ImageProcessing/ImageUtils.cs Adds IsIndexedColorPngFile helper and indexed-PNG early-exit guard in TryResizeImageWithGraphicsMagick; logic is sound but has a minor robustness gap in the header read and an imprecise bit-depth assumption in the area heuristic comment.

Reviews (1): Last reviewed commit: "Avoid trying to shrink indexed-color PNG..." | Re-trigger Greptile

Comment on lines +906 to +911
using (var fs = RobustIO.GetFileStream(filePath, FileMode.Open, FileAccess.Read))
{
if (fs.Length < 26)
return false;
fs.Read(header, 0, 26);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Stream.Read may return fewer bytes than requested even when the stream has enough data, so header[25] could end up zero (causing a false negative) if the read is split across multiple system calls. Capturing the return value and looping — or using ReadExactly — ensures the full 26-byte header is always populated before the color-type check.

Suggested change
using (var fs = RobustIO.GetFileStream(filePath, FileMode.Open, FileAccess.Read))
{
if (fs.Length < 26)
return false;
fs.Read(header, 0, 26);
}
using (var fs = RobustIO.GetFileStream(filePath, FileMode.Open, FileAccess.Read))
{
if (fs.Length < 26)
return false;
int offset = 0;
while (offset < 26)
{
int read = fs.Read(header, offset, 26 - offset);
if (read == 0)
return false; // unexpected EOF
offset += read;
}
}

Comment on lines +1871 to +1872
var currentArea = imageInfo.Image.Size.Height * imageInfo.Image.Size.Width; // 1 byte per pixel for indexed PNGs
var newArea = size.Height * size.Width * 4; // 4 bytes per pixel for non-indexed PNGs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Area heuristic assumes 8 bpp for all indexed PNGs

Indexed PNGs can legally use 1, 2, or 4 bits per pixel (PNG spec §11.2.2). The comment "1 byte per pixel for indexed PNGs" is only accurate for 8 bpp; for lower bit-depth images currentArea overestimates the source footprint by up to 8×, so the guard is more conservative than intended — it will refuse to convert cases where conversion might actually shrink the file. The downstream file-size check still prevents any wrongly-approved conversion from landing, so behavior is always correct, but some beneficial resizes may be skipped for small low-bpp palettised images.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants