commit 1831a88e7dc159ad18a560eca08969765b152a13
parent 29025adfb526b462e403b312df8b6e270f20eb2e
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date: Sun, 20 Sep 2026 16:24:55 -0300
icns: stop warning about ARGB padding
actool on macOS 26 writes an ARGB element whose stream ends on its last run.
The evidence for the dropped value was only ever the three plane types, and
a check that accuses Apple's own output loses its authority.
Diffstat:
2 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/validate.go b/validate.go
@@ -122,27 +122,26 @@ func (e Entry) problems() []Problem {
return problems
}
-// paddingProblems reports a run-length encoded icon whose stream ends on its
+// paddingProblems reports a colour plane element whose stream ends on its
// last run. Apple's reader on Apple silicon drops the last value of such a
// stream, so a byte has to follow it for the icon to survive.
+//
+// Only the three plane types are read this way. The ARGB elements are left
+// alone: actool on macOS 26 writes them with their stream ending exactly on
+// the last run, so whatever drops a value does not reach them.
func (e Entry) paddingProblems() []Problem {
+ if e.ImageFormat != ImageFormatRGB {
+ return nil
+ }
var (
pixels = int(e.Size) * int(e.Size)
- data []byte
- want int
+ data = e.data
+ want = pixels * 3
)
- switch e.ImageFormat {
- case ImageFormatRGB:
- data, want = e.data, pixels*3
- // it32 is the one colour element that prefixes its planes with four
- // zero bytes.
- if e.ID == "it32" && len(data) >= 4 && binary.BigEndian.Uint32(data[:4]) == 0 {
- data = data[4:]
- }
- case ImageFormatARGB:
- data, want = e.data[len(argbHeader):], pixels*4
- default:
- return nil
+ // it32 is the one colour element that prefixes its planes with four zero
+ // bytes.
+ if e.ID == "it32" && len(data) >= 4 && binary.BigEndian.Uint32(data[:4]) == 0 {
+ data = data[4:]
}
// Data stored at its exact length is not compressed, so there is no run
// for a reader to drop.
diff --git a/validate_test.go b/validate_test.go
@@ -115,6 +115,27 @@ func TestValidateAcceptsUncompressedPlanes(t *testing.T) {
}
}
+// TestValidateLeavesARGBAlone records why the padding check covers only the
+// three plane types. actool on macOS 26 compiled an icon into an icns whose
+// ic04 is ARGB with its stream ending exactly on the last run, so warning
+// about that shape would be accusing Apple's own output.
+func TestValidateLeavesARGBAlone(t *testing.T) {
+ const side = 16
+ planes := make([]byte, side*side*4)
+ for i := range planes {
+ planes[i] = byte(0x40 + i/(side*side))
+ }
+ packed := packRLE(planes)
+ if len(packed) == len(planes) {
+ t.Fatal("fixture did not compress, so there is no run to end on")
+ }
+ data := file(encodeElement("ic04", append([]byte("ARGB"), packed...)))
+ problems := validate(t, data)
+ if _, ok := found(problems, "Apple silicon drops"); ok {
+ t.Errorf("reported padding for an ARGB icon: %v", problems)
+ }
+}
+
func TestValidateReportsAMissingMask(t *testing.T) {
planes, _ := splitPlanes(flat(32), 32)
data := file(encodeElement("il32", padRLE(packRLE(planes), len(planes))))