What's wrong
When an input's brightest opaque pixel is below 255, the offset normalization lifts every opaque pixel by 255 - maxValue, black included. True black ends up with non-zero coverage, so the background stays partly opaque and the crop can't trim it.
Where
IconHelper/IconHelper.cs, NormalizedIntensity (around lines 263-285):
return (byte)(255 - (maxValue - pixel.R)); // pixel.R == 0 -> 255 - maxValue, not 0
The coverage and bounding-box pass (around lines 325-336) then treats those pixels as visible.
This contradicts CLAUDE.md:91 and the README: "A region that flattens to black comes out fully transparent and falls outside the crop". The existing test DropsUnlitArtworkFromTheCoverage only covers inputs where a white patch pins maxValue at 255, where the offset is 0.
Failure scenario
Reproduced with a throwaway test against the current code: an 80×80 opaque-black canvas with a 40×40 square of (80,80,80) in the middle. After the contrast filter the grey is about 105, so maxValue = 105.
|
Expected |
Actual |
| Output size |
40×40 |
80×80 |
| Corner alpha |
0 |
150 |
In practice, any dark icon on a black background, including every JPEG input (no alpha channel), comes out as a translucent full square.
Suggested fix
This needs a deliberate choice, because the "offset, not scale" rationale is documented in the README:
- Option A: keep the offset but pin true black:
pixel.R == 0 ? 0 : 255 - (maxValue - pixel.R). Near-black anti-aliasing still carries the offset.
- Option B: scale instead (
pixel.R * 255 / maxValue). Black stays 0, but edge gradients are stretched.
Whichever is chosen, update the README, CLAUDE.md, gold masters and the README line about dim artwork being "translucent throughout". Add a test with dim artwork on opaque black that checks the output is cropped to the artwork and the corners are transparent.
What's wrong
When an input's brightest opaque pixel is below 255, the offset normalization lifts every opaque pixel by
255 - maxValue, black included. True black ends up with non-zero coverage, so the background stays partly opaque and the crop can't trim it.Where
IconHelper/IconHelper.cs,NormalizedIntensity(around lines 263-285):The coverage and bounding-box pass (around lines 325-336) then treats those pixels as visible.
This contradicts CLAUDE.md:91 and the README: "A region that flattens to black comes out fully transparent and falls outside the crop". The existing test
DropsUnlitArtworkFromTheCoverageonly covers inputs where a white patch pinsmaxValueat 255, where the offset is 0.Failure scenario
Reproduced with a throwaway test against the current code: an 80×80 opaque-black canvas with a 40×40 square of (80,80,80) in the middle. After the contrast filter the grey is about 105, so
maxValue = 105.In practice, any dark icon on a black background, including every JPEG input (no alpha channel), comes out as a translucent full square.
Suggested fix
This needs a deliberate choice, because the "offset, not scale" rationale is documented in the README:
pixel.R == 0 ? 0 : 255 - (maxValue - pixel.R). Near-black anti-aliasing still carries the offset.pixel.R * 255 / maxValue). Black stays 0, but edge gradients are stretched.Whichever is chosen, update the README, CLAUDE.md, gold masters and the README line about dim artwork being "translucent throughout". Add a test with dim artwork on opaque black that checks the output is cropped to the artwork and the corners are transparent.