Video to GIF Converter

Pick the moment, see the size, save the GIF.

  • Own GIF encoder
  • Palette and dither
  • Size shown first
A short loop of dark film strip lying on a pale wooden desk beside two round, black-rimmed blank frames standing on edge.

The guide

A GIF made from video is a flipbook of 256-colour pages, and every page has a price

How an animated GIF stores motion, why each frame gets at most 256 colours, what palettes, dithering and frame delays really do, and when a short video file is simply the better choice.

  • 256 colours at most in one frame's palette
  • 1/100 s the unit of every GIF frame delay
  • 12 bits the widest LZW code a GIF decoder reads
  • 6.7 MB ten seconds of 320 px gradient video, as a GIF, in our test
Read the full guide Fold the guide 8 min · 16 sources

A video file and an animated GIF can show the same three seconds of a dog catching a ball, yet they are built on opposite ideas. A modern video codec stores a few complete pictures and then describes how the rest differ from them. A GIF stores pictures. It is a flipbook, and the format was never asked to be clever about what changes between one page and the next.

That one fact explains most of what surprises people when they turn a clip into a GIF: the file is bigger than the video it came from, the sky turns into bands, and the timing drifts if nobody does the arithmetic. None of this is a flaw in a particular converter. It is the format, read carefully.

A file format that predates the web it now decorates

GIF was released on 15 June 1987 by an online service that wanted a colour image format for its download areas. The 1989 revision, called 89a, added what animation needs: a delay between images, a transparent colour, and room for application data. The specification for 89a, dated 31 July 1990, is still the document a decoder follows. It describes a stream of blocks: a header, a logical screen, an optional global colour table, then any number of images, each optionally preceded by a Graphic Control Extension, and a single trailer byte at the end.

Animation lives in that Graphic Control Extension. It carries a delay time counted in hundredths of a second, a disposal method that says what happens to the frame once its time is up, and an optional transparent index. Looping came later and from outside the specification. In 1995 a browser’s version 2.0 used an application extension block, tagged NETSCAPE2.0, holding a repeat count from 1 to 65535, where zero means forever. Browsers adopted it, and it remains the way a GIF says “play again”.

So the unit of time is 1/100 s, not a frame rate. A GIF has no notion of 12 or 30 frames per second. It has a list of pauses.

Why 256 colours, and what a palette costs

Each frame is a grid of small numbers, and each number is an index into a colour table. A table holds at most 256 entries, chosen from the 24-bit RGB space, because a pixel in a GIF is at most eight bits. In 1987 that was generous: hardware that could show more than 256 colours at once was rare. A frame may use the file’s global table or carry a local table of its own, so the limit is 256 per frame rather than per file.

For a cartoon, a screen recording or a logo, 256 is plenty. For a video frame of a sunset it is not, and something has to decide which 256 colours survive. That job is colour quantization, and two classic methods still do it well. Median cut, developed by Paul Heckbert in his 1980 bachelor’s thesis and published in 1982, puts every colour in one bucket, finds the channel with the widest range, sorts by it and splits the bucket at the median. It repeats on the bucket with the widest range until there are as many buckets as palette entries, and each bucket’s average becomes a colour.

Octree quantization, first conceived by Gervautz and Purgathofer, sends each colour down a tree that splits red, green and blue one bit per level, then merges the smallest branches until few enough leaves remain. Both are fast. Median cut tends to spend entries where colours are spread out; the octree tends to protect colours that cover many pixels.

The more interesting choice is global or local. One palette for the whole clip keeps colours steady from frame to frame and saves the cost of a table per frame. A palette per frame fits each picture better but lets a flat wall shimmer as its nearest colour changes.

There is also a trap in the global route. If the palette is built from a sample of frames, a colour that only appears between the samples is missing. We hit exactly this while testing: a clip of eight flat colour bars, half a second each, sampled at eight frames, lost its blue bar entirely and showed cyan in its place. Building the palette from 24 frames spread across the clip fixed it. Sampling is a bet, and it should be stated as one.

Once the palette is fixed, every pixel must be mapped to an entry. Mapping each pixel to its nearest entry alone produces bands wherever a gradient falls between two palette colours. Dithering hides the bands by mixing nearby entries so that, from a normal viewing distance, the average looks right.

Floyd-Steinberg dithering, published by Robert Floyd and Louis Steinberg in 1976, takes the error left at each pixel and pushes it onto neighbours not yet visited: seven sixteenths to the right, and three, five and one sixteenths to the three pixels below. The weights were found by trial and error, aiming to turn a mid grey into a checkerboard. Running alternate rows in opposite directions, called serpentine scanning, avoids a drift in one direction. The result is fine grain that follows the picture closely.

Ordered dithering adds a fixed pattern instead. A threshold map, most often the Bayer map, is tiled over the image, and each pixel is nudged up or down by its cell’s value before the nearest colour is chosen. The Bayer map can be built recursively: the 2 by 2 map holds 0, 2, 3 and 1, and every larger map is four scaled copies of the one before. It leaves a visible crosshatch. It also has a property that matters enormously for animation: a pixel that did not change gets exactly the same treatment in the next frame.

That property decides file size. Error diffusion lets a tiny change in one corner ripple through every pixel after it, so a still background can flicker in its grain, and a flickering pixel has to be stored again. An ordered pattern stays put. Turning dithering off entirely gives the smallest files and the most banding.

Why GIFs get large

The compression in a GIF is LZW, published by Terry Welch in 1984 as an improvement on Lempel and Ziv’s 1978 method. It builds a dictionary of index sequences as it reads and emits a code for each sequence it has seen before. In a GIF the codes start one bit wider than the pixel indices and grow by a bit each time the table fills a width, up to 12 bits, which caps the table at 4096 entries.

A clear code empties the table so it can adapt to new patterns, and an end code closes the image. The encoder and decoder must widen their codes at exactly the same moment; widening one code too early or too late corrupts everything after it.

LZW is lossless and good at runs and repeats. It is poor at noise, and dithered video frames are close to noise. Worse, nothing in the format predicts one frame from the last. The two tools GIF does offer are worth using. A frame can cover a smaller rectangle than the whole screen, and pixels that did not change can be given the transparent index, which leaves the previous frame showing through. Our converter does both when “Skip unchanged pixels” is on, using the disposal method that keeps the last frame in place.

The difference that content makes is extreme. In our tests, three seconds of flat colour bars at 320 by 240 pixels and ten frames a second came to 3.5 KB. Ten seconds of a drifting colour gradient with a moving ball, at 320 by 180 pixels and 30 frames a second, came to 6.7 MB: 300 frames, almost all of them changed everywhere. The estimate the tool shows before encoding, taken from six encoded pairs of neighbouring frames, said about 5.8 MB for that clip, 14 percent low. An estimate from samples can only be as good as the samples.

Timing that adds up

Because delays are whole hundredths, most frame rates cannot be written exactly. Twelve frames a second wants 8.33 hundredths per frame. Writing 8 every time loses a third of a hundredth per frame, and over four seconds the clip ends a sixth of a second early. Carrying the rounding error forward fixes that: compute each frame’s start time, round the running total, and take differences.

A worked example you can reproduce in the tool with its sample clip: 4 seconds at 12 frames a second gives 48 frames with delays 8, 9, 8, 8, 9, 8 and so on, adding up to exactly 400 hundredths. At 30 frames a second the pattern is 3, 4, 3, and 2.5 seconds comes to 75 frames and 250 hundredths. In every case the total lands within half a hundredth of the length asked for.

Getting frames out of a video in a browser has its own honest limits. The converter seeks a video element to each planned time and waits for the seeked event, which fires once the seek completes and the seeking flag clears. Where the browser offers requestVideoFrameCallback, its metadata reports the presentation timestamp of the frame actually shown, and that is the time the tool records. A seek lands on a frame the decoder can display, not on an arbitrary instant. In our recorded test clip at 30 frames a second, measured times sat 16 to 20 milliseconds after the plan, and in the longer clip up to 61 milliseconds. The tool reports those offsets rather than claiming frame accuracy.

Checking the result matters as much as writing it. The tool decodes its own GIF back, and where the browser offers ImageDecoder, part of the WebCodecs API, it decodes every frame a second time with the browser’s own decoder and compares them pixel by pixel. In our runs every frame agreed.

When a short video is the better answer

For anything photographic and longer than a few seconds, a GIF is the wrong container. One widely read web performance guide shows a 3.7 MB GIF that became a 551 KB MP4 and a 341 KB WebM, and notes that a video element marked autoplay, loop, muted and playsinline behaves the way people expect a GIF to behave. Animated GIFs converted to lossy WebP have been reported to be about 64 percent smaller on average. Video codecs predict frames from one another, keep millions of colours and still come out smaller.

A GIF still earns its place where video cannot go: a chat or a forum that only accepts images, an email, a README, a tiny screen recording of an interface where flat colours keep the palette honest. Keep it short, keep it narrow, prefer an ordered dither or none for anything with a still background, and let unchanged pixels stay transparent. And if the clip flashes, remember the accessibility rule that nothing should flash more than three times in any one second. A converter can make the file; deciding whether the file should exist is still the person’s job.

The Graphics Interchange Format is the copyright property of CompuServe Incorporated, and GIF is a service mark property of CompuServe Incorporated; this acknowledgement is the one the GIF89a specification asks software that writes the format to make.

Sources

Every source consulted for this guide. Links checked October 23, 2026.

  1. GRAPHICS INTERCHANGE FORMAT(sm) Version 89a CompuServe Incorporated, hosted by the World Wide Web Consortium
  2. GIF - Wikipedia Wikipedia
  3. Lempel-Ziv-Welch Wikipedia
  4. Color quantization Wikipedia
  5. Median cut Wikipedia
  6. Octree Wikipedia
  7. Floyd-Steinberg dithering Wikipedia
  8. Ordered dithering Wikipedia
  9. HTMLVideoElement MDN Web Docs
  10. HTMLVideoElement: requestVideoFrameCallback() method MDN Web Docs
  11. HTMLMediaElement: seeked event MDN Web Docs
  12. HTMLMediaElement: seeking property MDN Web Docs
  13. ImageDecoder MDN Web Docs
  14. MediaRecorder MDN Web Docs
  15. Replace animated GIFs with video for faster page loads web.dev
  16. Understanding Success Criterion 2.3.1: Three Flashes or Below Threshold World Wide Web Consortium