gifski: a pngquant-based GIF encoder that spends its budget on cross-frame palettes
GIF encoder based on libimagequant (pngquant). Squeezes maximum possible quality from the awful GIF format.
At a glance
- What is it?
- gifski converts PNG frames or an ffmpeg yuv4mpegpipe stream into animated GIFs using per-frame palettes and temporal dithering. It is a CLI tool and, optionally, a C and WASM library, and its licence is AGPL-3.0-or-later.
- Who is it for?
- Adopt gifski if you already have ffmpeg or a directory of PNG frames and you care about colour fidelity more than about squeezing the last kilobyte, and if AGPL-3.0-or-later fits how you ship the result. Do not adopt it if you need a GUI (the README points Windows and macOS users at separate apps), if you need a prebuilt binary for Android or iOS, or if you cannot tolerate an imprecise size estimate.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 107 days ago.
- What is it written in?
- Mainly Rust, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The problem gifski solves, and who actually has it
GIF is a palette format. A conventional encoder picks one global palette for the whole animation, usually 256 colours, and every frame is drawn from that same set. On a screen recording of a UI, that is fine. On footage with gradients, skin tones or a camera pan, a single global palette runs out of colours and the result bands. gifski's stated approach is to use pngquant's features for efficient cross-frame palettes and temporal dithering, and it claims output that uses thousands of colours per frame. The mechanism behind that claim is a palette chosen per frame rather than once for the file, with dithering patterns varied between frames so the error does not sit still and read as texture.
The audience is narrow and specific. If you are comfortable in a terminal, have ffmpeg installed, and are producing an animation for a README, a chat message or a bug report, gifski is aimed at you. The README is explicit that it is a command-line tool and tells people who are not comfortable with a terminal to use the GUI version for Windows or macOS instead. That sentence is the honest boundary of the project: the CLI is the product, and the graphical front ends are separate downloads maintained elsewhere. If your input is already a GIF and you only want to shrink it, you are not the target either, because gifski's input is video frames or PNG frames, not existing GIFs.
How the encoder pipeline is put together
Two input paths exist in the default build. The first is a yuv4mpegpipe stream, which is what ffmpeg produces with -f yuv4mpegpipe; the README notes that reading a .y4m file from disk would also work but that these files are huge, which is why the documented usage pipes them. The second is a set of PNG frames, either exported from animation software or produced by ffmpeg with a numbered pattern. The Cargo.toml dependency list is consistent with that: y4m and yuv are optional dependencies, lodepng handles PNG decoding, and wild provides glob expansion for the frame pattern.
From there the work is quantisation and encoding. imagequant is the quantiser, gif-dispose and the gif crate handle frame disposal and container writing, resize handles scaling, and crossbeam-channel plus ordered-channel appear in the dependency list, which suggests frames are processed concurrently but written in order. That last detail matters for anyone embedding the library: the ordering guarantee is a deliberate part of the design, not an accident of a thread pool. The library surface is real too. The README states the tool can be compiled as a C library for use in other apps, and the repository ships gifski.h and cbindgen.toml at the top level alongside an Xcode project and a wasm-pack.toml, so C, Apple-platform and WebAssembly consumers are all anticipated by the build files. A Rust-facing API is published on docs.rs.
Installing gifski and making a first animation
The README lists three ways to get a binary: download an executable from the releases page, use Homebrew, or build from source with Rust from rustup. The Homebrew route is one command.
brew install gifskiThe cargo route needs a recent toolchain. The README says Rust 1.63 or newer for the cargo install path, while Cargo.toml declares rust-version 1.85 and edition 2024, so treat the manifest as the binding constraint if you build from a clone rather than from the published crate.
cargo install gifskiFor a first real conversion the shortest path is to let ffmpeg decode and gifski encode in one pipeline. The README gives this exact example, and the trailing dash is what tells gifski to read from standard input.
ffmpeg -i video.mp4 -f yuv4mpegpipe - | gifski -o anim.gif -If you would rather see the frames, export them first and pass them as a glob. The README warns that the wildcard must not be inside quotes.
ffmpeg -i video.webm frame%04d.png
gifski -o anim.gif frame*.pngExpect gifski to downsize automatically if the source resolution is too high for GIF, and expect a running estimate of the total file size during compression. The README is blunt that this estimate is very imprecise, so do not treat it as a contract. Run gifski --help for the full flag list.
Tuning file size, and why the quality knobs are a losing trade
The README's own advice on smaller files opens with a warning worth quoting in spirit: expect to lose a lot of quality for little gain, because GIF is not good at compressing no matter what you compromise. Given that, the ordering of the recommended levers is sensible. Width and height come first, because they make the biggest difference. Then a global --quality value, and then the two finer knobs: --lossy-quality, where lower values make animations noisier and grainier, and --motion-quality, where lower values cause smearing or banding in frames with motion. Those two descriptions are useful because they tell you what artefact to look for when you push them down. Grain is easier to accept than banding in most UI captures.
The README also gives a piece of advice that is easy to skip and expensive to ignore: if the input was ever encoded with a lossy video codec, halve the frame size at least, to hide compression artefacts and counter the chroma subsampling the codec performed. In practice that means a 1080p screen recording should not become a 1080p GIF. There is no size-target mode. If you need a GIF under a fixed byte budget, the README says you have to experiment with sizes and quality settings, and it does not document a search mode that does this for you. That is the main workflow gap in the tool.
Where gifski is the wrong tool
The built-in video support is the clearest limitation, and the README does not soften it. Decoding video directly relies on ffmpeg 6.x, which the README describes as possibly very hard to get working, so it is not enabled by default. Enabling it means having ffmpeg and libclang installed with their C headers in default system include paths, and the README names packages such as libavformat-dev, libavfilter-dev, libavdevice-dev, libclang-dev and clang. It then states plainly that on macOS and Windows this takes expert knowledge and can waste several hours on installation and compilation errors the author cannot help with. If your plan was a self-contained binary that reads MP4 files, the default build does not do that; the pipe from ffmpeg does.
Licensing is the second boundary. When compiled with video support, ffmpeg licences apply, and the README notes you may need a patent licence for H.264 or H.265 and recommends VP9/WebM instead. The third issue is scale: gifski is an encoder, not a GIF editor. It does not crop, add captions, or assemble frames from a timeline. And if you need to hit an exact file size, the imprecise estimate plus the lack of a target-size flag means you will be running the same command repeatedly with different numbers.
gifski against ffmpeg, gifsicle and ezgif
The obvious alternative is ffmpeg's own GIF output, and the difference is architectural. A typical ffmpeg GIF encode applies a single palette to the whole stream, often via a palettegen and paletteuse filter chain, so colours are shared across every frame. gifski makes the opposite bet: a palette per frame with temporal dithering, which is why its output can hold thousands of colours in a frame. The cost of that bet is a larger file and a slower encode. If your source is already low-colour, ffmpeg alone is entirely adequate and you avoid a second process.
gifsicle is not a competitor at the encoding stage. It operates on GIF files, so it is what you reach for after gifski has produced one, to optimise or inspect it. The two are complementary, not alternatives. ezgif is a browser-based service, which is a different trade: no install, but you upload your frames to someone else's server. That distinction matters if the footage is internal. The README's own GUI pointers for Windows and macOS are the other comparison point, and they are separate applications rather than a mode of this tool.
Licence, maintenance and the cost of upgrading
gifski's licence is AGPL-3.0-or-later, and Cargo.toml carries the same identifier. The README states that alternative licensing options, including commercial licences, are available on request, with a contact link. That is the practical implication for anyone embedding the library: AGPL is a strong copyleft licence, and if your product cannot comply with it, the path is to ask about a commercial licence rather than to assume the question away. Nothing here is legal advice; read the LICENSE file and talk to counsel if the answer affects your shipping plans.
The repository is not archived, and its most recent push was on 2026-06-17. The release history shows 1.34.0 on 2025-07-13, 1.33.0 on 2025-03-17, and 1.32.0 on 2024-04-24, and Cargo.toml declares version 1.35.0, so the manifest is ahead of the published release list. Upgrades have been incremental rather than disruptive, and the 1.32.0 release name, No temp PNGs needed, is the kind of change that removes a workaround rather than adding a feature. The real upgrade cost sits in the optional video feature: it pins you to a specific ffmpeg generation and a set of C headers, so a toolchain change on your build machine can break a build that was fine before. If you use only the default build with piped input, that cost does not apply.
Editorial conclusion
Adopt gifski if you already have ffmpeg or a directory of PNG frames and you care about colour fidelity more than about squeezing the last kilobyte, and if AGPL-3.0-or-later fits how you ship the result. Do not adopt it if you need a GUI (the README points Windows and macOS users at separate apps), if you need a prebuilt binary for Android or iOS, or if you cannot tolerate an imprecise size estimate. Before committing, verify three things on your own machine: that your ffmpeg build can emit yuv4mpegpipe, that the release binary or cargo install works on your platform, and that the estimated file size the tool prints during compression lands close enough to your target, since the README states the estimate is very imprecise.
Frequently asked questions
What is gifski?
It is a GIF encoder based on pngquant, distributed as a command-line tool that converts video frames or PNG frames into animated GIFs. The README describes it as producing animations that use thousands of colours per frame through cross-frame palettes and temporal dithering.
How does gifski work?
It reads either a yuv4mpegpipe stream or a set of PNG frames, quantises colours with imagequant, and writes a GIF using per-frame palettes with temporal dithering. The README frames this as using pngquant's features for efficient cross-frame palettes.
How do I install gifski?
The README gives three routes: download an executable from the releases page, run brew install gifski if you have Homebrew, or run cargo install gifski with Rust from rustup. Building from a clone uses cargo build --release, which places the binary in ./target/release.
Is gifski free?
It is released under AGPL-3.0-or-later, so there is no purchase price, and the README states that alternative licensing options including commercial licences can be arranged. The AGPL terms still apply to how you redistribute or embed it.
How do I use gifski on Windows?
The README directs Windows users who are not comfortable with a terminal to a GUI version distributed as an MSI, and otherwise describes the same command-line usage as other platforms. The documented ffmpeg pipeline works wherever both tools are installed.
Is gifski safe?
The README points to the releases page for executables and to Homebrew or cargo as the other install routes, which are the sources the project itself names. It does not make any security claims, so the safest path is to take binaries from those documented sources rather than a mirror.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/imageoptim-gifski)