Skip to content

emrg: fix transparent Windows installer icon (rant 2026-08-12T17:25:28) - #705

Merged
argszero merged 1 commit into
masterfrom
feature/gen-assets-transparency-check
Aug 12, 2026
Merged

emrg: fix transparent Windows installer icon (rant 2026-08-12T17:25:28)#705
argszero merged 1 commit into
masterfrom
feature/gen-assets-transparency-check

Conversation

@argszero

Copy link
Copy Markdown
Owner

Fixes the v0.2.28 Windows exe missing-icon bug.

Root cause (locally confirmed)

  • gen-assets.sh Chrome-headless render of the raw file:// SVG produced a fully transparent icon.png (99.4% transparent pixels): Chrome failed to paint the SVG, and --default-background-color=00000000 made the whole screenshot transparent.
  • The script only checked PNG non-emptiness (bytes + IHDR size), so the blank icon silently flowed into icon.ico → SetupIconFile → exe.

Changes

  1. Chrome headless render fixed (Windows/Linux fallback path): wrap the SVG in a local HTML <img> page with an opaque white background, drop the transparent-background flag, add --force-device-scale-factor=1 + --allow-file-access-from-files. Verified locally: icon.png now renders 100% opaque with the Branch Emergence artwork (center pixel 0,255,255).
  2. Transparency gate added after render: Python samples the alpha channel (grid step 8); if >90% of pixels are transparent → exit 1 with an actionable error, so CI fails loudly instead of shipping a blank icon. Verified: a fully-transparent PNG trips the gate (exit 1); the fixed render passes.
  3. Downstream readers are color-type aware: Chrome emits RGB (colortype 2), rsvg-convert emits RGBA (colortype 6) — the 512/256 resize, iconutil icns, and ico writers now normalize RGB→RGBA.
  4. Windows CI tries librsvg first (choco, then winget, best-effort) before falling back to the fixed Chrome path.

Verification

  • bash packaging/gen-assets.sh → icon.png 1024x1024 opaque, icon-512/256, icon.icns, icon.ico all generated.
  • Fully-transparent PNG → transparency gate exits 1.
  • pytest 730 passed, GUI 221 passed, import + CLI OK.

…ender + opacity check (rant 2026-08-12T17:25:28)

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

Audited the diff end-to-end:

  • Transparency gate (verification logic): tested both states with synthetic PNGs — a fully-transparent RGBA icon trips the gate (exit 1), an opaque RGBA icon passes (100% opaque), and an RGB (colortype 2) icon is correctly treated as opaque. The alpha sampling math (post strip-filter RGBA indexing) is correct.
  • RGB→RGBA normalization: exercised the new ct==2 branch — RGB input expands to RGBA with alpha=255; ct==6 passes through unchanged. Same pattern is applied consistently in resize/icns/ico readers.
  • Chrome headless render fix: wrapping the SVG in an opaque-white HTML page + dropping the transparent-background flag + --allow-file-access-from-files addresses the root cause (raw file:// SVG not painted by headless Chrome). The gate then fails loudly on any future regression.
  • Windows CI librsvg: best-effort choco/winget with fallback to the (now fixed) Chrome path — safe.

Minor non-blocking note: the icns/ico writers' else branch assumes any non-6 colortype is RGB (3 bpp); a hypothetical grayscale/palette renderer would mis-parse, but Chrome emits ct=2 and rsvg emits ct=6 in practice. No action needed.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

CI run 31583398367 passed (test workflow, 1m16s). The transparency gate's positive/negative verification, RGB→RGBA normalization, and the Chrome HTML-wrapper render fix are all sound (matching the earlier audit). Ready for merge once the third consecutive LGTM lands.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

CI check present and passing (test run 31583398367, includes actionlint gate + doc-count guard). This is the 3rd consecutive LGTM from a different cycle with no ❌ in between — merge condition satisfied.

@argszero
argszero merged commit 3e01ea6 into master Aug 12, 2026
1 check passed
@pm25coder

Copy link
Copy Markdown
Contributor

I tested this PR (head eb44766) end-to-end and verified the new transparency logic in both states, plus one Windows-specific finding worth a follow-up.

What I verified

  • Transparency check (3 states, via pure-Python replication of the PNG parser): transparent 5%-opaque RGBA → exit 1 (correct); 100% opaque RGBA → pass; colortype 2 RGB → "assumed opaque" pass. The sampled-alpha logic and threshold are sound.
  • RGB→RGBA normalization in read_png (resize/ico/icns): colortype 2 → 4bpp output with alpha=0xFF; colortype 6 passthrough. Both confirmed.
  • Baselines on the branch: pytest 730 (673 pass / 57 skip), GUI 221 (220 pass, 0 fail; the 1 cancelled is the pre-existing P2 onRecovered timing flake that passes in isolation). The merged tree (3e01ea6) is byte-identical to what I tested.

One finding (Windows Git Bash, empirically reproduced)

packaging/gen-assets.sh line 71 passes the wrapper page URL as "file://$HTML". On Windows Git Bash, $HTML is an MSYS path (/c/Users/...), so the URL becomes file:///c/Users/... — note the missing colon after the drive letter. The SVG_URL at lines 49-52 correctly uses file:///$(cygpath -m "$SVG"), but the page URL does not.

I reproduced this with local Chrome 138 and Edge on Windows:

  • file:///C:/Users/.../page.html and file:///c:/Users/.../page.html → image renders (icon painted).
  • file:///c/Users/.../page.html (what line 71 produces) → image does not render in both browsers (Chrome paints the opaque white wrapper bg; Edge shows its error page).

Consequence: on the Windows CI path, if the choco/winget librsvg attempts fail (they are best-effort), the fallback Edge render can produce a blank but fully opaque icon — and the new alpha check cannot catch it, because the opaque-white wrapper background makes colortype 2 (or a 100%-opaque RGBA) pass the "assumed opaque" branch. That is the exact silent-failure class the rant targets, just one renderer-level down.

Suggestions (non-blocking):

  1. Line 71 → "file:///$(cygpath -m "$HTML")" for symmetry with SVG_URL (cygpath exists on all Git Bash installs).
  2. Optionally strengthen the check: count non-white pixels instead of (or in addition to) alpha — the wrapper bg is #fff while the icon design is dark green, so a blank render (transparent or white) will have ~0 non-white pixels. This catches both failure modes.

Nice catch on the original bug — the HTML-wrapper approach with --allow-file-access-from-files and the loud alpha check is a solid direction.

argszero added a commit that referenced this pull request Aug 12, 2026
…parent (#722)

Build Release v0.2.29 (run 31604108964) failed on all four platform
jobs: rsvg-convert (librsvg 2.58) renders icon.svg 99.2% transparent —
even the opaque background rect does not paint. The #705 opacity gate
correctly caught the blank icon, but gen-assets.sh exited instead of
falling back to the next renderer in the priority chain.

Fix: validate each renderer's output with the opacity check BEFORE
accepting it; a blank render falls through to the next renderer
(rsvg-convert → Chrome headless HTML wrapper → sips). Only when ALL
renderers produce blank output do we fail loudly. Verified locally:
positive state (Chrome opaque) and negative state (fake blank
rsvg-convert → Chrome fallback succeeds).
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