Bhinish Dhiman
How to make an animated GIF from images, and keep the file small
Drop the images into the GIF maker, drag them into order, pick a width, set the frame delay, and read 'What this will weigh' before pressing Build the GIF. Size grows with width × height × frames: photographs cost 0.56 to 0.75 bytes per pixel per frame through this encoder, an interface screenshot 0.006. Halving the width quarters the file, which is a better fix than cutting colours.
Making a GIF from a handful of stills takes a minute. Making one that is not several megabytes takes knowing how the format charges you, and it charges in a way that is easy to work out before you press anything. This guide is about still images; if you are starting from a video clip, the measurements in video to GIF: the bytes per pixel per frame cover that case.
How a GIF charges you
An animated GIF is a stack of complete still images, each stored as 8-bit palette indexes and compressed with LZW, with a delay written next to each one. There is no motion estimation and no reference frame: nothing in the format notices that two frames are nearly the same picture. So the size is close to a multiplication:
bytes ≈ width × height × encoded frames × bytes per pixel per frame
The last term is set by the picture, not by any setting. Measured through the encoder this tool uses, in Chromium on 27 September 2026:
| Content | Bytes per pixel per frame |
|---|---|
| Photograph, 800 × 533, 8 frames | 0.56 to 0.69 |
| Photograph, 480 × 320, 8 frames | 0.59 to 0.75 |
| Flat colour bands | 0.033 |
| Interface screenshot | 0.006 to 0.013 |
That is two orders of magnitude between a photograph and a screenshot. LZW collapses long runs of identical pixels very well and gains very little on photographic grain, so no palette or dithering setting closes the gap.
Working out the weight before you build
The tool shows its estimate under “What this will weigh”, above the build button. It takes a 64 × 64 sample of your pixels, counts the distinct colours, and picks a rate between 0.03 bytes per pixel per frame (64 colours or fewer in the sample, which reads as flat) and 0.65 (2,000 or more, which reads as photographic). It then adds 800 bytes for the file and 24 for each frame. Here is that arithmetic for six 4:3 photographs:
| Set-up | Encoded frames | Frame size | Rate used | Estimate |
|---|---|---|---|---|
| Six photos, width 480 | 6 | 480 × 360 | 0.65 | 674,864 B |
| Six photos, width 240 | 6 | 240 × 180 | 0.65 | 169,424 B |
| Six photos, width 480, crossfade of 2, looping | 18 | 480 × 360 | 0.65 | 2,022,992 B |
| Twelve photos, width 800 | 12 | 800 × 600 | 0.65 | 3,745,088 B |
| Six flat screenshots, width 480 | 6 | 480 × 360 | 0.03 | 32,048 B |
The first row is 800 + 6 × (24 + 480 × 360 × 0.65) = 674,864. Three things fall out of the table.
Width is the lever. Halving the width from 480 to 240 quarters the pixels and took the estimate to 25% of the first row (169,424 ÷ 674,864 = 0.251). No other control comes close for the visual cost.
Crossfade is priced in whole frames. Each blend step is a complete extra frame. With two steps between each of six images, and the last image fading back into the first because the animation loops, 6 images become 6 + 6 × 2 = 18 encoded frames, and the estimate triples. The blends are held for 40 ms each, so the running time only grows from 1.2 seconds to 1.68 (6 × 200 ms + 12 × 40 ms).
The red line is 3,000,000 bytes. Past it, the estimate turns red. Twelve photos at 800 pixels wide crosses it comfortably.
The estimate is shown as a range 35% either side of the likely figure, and it is replaced by the real byte count once the file is built. Two limits on it are worth knowing. It does not change when you move “Colours” or “Dithering”, because it is driven by size, frame count and the pixel sample only. And for flat interface screenshots its lowest rate, 0.03, is above the 0.006 to 0.013 actually measured, so a screenshot GIF can come in well under the range shown.
Doing it in the GIF maker
- Open the GIF maker and press “Choose images”, or drop them on the box; they become the frames in the order you add them. HEIC straight from an iPhone usually needs converting first.
- Put the frames in order under “Frames · drag to reorder”. Drag a thumbnail, or use the ← and → buttons under it; × removes a frame, and “Add more images” adds to the end.
- Pick a width: 240, 320, 480 (the starting value), 640 or 800, or type one under “Exact width”. The height follows the shape of the first frame.
- Set the timing with the “Frame delay” slider, which starts at 200 ms (5 fps). To time frames individually, press “One delay for all” so it reads “Per-frame delays”, and type into the ms box under each thumbnail.
- Set “Loops · 0 is forever”. Frames of a different shape from the first are placed with “Fit inside” or “Fill and crop”, on a “White”, “Black” or “Grey” background.
- Read “What this will weigh”. If it is red or simply too big, lower the width before you touch anything else.
- Press “Build the GIF”, then “Download” (the button carries the real size). Under “The actual file”, the tool prints the true bytes per pixel per frame of what it just made.
The delay you type and the delay you get
The format stores each delay as a count of hundredths of a second, so every value lands on a 10 ms grid: 33 ms is stored as 30, which plays at 33.3 frames a second rather than 30. Underneath that, every major browser replaces a delay of 10 ms or less with 100 ms, a rule inherited from Netscape that nothing reports. The slider stops at 20 ms. The per-frame boxes accept 10, and if you type it, the tool warns in red that browsers will substitute 100 ms, and the preview plays at the slower speed the file will really have.
Colours and dithering
“Colours” offers 32, 64, 128 (the starting value) and 255, the most the format allows once one slot is kept for transparency. A single palette is built from every frame and shared, which is what stops flat areas shifting colour from frame to frame. “Dithering on” hides banding in gradients by scattering the error, and usually makes the file bigger, because scattered pixels give LZW fewer runs to collapse. Fewer colours do shrink a GIF, at the price of visible banding; the video-to-GIF measurements put figures on that trade.
GIF has one fully transparent palette slot and no partial transparency, so a soft-edged PNG frame is flattened onto the background colour you chose rather than left with a ragged fringe.
Other ways to do it
FFmpeg can build a GIF from numbered stills with a shared palette:
ffmpeg -framerate 2 -i frame%03d.png -vf "split[a][b];[a]palettegen[p];[b][p]paletteuse" out.gif
-framerate 2 shows two frames a second, which is 500 ms per frame (1,000 ÷ 2). frame%03d.png reads files numbered with three digits, frame001.png onwards. The filter chain generates one palette from the frames and then applies it, the same shared-palette idea the tool uses. macOS and Windows have no built-in way to make an animated GIF to point you to.
Before you make one at all, check whether the destination takes video. The same animation as an MP4 or WebM is routinely ten to fifty times smaller and plays more smoothly; GIF is the right answer when the destination accepts images only.
Checking that nothing was uploaded
Open your browser’s developer tools on the Network tab before you build. Pressing “Build the GIF” the first time fetches the encoder, 11.6 KB gzipped from this site; no request carries your frames anywhere, because they are composited and encoded in the tab.
Build yours in the GIF maker, and read the weight before you press the button. If the frames need cropping or straightening first, do it in the image editor, which encodes them once rather than three times.