Skip to content

Set width/height on outgoing image attachments - #2093

Merged
AsamK merged 2 commits into
AsamK:masterfrom
mikesimone:add-attachment-image-dimensions
Jul 29, 2026
Merged

AsamK merged 2 commits into
AsamK:masterfrom
mikesimone:add-attachment-image-dimensions

Conversation

@mikesimone

@mikesimone mikesimone commented Jul 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

AttachmentUtils.createAttachmentStream() never populates SignalServiceAttachmentStream's width/height fields, even though the SignalServiceAttachment.Builder has supported withWidth()/withHeight() since at least the currently-pinned libsignal-service version (2.15.3_unofficial_149). Without those fields set, other Signal clients render outgoing image attachments as a square-cropped thumbnail instead of their real aspect ratio, since the receiving client has no dimension metadata to lay the attachment out correctly.

This PR probes the attachment's dimensions with ImageIO when the content type is image/* and the payload is under 20MiB, then passes them through to the builder. Behavior is unchanged for everything else:

  • Non-image attachments: width/height stay 0, exactly as before.
  • Oversized images (>20MiB) or anything ImageIO can't parse: falls back to width/height 0, attachment still sends normally.
  • The bytes handed to the builder for upload are byte-for-byte identical to the original stream in all cases β€” probing never mutates or truncates the outgoing attachment.

Test plan

  • ./gradlew :lib:build passes (existing test suite green)
  • Added AttachmentUtilsTest with two cases:
    • a real in-memory PNG confirms width/height come back correctly and the uploaded stream bytes match the source image exactly
    • a non-image payload confirms width/height stay 0 and bytes are still passed through unchanged
  • Manual test forwarding an image via signal-cli against a live account (not yet done β€” happy to if useful for review)

πŸ€– Generated with Claude Code

mikesimone and others added 2 commits July 26, 2026 08:18
createAttachmentStream() never populated SignalServiceAttachmentStream's
width/height fields, even though the Builder has supported them since at
least the currently pinned libsignal-service version. Without them, other
Signal clients render outgoing image attachments as a square-cropped
thumbnail instead of their actual aspect ratio.

Probe dimensions via ImageIO for image/* attachments up to 20MiB (buffered
in memory only for that check) and pass them through to the builder.
Falls back to width/height 0 (today's behavior) for non-images, oversized
files, or anything ImageIO can't parse.
@AsamK
AsamK merged commit 9878320 into AsamK:master Jul 29, 2026
7 checks passed
zdiemer added a commit to zdiemer/selfhosted that referenced this pull request Aug 13, 2026
Sending any photo over Signal failed. 0.14.7 added "Set width/height on
outgoing image attachments" (AsamK/signal-cli#2093), which reads the image
through javax.imageio β€” and the GraalVM native build we use ships no
ImageIO/AWT at all. A regression landing in exactly the version we pinned.

Confirmed against the live daemon: a text attachment by path succeeds, the
same photo declared image/jpeg fails with "Could not initialize class
javax.imageio.ImageIO", and the release notes name the feature that added the
call. The native tarball is a single binary β€” nothing was being discarded by
the Dockerfile's targeted extract, so there were no AWT libs to restore.

0.14.6 does not read dimensions and is five weeks older, well inside what
Signal's servers accept.

The untyped data URI fallback from the previous commit stays as a safety net,
but it is not a fix: Signal renders application/octet-stream as a "MacBinary
archive" file card rather than an inline image, which is what the first real
send produced. My earlier reading that it previewed correctly was wrong.

The JVM distribution plus a Java 21 runtime is the other way out and would
even shrink the image ~200MB, but it replaces the daemon this surface talks
over, to recover a dimensions field. Documented in the Dockerfile with what to
check before anyone bumps this again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
elShiaLabeouf added a commit to elShiaLabeouf/signal-cli that referenced this pull request Aug 29, 2026
Extends the outgoing attachment dimension probe (added for images in
AsamK#2093) to video: MP4/QuickTime/M4V via ISO-BMFF box walking (moov >
trak > tkhd, honoring the rotation matrix for portrait video) and
WebM/Matroska via EBML parsing (Segment > Tracks > TrackEntry > Video).
No new dependencies, no frame decoding, same 0/0-on-failure posture as
the image probe.

Recipients currently see outgoing videos as a generic file row instead
of a video tile with a play button until they download it, because
signal-cli sends no width/height metadata for video attachments (only
images get this today). Setting real dimensions is a prerequisite for
clients to render a proper preview tile.

Off by default behind a new --set-video-preview flag (also available
over JSON-RPC as setVideoPreview), since it changes outgoing
attachment metadata that existing automated workflows may depend on
staying byte-for-byte the same. Threaded through Message ->
AttachmentHelper -> AttachmentUtils; image probing is unaffected.
@mikesimone
mikesimone deleted the add-attachment-image-dimensions branch October 30, 2026 19:20
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