Installing Pillow and the format matrix
Install a build with the codecs you actually need, and query Pillow at runtime to see which formats it can read and write.
Install the right build
pip install --upgrade Pillow
# confirm it is real Pillow, not the abandoned PIL
python -c "import PIL; print(PIL.__version__, PIL.__file__)"
# which optional codecs did this build get?
python -c "from PIL import features; features.pilinfo()"The import name is still PIL for historical reasons, but the package is pillow. If PIL.__file__ points somewhere unexpected, an old PIL install is shadowing it — uninstall both and reinstall Pillow.
- Prebuilt wheels include JPEG, PNG, GIF, BMP, TIFF and WebP support, which covers almost every project.
- Building from source requires the development headers:
libjpeg-turbo,zlib,libtiff,libwebpandlibfreetypefor text. Missing headers silently drop a codec rather than failing the build. - Rare formats live in separate packages:
pillow-heiffor HEIC/AVIF,pillow-avif-pluginfor AVIF on older Pillow.
Ask Pillow what it supports
from PIL import Image, features
print(features.check("jpg")) # JPEG read/write compiled in?
print(features.check("webp"), features.check("webp_anim"))
print(features.check("libtiff"))
exts = Image.registered_extensions() # extension -> format name
print(exts[".webp"], exts[".tif"], len(exts))
print(sorted(Image.OPEN)) # readable formats
print(sorted(Image.SAVE)) # writable formats
Image.init() # force a rescan if plugins were imported lateReading this table before writing a conversion script saves a lot of guessing. A format can be readable but not writable, and the animation flag for WebP is separate from basic WebP support.
Plugin limits worth knowing
| Format | Typical limits |
|---|---|
| JPEG | Lossy, no alpha channel, 8-bit per channel |
| PNG | Lossless but large; 16-bit and palette modes supported |
| WebP | Both lossy and lossless, alpha and animation supported |
| GIF | 256 colours per frame, 1-bit transparency only |
| TIFF | Many variants; compression mode matters when reading |
| BMP | Uncompressed and large; no metadata to speak of |
| HEIC / AVIF | Needs an extra plugin; not in the base wheel |
💡
A missing codec fails at save time or at first access, not at import time. If
Image.open works but save("out.webp") raises KeyError or a plugin error, check features.check("webp") before rewriting your code.FAQ
Why does save fail with a KeyError for the format?
Pillow chooses the format from the file extension, and that extension is not in
Image.SAVE for your build. Pass an explicit format= argument, or install the plugin that adds the codec.Do I need to install PIL first?
No, and you should not. Pillow is the maintained fork and provides the same
PIL import name. Having both installed produces confusing import errors.Related
Opening, inspecting and saving images Debugging Pillow: mode errors, bombs and truncated files
Last refreshed 2026-09-18.