← all builds

From-Scratch Build · Media Tooling

GIF Compression & Conversion Tool

Give it a bloated GIF and a target size, and it shrinks the file to fit while keeping it looking as good as possible. It can also turn an MP4 clip into a tidy, optimised GIF. Runs as a browser app or straight from the command line. Built from scratch to learn how images are squeezed.

PythonPillowStreamlit FFmpeggifsicle

What it is

Hit a size, keep the quality

The tool solves one stubborn, everyday problem: a GIF is too big to attach, post or embed. You hand it a file and say "get this under one megabyte", and it works toward that budget automatically — trading away just enough detail to fit, and no more. It also accepts an MP4 and converts the clip into a GIF first, so a screen recording becomes a shareable loop.

I built this because "make it smaller" hides a surprising amount of engineering. There is no single knob — file size is the product of colours, dimensions, frame count and timing, and the art is deciding which to sacrifice and in what order.

The core idea I wanted to learn: compression to a target size is a search problem. You can't compute the perfect setting up front, so you try a strategy, measure the result, and adapt — reducing colours first, then scale, then frames — until the file lands inside the budget.

The stack

Tools under the hood

This rebuild leans on a few specialised media tools, each handling one part of the job. Here is what they do.

imaging

Pillow

The Python imaging workhorse — reads and writes GIF frames, reduces colour palettes and rescales as a dependable fallback.

interface

Streamlit

Turns the script into a browser app with upload, a settings sidebar, and a side-by-side before/after comparison.

video

FFmpeg

Handles MP4-to-GIF conversion cleanly when present; the tool falls back to a pure-Python path when it isn't.

optimiser

gifsicle

A dedicated GIF optimiser that squeezes harder than Pillow alone, used automatically whenever it's installed.

cli

Command line

The same engine as a scriptable command, with batch mode to process a whole folder of GIFs at once.

packaging

Docker

A container image bundles the app and its media tools so it runs the same anywhere without a manual setup.

Architecture

The adaptive squeeze

Compression runs as a loop that keeps trying harder strategies until the file fits the target. Each step gives up a little more, so the result is the gentlest reduction that still meets the budget.

  1. Ingest live

    Take a GIF directly, or convert an incoming MP4 to a GIF first via FFmpeg or the Python fallback.

  2. Pre-process live

    Optional cropping of dead borders, frame sampling and frame-duration tweaks before the real work begins.

  3. Reduce colours live

    The first, cheapest lever — fewer palette colours often hits the target with little visible loss.

  4. Scale down live

    If colour reduction isn't enough, shrink the dimensions toward a configurable floor.

  5. Drop frames live

    As a last resort, sample out frames to cut size further while keeping the motion readable.

  6. Optimise & export live

    Run gifsicle for a final pass when available, then offer the result for download.

How it runs

Two front doors

The same engine is wrapped two ways, depending on whether you want clicks or scripts:

In my rebuild I cared most about the ordering of strategies — reaching the target with the least visible damage is the difference between a useful tool and a blunt one.

Reflection

What rebuilding it taught me