Skip to main content

GIF Color Changer

Command line tool for replacing colors across every frame of a GIF.

Try it in your browser → It runs the real CLI on Pyodide, so nothing is uploaded.

Install

uv tool install gif-color-changer

Or with pipx:

pipx install gif-color-changer

Or run it once without installing:

uvx --from gif-color-changer gifcc input.gif output.gif --map "#FFFFFF=#FF0000"

From a local checkout:

uv tool install .

Usage

gifcc input.gif output.gif \
  --map "#FFFFFF=#FF0000" \
  --map "#000000=#00FF00"

Each --map is:

source_color=replacement_color

So this:

--map "#FFFFFF=#FF0000"

means:

replace white with red

You can pass as many mappings as you need. They run in order, and a pixel is only changed once.

Alpha is not part of color matching. The tool only changes RGB values and preserves each pixel's original alpha value, including fully transparent pixels.

Transparency

The replacement (right-hand) side of a mapping can be the keyword transparent (or none) instead of a hex color, which makes every matched pixel fully transparent:

gifcc input.gif output.gif \
  --map "#FFFFFF=transparent"

This knocks out a solid color, for example to drop a flat background. Matching is still RGB-only and respects --tolerance; only the right-hand side may be transparent. With --softness, pixels near the edge of the tolerance range fade out gradually (their alpha drops proportionally) instead of being cut out abruptly.

transparent also works as a target in palette mode (see below).

Tolerance

GIF colors are often not exactly what they look like, especially after palette conversion or compression. Use --tolerance to match colors that are close to the source color.

gifcc input.gif output.gif \
  --map "#FFFFFF=#FF0000" \
  --tolerance 20

The default tolerance is 50.

Softness

Use --softness to blend pixels near the edge of the tolerance range instead of fully replacing every matched pixel.

gifcc input.gif output.gif \
  --map "#FFFFFF=#FF0000" \
  --tolerance 20 \
  --softness 8

With --tolerance 20 --softness 8, pixels within distance 12 of the source color are fully replaced. Pixels between 12 and 20 are blended proportionally from their original color toward the replacement color.

The default softness is 25. Use --softness 0 for hard replacement.

Palette Rewrite Mode

Palette mode rewrites every pixel by mapping its RGB value to the nearest color in a source palette, then forcing it to the color at the same position in a target palette. Alpha values are preserved unchanged.

gifcc input.gif output.gif \
  --source-palette "#000000,#808080,#FFFFFF" \
  --target-palette "#1D3557,#E63946,#F1FAEE"

Both palettes must contain the same number of colors. The source and target palettes are matched by position, so the first source color maps to the first target color, the second source color maps to the second target color, and so on.

Any target palette entry may be transparent (or none) to make every pixel assigned to that bucket fully transparent, while still mapping the remaining buckets to colors:

gifcc input.gif output.gif \
  --source-palette "#000000,#808080,#FFFFFF" \
  --target-palette "#1D3557,#E63946,transparent"

Source palette colors must be hex; only the target side accepts transparent.

Palette mode cannot be combined with --map, --tolerance, or --softness.

By default, palette mode uses squared RGB distance. Use --distance weighted-rgb to weight channel differences by perceptual luminance:

gifcc input.gif output.gif \
  --source-palette "#000000,#808080,#FFFFFF" \
  --target-palette "#1D3557,#E63946,#F1FAEE" \
  --distance weighted-rgb

Edge cleanup

Because each pixel is classified to its nearest palette color independently, antialiased or dithered pixels along an edge can land in a different bucket than the region around them, leaving isolated speckles of an unexpected color.

Use --cleanup to run one or more cleanup passes that reassign such pixels to the palette bucket that dominates their neighborhood:

gifcc input.gif output.gif \
  --source-palette "#000000,#808080,#FFFFFF" \
  --target-palette "#1D3557,#E63946,#F1FAEE" \
  --cleanup 2

Each pass reassigns a pixel whenever some other bucket occupies more of its 8-neighborhood than its own bucket does, snapping it to whichever neighbor color surrounds it most. This absorbs isolated speckles and the thin intermediate-color bands that form along antialiased edges, while pixels inside a solid region or on a real boundary are left intact, because their own side still dominates their neighborhood. More passes dissolve thicker bands but can also erode thin, legitimate detail.

Transparency is treated as just another region, so a pixel takes on the color and opacity of whatever surrounds it most. A stray opaque pixel sitting in transparent space becomes transparent, and a transparent hole inside a solid region fills in with that region's color. This also means a visible pixel bordering transparency is never recolored toward the hidden color of the transparent area around it.

--cleanup defaults to 0 (off) and is only valid in palette mode.

Output

The script prints how many pixels were changed for each mapping:

(255, 255, 255) -> (255, 0, 0): changed 1234 pixel(s)

In palette mode, it prints how many pixels were assigned to each source palette bucket:

(0, 0, 0) -> (29, 53, 87): assigned 1234 pixel(s)

If a mapping says it changed 0 pixels, the source color probably does not exist in the GIF at that tolerance.

Use with AI agents

  • Any agent: point it at llms.txt. It covers install steps, every flag and worked examples.

  • Claude Code: install the skill in skills/gifcc/SKILL.md and Claude will handle GIF recoloring requests on its own:

    mkdir -p ~/.claude/skills/gifcc && curl -fsSL \
      https://mpeyfuss.github.io/gif-color-changer/SKILL.md \
      -o ~/.claude/skills/gifcc/SKILL.md
    

Uninstall

uv tool uninstall gif-color-changer

Development

Set up the repo and install the git pre-commit hooks:

uv sync
make hooks

The hooks run ruff (lint + format) and pyrefly (type checking) on every commit. CI runs the same hooks. To run them across the whole repo by hand:

make lint    # ruff check, ruff format, pyrefly
make check   # lint + tests

Run tests:

uv run pytest

Run tests against a specific Python version:

uv run --python 3.11 pytest

Or use the Makefile:

make test
make test-all
make test-3.11

Run the command without installing it as a tool:

uv run gifcc input.gif output.gif \
  --map "#FFFFFF=#FF0000"

Browser playground

The playground in site/ is a Vite + TypeScript app, managed with Bun. On page load it installs the latest gif-color-changer release from PyPI into Pyodide inside a Web Worker, so publishing a new version updates the playground without a redeploy. Pushes to main that touch site/ or skills/ deploy it to GitHub Pages via .github/workflows/pages.yml.

make site        # dev server at http://localhost:5173/gif-color-changer/
make site-build  # test, build and preview the production bundle

Build

uv build

That writes the package artifacts to dist/.

Releasing

Publishing a GitHub Release uploads the package to PyPI via .github/workflows/release.yml (PyPI Trusted Publishing, no API token).

  1. Bump the version and push it to main:

    uv version --bump patch   # or minor / major
    git commit -am "bump version to $(uv version --short)"
    git push
    
  2. On GitHub, draft a new Release with a tag v<version> that matches pyproject.toml (e.g. v0.5.1) and publish it.

  3. CI runs the tests, checks the tag matches the version, builds, publishes to PyPI and attaches the wheel and sdist to the Release.

Release files for gif-color-changer 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gif-color-changer 0.5.1
File Size Uploaded
gif_color_changer-0.5.1.tar.gz 9.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gif-color-changer 0.5.1
File Interpreter ABI Platform
gif_color_changer-0.5.1-py3-none-any.whl Python 3 none any Details

Total release size: 20.0 kB

Release files / gif_color_changer-0.5.1.tar.gz

Download URL gif_color_changer-0.5.1.tar.gz
Size 9.4 kB
Tags Source
SHA-256 checksum
How to use checksums
a62847a97905ea79d2b39e8a3fd09814cd386f3c5990f871f1838e341218d901
BLAKE2b-256 checksum
How to use checksums
f664cadcb52a93d851ddea6c80945546933b729c05ccff7f158cc5e43d854587
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / gif_color_changer-0.5.1-py3-none-any.whl

Download URL gif_color_changer-0.5.1-py3-none-any.whl
Size 10.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
82857136b6d53639fa01ba857df7f709cab5ae7f926b39f7f629c04122a33516
BLAKE2b-256 checksum
How to use checksums
5967fdacc37cf395af7d143f7e060ce04e37be6b74f0a001f122cc679ec337fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.19 {"installer":{"name":"uv","version":"0.12.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.1 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page