GIF compressor · color audit
Why Does a GIF Compressor Change Colors?
Direct answer: this compressor rebuilds every retained frame with a new limited palette, so even Light is not color-lossless. In a controlled 256-color test, Light kept the 16 × 16 canvas but wrote 128 decoded colors; 48 of 256 pixels kept their exact source RGB values. Balanced also capped the palette at 128, while Smallest wrote 64 colors.
Measured production output
One 256-color grid through all three presets
| File | Dimensions | Decoded colors | File bytes |
|---|---|---|---|
| Source | 16 × 16 | 256 | 1,114 |
| Light | 16 × 16 | 128 | 696 |
| Balanced | 12 × 12 | 128 | 603 |
| Smallest | 8 × 8 | 64 | 321 |
Method: scripts/verify-gif-compressor-color-quality.mjs generated one opaque 16 × 16 frame with 256 distinct indexed colors, processed it through the live production compressor in headless Chrome, decoded every output, and counted distinct RGBA values. These figures describe this fixture, not a promised result for another GIF.
Isolate the palette step
Light changed colors without resizing the frame
Light kept the original 16 × 16 dimensions and the single frame, so its comparison isolates the palette rebuild from scaling and frame removal. Of 256 corresponding pixels, 48 retained the exact source red, green, and blue values. The mean absolute difference was 5.73 levels per RGB channel, and the largest single-channel difference was 11 levels.
Those values are measurements from this synthetic grid, not a visual-quality score. A small numeric shift can matter in a flat logo or keyed color, while a larger shift can be difficult to notice in a textured frame. The useful decision is to inspect the actual output at its intended display size.
Current implementation
Each retained frame gets a new local palette
The current compressor composites a rendered frame, reads its RGBA pixels, builds a palette with RGBA4444 quantization, maps every pixel to the nearest selected entry, and writes the indexed frame. Light and Balanced request at most 128 colors per frame; Smallest requests at most 64. There is no lossless mode, dither control, or global-palette control in this interface.
The GIF89a specification defines color tables whose entries are addressed by pixel indexes. SwapMyGIF does not copy the source table: it derives new entries from the rendered pixels. A frame that starts with fewer colors may use fewer than the preset ceiling.
Separate three causes
Palette loss, scaling, and transparency are different checks
| Visible symptom | Likely step to inspect | Useful comparison |
|---|---|---|
| Flat colors shift or merge | Palette rebuilding | Original versus Light at 100% zoom |
| Thin edges or text soften | Canvas scaling | Light versus Balanced |
| Transparent edges change | Binary alpha and disposal | Replay on the final background |
Use the transparency audit for alpha and disposal behavior. The separate face-swap dithering guide describes another encoder path with different palette settings; its measurements do not describe this compressor.
A repeatable review
Compare from the original, not from an earlier compressed copy
- Keep the source open. Use it as the input for every preset so palette loss does not accumulate.
- Start with Light. It keeps dimensions and frames, making color changes easier to isolate.
- Inspect critical regions. Check logos, skin gradients, small text, flat backgrounds, and transparent edges.
- Replay the complete loop. A separate palette is built for every retained frame, so a color can vary over time.
- Keep the original when needed. A smaller byte count is not useful when essential colors or detail are lost.
Direct answers
GIF compressor color questions
Does Light preserve every source color?
No. Light keeps dimensions and frames but rebuilds each retained frame with at most 128 colors.
Is 128 colors the same as 50% visual quality?
No. It is a palette-entry ceiling, not a quality percentage. The visible effect depends on the source pixels and which colors the quantizer selects.
Can the compressor add dithering?
No. The current interface has no dither control. It maps rendered pixels to a newly selected per-frame palette.
Will the same color change on every GIF?
No. The measured values above belong to one controlled 256-color grid. Another frame can produce a different palette and different pixel errors.
Protect essential colors before chasing fewer bytes.
Start with Light, compare the decoded result, then accept scaling or fewer colors only when the final display still works.
Compress and compare