13.0.0 (unreleased)

Security

TODO

TODO

CVE YYYY-XXXXX: TODO

TODO

Backwards incompatible changes

Python 3.10

Pillow has dropped support for Python 3.10, which reached end-of-life in October 2026.

Saving I mode images as PNG

In order to fit the 32 bits of I mode images into PNG, when PNG images can only contain at most 16 bits for a channel, Pillow has been clipping the values. Rather than quietly changing the data, this is now removed. Instead, the image can be converted to another mode before saving:

from PIL import Image
im = Image.new("I", (1, 1))
im.convert("I;16").save("out.png")

Image.fromarray mode parameter

Using the mode parameter in fromarray() was deprecated in Pillow 11.3.0. In Pillow 12.0.0, this was partially reverted, and now the only functionality removed is when the mode changes data types. Since pixel values do not contain information about palettes or color spaces, the parameter can still be used to place grayscale L mode data within a P mode image, or read RGB data as YCbCr for example. If omitted, the mode will be automatically determined from the object’s shape and type.

Image.Image.get_child_images()

Image.Image.get_child_images() has been moved to ImageFile.ImageFile.get_child_images(). The method uses an image’s file pointer, and so child images could only be retrieved from an PIL.ImageFile.ImageFile instance.

Image._show

Image._show has been removed. Use show() instead.

ImageCms.ImageCmsProfile.product_name and .product_info

ImageCms.ImageCmsProfile.product_name and the corresponding .product_info attributes have been removed. They were set to None since Pillow 2.3.0.

ExifTags.IFD.Makernote

ExifTags.IFD.Makernote has been removed. Instead, use ExifTags.IFD.MakerNote.

Deprecations

IM image format

The IM image format has been deprecated and removal is planned in Pillow 15.0.0 (2028-10-15). If you are using this format and would like to continue doing so, open an issue about what other software uses it.

JpegImageFile.load_djpeg

JpegImageFile.load_djpeg has been deprecated, and will be removed in Pillow 14 (2027-10-15).

Use the built-in JPEG decoder instead, or call djpeg directly and decode the resulting image with Pillow.

ImageQt align8to32()

ImageQt.align8to32() has been deprecated. This was an undocumented helper function intended for internal use, so there is no replacement.

API changes

TODO

TODO

API additions

New resizing filters

Two new filters are available for resize() and thumbnail(): Image.Resampling.MKS2013 and Image.Resampling.MKS2021. These are versions of the Magic Kernel Sharp filter.

Added strip_namespaces argument to Image.getxmp()

getxmp() now accepts an optional keyword argument of strip_namespaces. It is set to True by default, stripping each tag’s XML namespace URI prefix as before. If set to False, each tag’s full {namespace-uri}local-name form is kept instead, avoiding collisions between tags that share a local name across different namespaces.

Added escape argument to PSDraw.text()

text() now accepts a keyword-only boolean argument, escape. Set it to True to escape backslashes, for example in Windows paths. The default, False, preserves the existing handling of backslashes and PostScript escape sequences.

Other changes

Python 3.15

Pillow 12.3.0 had wheels built against Python 3.15 beta, available as a preview to help projects prepare for 3.15, and to ensure Pillow could be used immediately at the release of 3.15.0 final (2026-10-01, PEP 790).

Pillow 13.0.0 now officially supports Python 3.15.

PyPy 3.12

Wheels are now also built for PyPy 3.12, in addition to PyPy 3.11.

Faster JPEG 2000, TIFF, FreeType and LittleCMS in macOS and Linux wheels

Several of the libraries bundled in the macOS and Linux wheels were built without compiler optimisation. The Windows wheels were not affected.

These libraries are now compiled with -O2. Compared to Pillow 12.3.0, the wheels

  • decode JPEG 2000 images 2 to 3 times faster and encode them about twice as fast,

  • read and write LZW-compressed TIFF images about twice as fast,

  • render text with ImageFont up to 3 times faster, and

  • apply ImageCms transforms up to 3 times faster.

PNG, JPEG, WebP and AVIF are unaffected, as those libraries were already built with optimisation.

Wheels now use HarfBuzz for hinting

FreeType can use HarfBuzz to work out which glyphs a script covers, so that its auto-hinter can derive hinting “Blue Zones” for scripts such as Arabic.

Only the Windows wheels were actually built with this support. The macOS wheels disabled HarfBuzz interoperability outright, and the Linux wheels left it up to FreeType’s configure, which in turn fell back to loading HarfBuzz by its unversioned name at runtime.

Since the bundled copy of HarfBuzz is renamed when the wheel is audited and repaired for distribution, that lookup only succeeded if a separate copy happened to be installed on the system with the expected name (e.g. libharfbuzz.so.0).

All wheels are now linked against the HarfBuzz that Pillow ships, which may slightly change how text is rendered in scripts that rely on the auto-hinter.

Preserved transparency when padding or expanding images in ImageOps

pad() and expand() now preserve the transparency value from the source image’s info dictionary. Transparent pixels in L, P and RGB images previously became opaque when a border was added. New palette colors are allocated without using reserved transparency entries.

Fixed ImageStat variance rounding

Fixed a floating-point rounding error that may have produced a negative variance in var.

Fixed ImageChops.offset() for 16-bit images

offset() now works correctly for 16-bit-per-channel images.

Fixed histograms for masked LA, La and PA images

When histogram() was given a mask for a two-band image (LA, La or PA), the second band was incorrectly derived from the first band of the input image, rather than the alpha band.

Fixed combining GIF frames with missing durations

Saving identical consecutive GIF frames no longer raises a KeyError when an earlier frame has no duration and a later frame does.

PNG palettes are no longer padded when saving with the bits argument

When saving a P mode image as a PNG with the bits argument, Pillow used to pad the PLTE chunk with zeroes up to 2 ** bits entries. The PLTE chunk now only contains as many entries as the image’s palette actually has, matching the behavior already used when bits is not specified.

Restore image position if ImageSequence.all_frames() fails

If processing a frame in all_frames() raises an exception, the given image will now seek back to its original frame.

Clean up TIFF encoders before closing their output files

TIFF saving now explicitly cleans up the libtiff encoder, including when saving raises an exception. Previously, delayed encoder destruction could access a closed file descriptor after it had been reused for another file, disturbing that file’s position or contents.

tobytes() also now explicitly cleans up its encoder on both success and failure, rather than relying on object destruction.

Fixed reading PSD layers at the wrong file offset

When seeking to a layer of a PSD image, the pixel data was read from the wrong position in the file, so seek() returned unrelated bytes reinterpreted as image data instead of that layer’s actual content.