fix(media): "Compress image" no longer blackens transparent images or freezes animations (#331) #399

Merged
jared merged 1 commits from fix/compress-alpha-anim into lotus 2026-10-18 07:23:10 -04:00
Owner

Fixes #331.

"Compress image before uploading" re-encodes through a canvas to JPEG, and only PNG was skipped:

  • a transparent WebP (sticker, logo) came out with a black background;
  • an animated GIF or WebP became a single still frame.

Change

  • isCompressible no longer offers image/gif or image/apng.
  • compressImage returns null (upload the original) for an animated WebP, detected by the VP8X header's animation flag.
  • It also returns null for any image with a transparent pixel, checked on the canvas before encoding.
  • Opaque JPEG and WebP still compress as before.

Verified with the real compressImage in Chromium, using 64×64 WebPs made on a canvas:

  • transparent → kept original;
  • opaque → image/jpeg;
  • isCompressible('image/gif') → false.

Unit tests for isAnimatedWebp and hasTransparency. The existing GIF-compressible assertion is updated, since that behaviour changes on purpose.

tsc clean · ESLint clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5

Fixes #331. "Compress image before uploading" re-encodes through a canvas to JPEG, and only PNG was skipped: - a **transparent WebP** (sticker, logo) came out with a **black** background; - an **animated GIF or WebP** became a **single still frame**. **Change** - `isCompressible` no longer offers `image/gif` or `image/apng`. - `compressImage` returns `null` (upload the original) for an **animated WebP**, detected by the VP8X header's animation flag. - It also returns `null` for any image with a **transparent pixel**, checked on the canvas before encoding. - Opaque JPEG and WebP still compress as before. **Verified** with the real `compressImage` in Chromium, using 64×64 WebPs made on a canvas: - transparent → **kept original**; - opaque → `image/jpeg`; - `isCompressible('image/gif')` → `false`. Unit tests for `isAnimatedWebp` and `hasTransparency`. The existing GIF-compressible assertion is updated, since that behaviour changes on purpose. `tsc` clean · ESLint clean. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared added 1 commit 2026-10-17 20:57:37 -04:00
fix(media): "Compress image" no longer blackens transparent images or freezes animations (#331)
CI / Build & Quality Checks (pull_request) Successful in 3m13s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 13s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m29s
3a74699fef
Compression re-encodes through a canvas to JPEG. Only PNG was skipped,
so a transparent WebP came out on a black background, and an animated
GIF or WebP became one still frame. GIF and APNG are no longer offered;
an animated WebP (VP8X animation flag) or any image with a transparent
pixel is kept as the original.

Fixes #331

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
jared merged commit 3f94d73c7a into lotus 2026-10-18 07:23:10 -04:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: LotusGuild/cinny#399