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, libwebp and libfreetype for text. Missing headers silently drop a codec rather than failing the build.
  • Rare formats live in separate packages: pillow-heif for HEIC/AVIF, pillow-avif-plugin for 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 late

Reading 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

FormatTypical limits
JPEGLossy, no alpha channel, 8-bit per channel
PNGLossless but large; 16-bit and palette modes supported
WebPBoth lossy and lossless, alpha and animation supported
GIF256 colours per frame, 1-bit transparency only
TIFFMany variants; compression mode matters when reading
BMPUncompressed and large; no metadata to speak of
HEIC / AVIFNeeds 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.

Opening, inspecting and saving images Debugging Pillow: mode errors, bombs and truncated files

Last refreshed 2026-09-18.