feat: add GIF decoder using Rust gif crate#104
Open
xfalcox wants to merge 5 commits intojamsinclair:mainfrom
Open
feat: add GIF decoder using Rust gif crate#104xfalcox wants to merge 5 commits intojamsinclair:mainfrom
xfalcox wants to merge 5 commits intojamsinclair:mainfrom
Conversation
Replace C/Emscripten giflib approach with Rust gif crate compiled via wasm-pack, matching the existing pattern used by png and oxipng packages. Supports decode (single frame), decodeAnimated (all frames with timing), and isAnimated methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Interactive HTML test page that demonstrates decode, decodeAnimated, and isAnimated methods with file input, animation playback controls, and timing info. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Import directly from the local wasm-pack output. Call init() for WASM initialization and pass Uint8Array to the raw wasm-bindgen functions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Redesigned example page with card layout, checkerboard transparency background, drag-and-drop file input, and a filmstrip showing all decoded frames as clickable thumbnails below the animation player. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All three exported functions (decode, decodeAnimated, isAnimated) now check for valid GIF87a/GIF89a headers before passing data to the gif crate, giving a clear error instead of a cryptic panic on non-GIF input. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
This was referenced Mar 31, 2026
Closed
xfalcox
added a commit
to discourse/jSquash
that referenced
this pull request
May 7, 2026
xfalcox
added a commit
to discourse/discourse
that referenced
this pull request
May 11, 2026
## Summary - Extends client-side image optimization to convert **JXL → JPEG**, **HEIC → JPEG**, and **animated GIF → animated WEBP** using jSquash WASM packages before upload - Transparent JXL/HEIC images are converted to **WEBP** instead of JPEG, so transparency is preserved (WEBP compresses much better than PNG for this case) - Gated as an **upcoming change** via `composer_media_optimization_image_convert_enabled` (experimental, `feature,all_members`, opt-in per group through the upcoming changes admin UI) - Sends raw file bytes to Web Worker for formats browsers can't decode natively (JXL, HEIC), with new `"convert"` and `"convertAnimated"` worker message types - Adds JXL to `authorized_extensions` and `supported_images`; adds HEIC/HEIF to `supported_images` for consistency - Skips GIF→WEBP when output is larger than input - Falls back to filename when MIME type is missing (browsers may not recognize JXL/HEIC) ### Note on jSquash packages This depends on Discourse-scoped forks of the jSquash packages (`@discourse/jxl`, `@discourse/heic`, `@discourse/webp`, `@discourse/gif`, `@discourse/jpeg`, `@discourse/resize`). The following upstream PRs would let us move back to the canonical `@jsquash/*` packages, but the upstream maintainer is currently unresponsive: - jamsinclair/jSquash#101 (`@jsquash/heic`) - jamsinclair/jSquash#103 (`@jsquash/webp` animated support) - jamsinclair/jSquash#104 (`@jsquash/gif`) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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
@jsquash/gifdecoder package using the Rustgifcrate (v0.13) compiled to WASM via wasm-packpngandoxipngpackagesdecode(first frame → ImageData),decodeAnimated(all frames with timing/disposal), andisAnimated(quick multi-frame check)Changes
codec/Cargo.toml— Rust crate config withgif,wasm-bindgen,js-sys,web-sysdepscodec/src/lib.rs— GIF decoder with full animation support (frame disposal methods, transparency, delay handling)codec/package.json+codec/pre.js— Build scripts and Node/CloudFlare Workers polyfills (matches png/oxipng pattern)decode.ts— TypeScript wrapper with lazy WASM init, GIF header validationindex.ts,meta.ts,package.json,tsconfig.json— Package scaffolding