Avoid trying to shrink indexed-color PNG files (BL-16424)#8032
Avoid trying to shrink indexed-color PNG files (BL-16424)#8032StephenMcConnel wants to merge 1 commit into
Conversation
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.
|
| 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
| using (var fs = RobustIO.GetFileStream(filePath, FileMode.Open, FileAccess.Read)) | ||
| { | ||
| if (fs.Length < 26) | ||
| return false; | ||
| fs.Read(header, 0, 26); | ||
| } |
There was a problem hiding this comment.
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.
| 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; | |
| } | |
| } |
| 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 |
There was a problem hiding this comment.
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!
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