terminal/kitty: accept first-frame GIF images via Wuffs#381
Merged
Conversation
Extend the Kitty graphics image decoder to handle GIF payloads, rendering the first frame only. Animation requires a separate design pass (renderer-side clock, disposal compositing, repaint hooks); this PR establishes the still-image plumbing so emitters using iTerm2 OSC 1337 File= can ship GIF logos and screenshots. - pkg/wuffs/src/c.zig enables WUFFS_CONFIG__MODULE__GIF (and the LZW module that the GIF decoder depends on); the build flag flows through to the wuffs amalgamation via the existing defines->flags pipeline in pkg/wuffs/build.zig. - New pkg/wuffs/src/gif.zig wrapper mirrors jpeg.zig with the extra decode_frame_config step that GIF requires before decode_frame, and a destination-buffer @Memset so sub-canvas frames keep transparent pixels rather than carrying debug-allocator poison bytes. After decoding the first frame, a second decode_frame_config call detects multi-frame sources and emits a log.debug so the dropped frames are visible at --log-level=debug. - Mirrors PNG/JPEG plumbing end-to-end: decode_gif sys slot, GhosttySysDecodeGifFn C ABI typedef + GHOSTTY_SYS_OPT_DECODE_GIF=4 enum entry, new .gif Format variant on the kitty graphics Transmission enum (Ghostty-internal; no Kitty wire f= code) with the matching GHOSTTY_KITTY_IMAGE_FORMAT_GIF=6 C ABI entry, init guard / shared-memory size / complete() dispatch arms, renderer switch arm, and iTerm2 OSC 1337 synth sniff for the "GIF8" magic (47 49 46 38) covering both GIF87a and GIF89a. Verified end-to-end on Windows and macOS.
4 tasks
deblasis
added a commit
that referenced
this pull request
May 21, 2026
Extend the Kitty graphics image decoder to handle GIF payloads, rendering the first frame only. Animation requires a separate design pass (renderer-side clock, disposal compositing, repaint hooks); this PR establishes the still-image plumbing so emitters using iTerm2 OSC 1337 File= can ship GIF logos and screenshots. - pkg/wuffs/src/c.zig enables WUFFS_CONFIG__MODULE__GIF (and the LZW module that the GIF decoder depends on); the build flag flows through to the wuffs amalgamation via the existing defines->flags pipeline in pkg/wuffs/build.zig. - New pkg/wuffs/src/gif.zig wrapper mirrors jpeg.zig with the extra decode_frame_config step that GIF requires before decode_frame, and a destination-buffer @Memset so sub-canvas frames keep transparent pixels rather than carrying debug-allocator poison bytes. After decoding the first frame, a second decode_frame_config call detects multi-frame sources and emits a log.debug so the dropped frames are visible at --log-level=debug. - Mirrors PNG/JPEG plumbing end-to-end: decode_gif sys slot, GhosttySysDecodeGifFn C ABI typedef + GHOSTTY_SYS_OPT_DECODE_GIF=4 enum entry, new .gif Format variant on the kitty graphics Transmission enum (Ghostty-internal; no Kitty wire f= code) with the matching GHOSTTY_KITTY_IMAGE_FORMAT_GIF=6 C ABI entry, init guard / shared-memory size / complete() dispatch arms, renderer switch arm, and iTerm2 OSC 1337 synth sniff for the "GIF8" magic (47 49 46 38) covering both GIF87a and GIF89a. Verified end-to-end on Windows and macOS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extend the Kitty graphics image decoder to handle GIF payloads, rendering the first frame only. Animation requires a separate design pass (renderer-side clock, disposal compositing, repaint hooks); this PR establishes the still-image plumbing so emitters using iTerm2 OSC 1337 File= can ship GIF logos and screenshots.
Seventh PR in the iTerm2 OSC 1337 series (after #375 #376 #377 #378 #379 #380). Closes the image-format gap on the iTerm2 synth path: PNG + JPEG + GIF.
Architecture
Mirrors PNG/JPEG plumbing end-to-end:
pkg/wuffs/src/c.zigenablesWUFFS_CONFIG__MODULE__GIF(and theWUFFS_CONFIG__MODULE__LZWmodule the GIF decoder depends on). The build flag flows through to the Wuffs amalgamation via the existingdefines -> flagspipeline in pkg/wuffs/build.zig.jpeg.zigwith two GIF-specific additions:decode_frame_configstep that GIF requires beforedecode_frame(PNG/JPEG short-circuit because they are single-frame).@memseton the destination buffer so sub-canvas frames keep transparent pixels rather than carrying debug-allocator poison bytes.decode_frame_configcall detects multi-frame sources and emits alog.debugso dropped frames are visible at--log-level=debug.decode_gifsys slot in src/terminal/sys.zig,GhosttySysDecodeGifFntypedef +GHOSTTY_SYS_OPT_DECODE_GIF=4enum entry in include/ghostty/vt/sys.h, new.gifFormat variant +GHOSTTY_KITTY_IMAGE_FORMAT_GIF=6in the kitty graphics C ABI, init guard + shared-memory size +complete()dispatch arms in src/terminal/kitty/graphics_image.zig, renderer switch arm in src/renderer/image.zig, and iTerm2 OSC 1337 synth sniff for the "GIF8" magic (47 49 46 38) covering both GIF87a and GIF89a.Tests
gif_decode_000000,gif_decode_FFFFFF).set decode_gif with null clears,set decode_gif installs wrapper) mirroring PNG/JPEG coverage.GIF89aheader payload.zig build testgreen on Windows and macOS.Out of scope
windows/Ghostty/Interop/NativeMethods.csdoesn't install any of the PNG/JPEG/GIF callbacks today. This PR inherits the gap; a separate PR can add the C# bindings.Test plan
zig build testpasses on Windowszig build testpasses on macOS (via SSH bundle)imgcat logo.gifon Wintty.exe