13.0.0¶
Security¶
CVE identifiers will be added to these entries as they are assigned.
Critical¶
CVE 2026-96639, GHSA-v9pv-5gc8-w2m6: Stale native image storage reused after mode transitions
GHSA-5x8w-8jj5-q52h, GHSA-8g5g-8vmr-9782: JPEG decoder buffer overflow from scanlines wider than tile extents
High¶
CVE 2026-96644, GHSA-9v9v-9qvf-h2hj: WMF/EMF heap out-of-bounds read from dimension truncation
CVE 2026-96637, GHSA-g842-9rc4-69pw: SPIDER decompression bomb bypass via seek()
CVE 2026-96643, GHSA-g4qv-2jxx-769h: Unbounded Exif header replacement loop
CVE 2026-96778, GHSA-g7cr-3p24-7wf7: JPEG comment write after ICC profile fills encoder buffer
GHSA-462x-pgg6-55fp, GHSA-c6hw-5grf-ff96: TIFF tile and YCbCr decoding out-of-bounds read from undersized libtiff buffers
GHSA-p4wg-p73j-c528: PDF parsing stack exhaustion from long trailer chains and deep or cyclic page trees
CVE 2026-96640, GHSA-mrfp-p49p-3hf2: PDF append resource exhaustion from repeated page tree references
GHSA-pchr-8j38-3x4p: TIFF encoder accepted an incorrectly sized Colormap for non-8-bit images
GHSA-332p-7hrc-92wf: TIFF encoder heap buffer overflow when saving to a file object
GHSA-xcvg-w56q-r89m: TIFF encoder heap buffer overflow when tags override the image size
GHSA-xvh5-g6gv-559v: TIFF encoder memory disclosure and crash from mismatched tag values
GHSA-q45j-58j2-45rg: TIFF decoding returned uninitialized memory for short JPEG strips
GHSA-78g4-xqwv-q3g8: Bundled OpenJPEG heap buffer overflow when reading tile-part data
Medium¶
GHSA-4rr5-89j8-mwwm: TIFF encoder use-after-free write
CVE 2026-96636, GHSA-p8hx-v2p6-rp84: MPO, DCX and MIC decompression bomb bypass via seek()
GHSA-f2g6-542v-9j58: PDF page tree stack exhaustion via cyclic
/KidsreferenceGHSA-5xm2-6676-qcp9: APNG decompression bomb bypass via delayed disposal-frame sizing
CVE 2026-96642, GHSA-3j72-p6qg-6xp7: TarIO negative size field causes infinite CPU-spin loop
CVE 2026-96638, GHSA-24rc-8hj2-v98c: BMP RLE decoder memory-amplification denial of service
GHSA-gg2r-wvfm-q9rx: MSP RLE decoder expands a tiny file into unbounded memory
GHSA-wqgw-9xfh-qf2g: TIFF and Exif IFD parsing memory and CPU amplification from shared tag data
GHSA-jg86-v3jv-hrpm: Quadratic time when writing many objects to a PDF
GHSA-254f-3936-288h: PdfParser unbounded recursion via deeply nested objects
GHSA-rfgq-q3w2-pmv2: Image.quantize() crash from an empty target palette
GHSA-xgh8-jp6q-p5x8: XBM header parsing regular expression denial of service
GHSA-22hg-r758-rrw9, GHSA-74r2-7ff9-mjj2, GHSA-fc9g-5qg7-mf45: GIF comment handling quadratic-time blowup from repeated concatenation
GHSA-27h8-gf7j-v5hc: Out-of-bounds read in rank-based filters for zero-dimension images
CVE 2026-96641, GHSA-4rm8-3hmm-39fg: Integer underflow in PILfont text width calculation
GHSA-cp9v-662q-vvx9: Image.merge() buffer overflow when merging 32-bit images as narrower bands
GHSA-j4m9-6w36-pw47: Uninitialized glyph pointer freed on font rendering error path
GHSA-7mwm-ghpf-9vrm: Double free in
Image.transform()after an allocation failureGHSA-4558-3h8r-v8xp:
P;2LandP;4Lraw mode decoders read past the end of their inputGHSA-w889-685w-c8fh: EPS filename argument injection into Ghostscript
Low¶
GHSA-65qm-jvmh-6pqg: GIF decompression bomb check used a size discarded on failure
GHSA-vx6w-vv9f-6gvg: EPS decompression bomb bypass via Ghostscript rendering
GHSA-58r4-6rv3-gfh8: ImageMorph.MorphOp.apply() out-of-bounds write on zero-width images
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.
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¶
ImageColor.getcolor() with premultiplied alpha modes¶
When mode is RGBa or La, getcolor() now returns
color values premultiplied by the alpha channel, matching how pixels are stored in
those modes. Previously, the unmultiplied values were returned.
Saving small ICO images¶
When saving an image smaller than 16x16 pixels as an ICO without a sizes
argument, the image’s own size is now used. Previously, none of the default sizes
matched, and an ICO containing no images was written. If no size in sizes fits
within the image, a ValueError is now raised.
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.
ImageOps invert, posterize and solarize of P images¶
invert(), posterize() and
solarize() now support P mode images. The operation is applied
to the palette colors, leaving any alpha values in the palette unchanged. Previously,
these functions raised NotImplementedError for P mode.
Path-like objects for font files¶
load(), load_path() and
save() now accept os.PathLike objects,
such as pathlib.Path, in addition to strings.
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.
Faster import¶
Importing Pillow takes around half the time it did in Pillow 12.3.0. PIL.Image no
longer imports logging, modules that are only needed for some operations, such as
tempfile, are now imported on first use, and on Python 3.15 Pillow also declares
__lazy_modules__ to defer its remaining standard library imports (PEP 810). On an
Apple Silicon Mac, from PIL import Image took 24 ms on Python 3.14 and 23 ms on
Python 3.15 with Pillow 12.3.0, and now takes 12 ms and 10 ms.
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
ImageFontup to 3 times faster, andapply
ImageCmstransforms up to 3 times faster.
PNG, JPEG, WebP and AVIF are unaffected, as those libraries were already built with optimisation.
Performance improvements¶
Building on the optimizations in Pillow 12.3.0, more of the C code has been
restructured so that compilers can vectorize it. Compared to Pillow 12.3.0,
offset() is up to 46 times faster,
getbbox() up to 24 times faster,
flipping and rotating by 180 degrees with
transpose() up to 10 times faster,
filter() up to 3.5 times faster,
difference() up to 3 times faster, and converting P and PA
images to RGB and RGBA up to 2.5 times faster. Saving an optimized GIF with a shared
palette is around 6 times faster and uses less memory.
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.
Thread safety for free-threaded Python¶
Critical sections now protect most operations on core image objects, such as conversion, pasting, filtering and pixel access, improving thread safety in the free-threaded build of Python. AVIF decoding also no longer blocks other threads.
Resizing images with alpha¶
The reducing_gap argument to resize() is now
applied to RGBA and LA images. Previously, these modes ignored the argument,
including when called by thumbnail(), which uses
reducing_gap=2.0 by default.
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 reading FITS images with more than 8 bits per pixel¶
FITS data is big-endian, but Pillow was reading 16-bit and 32-bit integer data, and 32-bit and 64-bit floating point data, in the native byte order. These images now load with the correct pixel values.
Fixed accuracy of 16-bit image filters and conversions¶
Applying a kernel filter to an I;16 image gave incorrect results for pixel values
above 255, and converting an I;16N image to I or F clipped values to 255.
Both now preserve the full 16-bit range.
Saving APNG frames with different palettes¶
An APNG file can only contain a single palette. When saving P mode frames with different palettes, the image is now saved as RGB, or RGBA if any palette contains alpha, instead of writing the later frames with the wrong colors.
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 drawing on I;16B images¶
When drawing on an I;16B image, some drawing methods wrote in the wrong byte order.
All drawing operations now use the byte order of the image mode.
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 exporting Arrow arrays from images with non-contiguous rows¶
Exporting an image as an Arrow array assumed that its rows were contiguous. However, this was not the case for
images whose rows were padded to an alignment returned incorrect data,
empty images,
images created by
frombuffer(), andimages memory-mapped from uncompressed files.
These images crashed instead.
Images with rows that are not contiguous now raise a ValueError, and the
others are exported correctly.
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.
Fixed opening XBM images with comments¶
XBM images with C-style /* ... */ comments in the header could not be identified.
Comments on separate lines before the bits declaration are now skipped.
Clarified FriBiDi shim license¶
The SBOM published with Pillow 12.3.0 listed the vendored FriBiDi shim
(src/thirdparty/fribidi-shim/) as LGPL-2.1-or-later. The shim was written for
Pillow and is covered by Pillow’s MIT-CMU license. Its header declares the parts of
FriBiDi’s public API needed to load FriBiDi at runtime, and contains no FriBiDi code.
FriBiDi itself is not included in Pillow’s wheels.
The shim’s source files now include SPDX license identifiers, and the SBOM has been corrected.
ImagePath.Path.compact() on an empty path¶
compact() is documented to return the number of
points removed. On a path with no points, it instead added a point whose
y coordinate was read from uninitialized memory, and returned -1.
compact() now leaves an empty path unchanged and returns 0.