All formats

Pillow

LanguagePython 3
LicenseMIT-CMU (permissive)
Repositorygithub.com/python-pillow/Pillow
Documentationpillow.readthedocs.io, PNG format notes
Depends onzlib, libjpeg and other codecs (bundled in the binary wheels)
Read / writeyes / yes, all color types (16-bit grayscale; 16-bit RGB is reduced to 8 bits), text chunks, APNG

Pillow is the maintained fork of PIL and the default image library for Python. It opens and saves PNG, JPEG, GIF, WebP, TIFF, BMP, ICO and many more formats, and has functions for resizing, cropping, rotating, drawing, filters and color conversion. Binary wheels for Windows, macOS and Linux include all codecs.

For PNG it reads and writes text chunks, pHYs (DPI), ICC profiles, Exif and transparency, and reads and writes APNG animations. One limitation: 16-bit-per-channel RGB and RGBA images are converted to 8 bits on load. Use pypng or OpenCV when you need full 16-bit color.

Installation#

Shell
pip install pillow

Basic usage: open, resize and save a PNG#

Python
from PIL import Image

with Image.open("in.png") as im:
    print(im.size, im.mode)  # (width, height), e.g. "RGBA", "RGB", "P", "L"
    im.thumbnail((800, 800), Image.Resampling.LANCZOS)  # fit inside 800x800, keeps aspect ratio
    im.save("out.png")

Image.open only reads the header; pixels are decoded on first access. The output format comes from the file extension.

How to get PNG width and height without decoding#

Python
from PIL import Image

with Image.open("in.png") as im:
    width, height = im.size
    print(width, height, im.mode, im.info.get("dpi"))

How to read and write PNG text chunks#

im.text returns tEXt, zTXt and iTXt chunks as a dict. To write them, pass a PngInfo object:

Python
from PIL import Image
from PIL.PngImagePlugin import PngInfo

with Image.open("in.png") as im:
    for key, value in im.text.items():
        print(f"{key}: {value}")

    meta = PngInfo()
    meta.add_text("Title", "Sunset")
    meta.add_text("Description", "long text is compressed", zip=True)  # zTXt
    meta.add_itxt("Author", "Zoë", lang="en")                          # UTF-8 iTXt
    im.save("out.png", pnginfo=meta)

How to make a PNG file smaller#

Python
from PIL import Image

with Image.open("in.png") as im:
    # lossless: best zlib settings (slower)
    im.save("optimized.png", optimize=True)

    # lossy: reduce to a 256-color palette, keeps transparency
    im.convert("RGBA").quantize(colors=256).save("palette.png", optimize=True)

How to convert PNG to JPEG#

JPEG can’t store transparency. Paste the image onto a white background:

Python
from PIL import Image

with Image.open("in.png") as im:
    im = im.convert("RGBA")
    bg = Image.new("RGB", im.size, (255, 255, 255))
    bg.paste(im, mask=im.getchannel("A"))
    bg.save("out.jpg", quality=85)

How to create an animated PNG (APNG)#

Python
from PIL import Image

frames = [Image.new("RGB", (100, 100), color) for color in ("red", "green", "blue")]
frames[0].save(
    "anim.png",
    save_all=True,
    append_images=frames[1:],
    duration=500,  # milliseconds per frame
    loop=0,        # 0 = forever
)

Read frames of an APNG with im.n_frames and im.seek(i), or PIL.ImageSequence.Iterator(im).

Tips#