Skip to content

Show transparent images frameless, like stickers - #27

Merged
gitautas merged 1 commit into
mainfrom
transparent-images-as-stickers
Oct 7, 2026
Merged

gitautas merged 1 commit into
mainfrom
transparent-images-as-stickers

Conversation

@gitautas

@gitautas gitautas commented Oct 7, 2026

Copy link
Copy Markdown
Owner

What

Images that are mostly transparent now render the way stickers do: no card border, no background, no rounded frame, and object-fit: contain instead of cover. Clicking still opens the lightbox.

Why

A transparent PNG pasted into a room is nearly always meant as a sticker (a character, a reaction, something cut out of its background). The card frame puts back the box it was cut out of.

How

  • src/lib/cutout.ts (new): for image/png|apng|webp|gif|avif only, fetches the thumbnail the timeline already shows, draws it at 48×48 and counts pixels with alpha < 128. If 4% or more are see-through, it's a cut-out. Answers are cached per mxc in memory and in localStorage (capped at 500), so there's no frame flash on later launches. Failed checks aren't persisted.
  • Why IPC instead of the <img>: an image from uwum:// is cross-origin, so drawing it taints the canvas. Rather than adding CORS headers to the private media protocol, the bytes come over get_media_bytes.
  • get_media_bytes now takes optional width/height so the check requests the same thumbnail as the <img> and hits the SDK media cache. Existing callers (video/audio) pass neither and behave as before. thumbnailSize() is factored out of mediaUrl in ipc.ts so both compute the same size.
  • ImageBody: cut-outs keep their picture-sized box, so detection doesn't shift the timeline.

Reviewer notes

  • macOS window screenshots with a drop shadow have a wide transparent margin and will also render frameless.
  • Detection only works on the receiving side, so it applies to images from any client. Nothing about what's sent changes. If a homeserver re-encodes PNG thumbnails as JPEG, the image just stays framed.
  • Not yet checked in a running build (dev builds can't be screenshotted). Typecheck, cargo check, and all 159 tests pass, 5 of them new for isCutout.

🤖 Generated with Claude Code

A mostly see-through PNG/WebP/GIF/AVIF is nearly always meant as a
sticker, and drawing it on a bordered card puts back the box it was cut
out of. Check the pixels of the thumbnail already on screen (over IPC, so
the canvas isn't tainted) and drop the frame, background and cropping for
cut-outs. Size is unchanged so the timeline doesn't shift; answers are
remembered across launches.

get_media_bytes takes an optional size so the check hits the same cache
entry as the <img>.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gitautas
gitautas merged commit e42fe94 into main Oct 7, 2026
2 checks passed
@gitautas
gitautas deleted the transparent-images-as-stickers branch October 7, 2026 19:08
@gitautas gitautas mentioned this pull request Oct 7, 2026
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.

1 participant