Documentation Menu

Image File Formats

Independent practical guide. Canonical source: official Image file formats documentation.

Pillow reads and writes the common web and photo formats (JPEG, PNG, WebP, GIF, TIFF, AVIF) plus a long tail of older and specialist ones. Read and write support differ: some formats are read-only (PSD, for example) and PDF is write-only. Run python -m PIL --report to see exactly what your installation supports. For measured file sizes and conversion recipes, see converting between image formats.

FormatReadWriteNotes
JPEG / JPG✅✅Lossy. No alpha. Most common photo format.
PNG✅✅Lossless with alpha. Best for UI / screenshots.
GIF✅✅Animated. 256-colour palette only.
WebP✅✅Lossy/lossless, animated. Best web compression.
TIFF / TIF✅✅Multi-page, raw, high-quality. Used in print/medical.
BMP✅✅Uncompressed raster. Windows bitmap.
ICO✅✅Windows icon format with multiple sizes.
PDF❌✅Can write images as PDF pages. Read not supported.
EPS / PS✅ *✅Requires Ghostscript for reading.
SVG❌❌Vector format; Pillow cannot read it. Rasterise to PNG first (e.g. with CairoSVG), then open the PNG.
HEIC / HEIF✅ *✅ *Requires pillow-heif plugin package.
PPM / PBM / PGM✅✅Portable bitmap formats (Unix legacy).
TGA✅✅Targa format. Common in 3D/game pipelines.
PCX✅✅ZSoft PC Paintbrush.
SGI / RGB✅✅Silicon Graphics Image format.
DDS✅✅DirectDraw Surface — used in DirectX games.
AVIF✅✅Built into the official wheels since Pillow 11.3.0 (except Windows ARM64 and iOS). Older versions: pillow-avif-plugin.
XBM✅✅X11 bitmap format.
SPIDER✅✅SPIDER image format (data visualization).
IM✅✅LabEye IM format.

* = Requires optional dependency or plugin

JPEG

JPEG is the most common format for photographs. It uses lossy compression that significantly reduces file size but cannot store alpha transparency. The JPEG/JFIF format supports RGB, L, and CMYK modes.

JPEG Save Options
img.save("output.jpg", quality=85, # 1-95. 85 is good balance. 95 is near-lossless. progressive=True, # Progressive JPEG for web optimize=True, # Huffman table optimization subsampling=2, # Chroma subsampling: 0=4:4:4, 1=4:2:2, 2=4:2:0 dpi=(72, 72) # Set DPI metadata )
Warning: JPEG does not support transparency. If you try to save an RGBA image as JPEG, Pillow raises an OSError. Always convert("RGB") first.

PNG

PNG is a lossless format supporting transparency. It supports modes 1, L, P, RGB, and RGBA. PNG files contain a series of chunks — Pillow exposes most of these via the info dictionary.

PNG Save Options
img.save("output.png", compress_level=6, # 0 (no compression) to 9 (max). Default: 6 optimize=True, # Find optimal compression settings pnginfo=meta # Pass PngInfo object for metadata chunks ) # Add metadata chunks to PNG from PIL.PngImagePlugin import PngInfo meta = PngInfo() meta.add_text("Author", "Pillow Python") img.save("output.png", pnginfo=meta)

PNG DPI metadata

To embed print resolution in a PNG, pass dpi=(x, y) to save(). Pillow writes it to the pHYs chunk; read it back with img.info.get("dpi").

PNG DPI metadata
img.save("print.png", dpi=(300, 300))

GIF

GIF supports animation and transparency but is limited to 256 colours per frame. Pillow reads and writes GIF files, including animated ones.

Animated GIF Save
frames[0].save( "animation.gif", save_all=True, append_images=frames[1:], duration=80, # ms per frame loop=0, # 0 = loop forever disposal=2, # 2 = restore background between frames transparency=0 # transparent colour index in palette )

WebP (support & save options)

WebP provides both lossy and lossless compression with support for transparency and animation. It generally achieves 25-35% smaller files than JPEG at the same visual quality, making it the recommended format for modern web images.

WebP Save Options
img.save("output.webp", quality=85, # 0-100 for lossy lossless=False, # True = lossless mode method=6 # Compression method 0-6. 6=slowest/best ) # Animated WebP frames[0].save( "animation.webp", save_all=True, append_images=frames[1:], duration=80 )

TIFF

TIFF is a flexible raster format widely used in print, medical imaging, and GIS industries. Pillow supports multi-page TIFF reading, writing, and a variety of compression options.

TIFF Reading & Writing
from PIL import Image, ImageSequence # 1. Save Multi-page TIFF pages[0].save( "multipage.tiff", save_all=True, append_images=pages[1:], compression="tiff_lzw", dpi=(300, 300) ) # 2. Read & Extract all pages from multi-page TIFF multi_img = Image.open("multipage.tiff") for i, page in enumerate(ImageSequence.Iterator(multi_img)): page.save(f"page_{i+1}.png")

BMP

BMP is the native Windows bitmap format. It stores uncompressed image data and supports a wide range of pixel depths (1, 4, 8, 16, 24, 32 bit). Modes: 1, L, P, RGB. Writing is limited to these modes.

ICO (Windows Icon)

ICO files contain multiple image sizes in a single file. Pillow can read and write ICO files, embedding multiple sizes.

ICO Multi-size
img = Image.open("icon_256.png") img.save("favicon.ico", sizes=[(16,16),(32,32),(48,48),(256,256)])

PDF (Write natively, Read via pdf2image)

Pillow natively exports single-page or multi-page PDF documents. To convert PDF documents into Pillow Images for processing, use the standard pdf2image wrapper around Poppler.

PDF Export & Import
# 1. Native Pillow: Export images to multi-page PDF images[0].save( "document.pdf", save_all=True, append_images=images[1:], resolution=100.0 ) # 2. Read PDF pages into Pillow Images (pip install pdf2image) from pdf2image import convert_from_path pdf_pages = convert_from_path("document.pdf", dpi=300) for idx, page_img in enumerate(pdf_pages): page_img.save(f"pdf_page_{idx+1}.jpg", "JPEG")

EPS / PS (PostScript)

Pillow can write EPS format and can read it if Ghostscript is installed. Ghostscript must be on the system path for rasterization of EPS to work.

SVG (Read-Only via Plugins)

Pillow's core does not support SVG. To render SVG files with Pillow, use a third-party library such as cairosvg, svglib, or Wand (ImageMagick binding) to first convert the SVG to PNG, then open it in Pillow.

SVG → PNG via cairosvg
import cairosvg, io from PIL import Image png_bytes = cairosvg.svg2png(url="icon.svg", output_width=512) img = Image.open(io.BytesIO(png_bytes))

HEIC / HEIF (via plugin)

HEIC is Apple's default photo format since iOS 11. Pillow supports it through the pillow-heif plugin.

HEIC Support
$ pip install pillow-heif import pillow_heif from PIL import Image pillow_heif.register_heif_opener() # Register decoder globally img = Image.open("photo.heic") img.save("photo.jpg", quality=90)

Other Supported Formats

FormatExtensionNotes
PPM / PBM / PGM / PNM.ppm .pbm .pgm .pnmPortable Any Map. Simple uncompressed formats.
TGA / TARGA.tga .vda .icb .vstTarga image. No magic number — extension-based detection.
PCX.pcxZSoft PC Paintbrush. Modes: 1, L, P, RGB.
SGI.sgi .rgb .bwSilicon Graphics native format.
DDS.ddsDirectDraw Surface. Used in DirectX/OpenGL games.
IM.imLabEye IM format.
XBM.xbmX11 bitmap. Mode: 1 only.
XPM.xpmX11 colour pixmap. Read only.
FITS.fits .fit .ftsNASA Flexible Image Transport System. Scientific imagery.
JPEG 2000.jp2 .j2k .jpf .j2cWavelet compression JPEG successor. Modes: L, RGB, RGBA.
PSD.psdAdobe Photoshop. Read only, flattened.
DCX.dcxIntel FAX format (multipage PCX).
MSP.mspWindows 1.x/2.x Paint. Mode: 1 only.

Tested: what each format really supports

The tables in this section are printed by Pillow 12.3.0 itself, so they reflect the installed version rather than a list typed by hand.

How many formats Pillow handles

what_pillow_supports.py
from PIL import Image, features

Image.init()                                                  # load every format plugin
readable, writable = set(Image.OPEN), set(Image.SAVE)
print(len(readable), "formats can be opened,", len(writable), "can be saved")
print("save-only:", sorted(writable - readable))
print("open-only (sample):", sorted(readable - writable)[:12], "...")
print("HEIF/HEIC readable without a plugin:", "HEIF" in readable)
print("codecs:", {name: features.check(name) for name in ["jpg", "zlib", "webp", "avif", "jpg_2000", "libtiff"]})
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
43 formats can be opened, 30 can be saved
save-only: ['MPO', 'PALM', 'PDF']
open-only (sample): ['CUR', 'DCX', 'FITS', 'FLI', 'FTEX', 'GBR', 'IMT', 'IPTC', 'MCIDAS', 'MPEG', 'PCD', 'PIXAR'] ...
HEIF/HEIC readable without a plugin: False
codecs: {'jpg': True, 'zlib': True, 'webp': True, 'avif': True, 'jpg_2000': True, 'libtiff': True}

Pillow reads far more formats than it writes. PDF is save-only (use pdf2image or PyMuPDF to read PDFs). HEIC/HEIF is missing from both lists: it needs the pillow-heif plugin.

Size, transparency, animation and bit depth per format

format_matrix.py
import io
from PIL import Image

photo = Image.open("photo.jpg").resize((800, 534))
logo = Image.open("logo.png")                                # RGBA with transparent corners
frames = [photo, photo.transpose(Image.Transpose.FLIP_LEFT_RIGHT)]


def save(img, fmt, **kw):
    buf = io.BytesIO()
    img.save(buf, fmt, **kw)
    buf.seek(0)
    return buf


def check(fn):
    try:
        return fn()
    except Exception:
        return "-"


print(f"{'format':<9}{'photo KB':>9}  {'keeps alpha':<12}{'animation':<10}{'16-bit grey'}")
grey16 = photo.convert("I").point(lambda v: v * 257).convert("I;16")
for fmt in ["JPEG", "PNG", "WEBP", "AVIF", "GIF", "TIFF", "BMP", "JPEG2000", "TGA", "PPM"]:
    kb = check(lambda: f"{save(photo, fmt).getbuffer().nbytes / 1024:.0f}")
    alpha = check(lambda: "yes" if Image.open(save(logo, fmt)).convert("RGBA").getpixel((2, 2))[3] == 0 else "no")
    anim = check(lambda: "yes" if getattr(Image.open(save(frames[0], fmt, save_all=True, append_images=frames[1:])),
                                         "n_frames", 1) > 1 else "no")
    deep = check(lambda: "yes" if Image.open(save(grey16, fmt)).mode in ("I;16", "I", "I;16B") else "no")
    print(f"{fmt:<9}{kb:>9}  {alpha:<12}{anim:<10}{deep}")
Tested on ✓ Linux ✓ Windows ✓ macOS
Output
format    photo KB  keeps alpha animation 16-bit grey
JPEG            39  -           -         -
PNG            426  yes         yes       yes
WEBP            28  yes         yes       no
AVIF            34  yes         yes       no
GIF            152  yes         yes       no
TIFF          1252  yes         yes       yes
BMP           1252  no          -         -
JPEG2000       411  yes         -         yes
TGA           1252  yes         -         -
PPM           1252  no          -         yes

"-" means saving raised an error; "no" means the file saved, but the feature was lost when it was opened again. The photo sizes use each format's default settings, so they compare defaults rather than best-case compression; see reducing file size and converting formats for tuned settings. GIF keeps transparency as a single palette entry, so soft edges become hard, and it has at most 256 colours per frame. PNG's "yes" for animation is APNG, which browsers play but many image viewers show as a still. BMP writes 32-bit pixels including the alpha byte, but with a header that does not declare an alpha channel, so readers (Pillow included) open it as plain RGB: hence "no".