NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #59 most downloaded on PyPI
Python Imaging Library (fork)
Last release 3 months ago
01 Jul 2026
Ships on a steady schedule
a new release about every 3 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
16 years old
107 releases · first in 2010
Add security release notes #9741 [ @radarhere ]
https://pillow.readthedocs.io/en/stable/releasenotes/12.3.0.html
tox -e lint instead of pytest #9670 [@hugovk]Image.filter() #9736 [@akx]Image.getchannel(), Image.merge(), Image.putalpha() and Image.split() #9675 [@akx]Image.fill(), Image.linear_gradient() and Image.radial_gradient(). #9737 [@akx]Image.resample() #9739 [@akx]alpha_composite, matrix, negative, quantize #9740 [@akx]Image.blend() #9649 [@akx]IFDRational.__float__() return value #9676 [@nyxst4ck]Note truncated.
One column per quarter.
When parsing a PDF, PdfStream.decode() attempts to decompress data without any limit. A default maximum of ImageFile.SAFEBLOCK has been added. PdfParser was added in Pillow 5.1.0. Reported by redyank.
If an attacker has control over the path passed to ImageShow.WindowsViewer.get_command(), and the result is executed by the user, the attacker may be able to execute arbitrary shell commands. Reported by Bin Luo, University of Electronic Science and Technology of China (luob87709@gmail.com).
If a negative byte count is specified for the BeginBinary byte count, an infinite loop is possible as Pillow seeks repeatedly backwards. This value will now be validated. BeginBinary parsing was only added in Pillow 12.0.0. Reported by jiagongzheng-stack.
The total component width was incorrectly accumulated across tiles within a JPEG2000 image, potentially leading to excessive memory use. This was introduced as part of an earlier security fix in Pillow 8.2.0, but has now been fixed. Reported by Fr3v1.
McIdas images can specify the stride, and if incorrectly set, may cause an OOB read. This has been fixed. Reported by Devansh Shah, RUDRA Cybersecurity Pvt. Ltd.
Saving 1 mode images as TGA with run-length encoding can trigger an OOB read. This was added in Pillow 5.2.0, but the functionality is not possible under the TGA specification, so it has been removed. Reported by Seratov.
~PIL.ImageFilter.RankFilter, and its subclasses, can potentially write out-of-bounds if given a large size. This has been fixed. Reported by Seratov.
Large paste box dimensions can cause an OOB write in Image.crop(), Image.paste() and Image.alpha_composite(). This has been fixed. Reported by Seratov.
Apply a transform mode to a different image mode can trigger an OOB write in ImageCmsTransform. Errors are now raised if the mode does not match. Reported by Seratov.
Decompression bomb checks have now been added to ~PIL.FontFile.FontFile, and its subclasses, checking the width and height of characters. Reported by Rahul Singh and Dinesh.
A decompression bomb check has been added to ~PIL.GdImageFile.GdImageFile. This is format must be explicitly called though, rather than being accessible from Image.open(). Reported by Rahul Singh.
~PIL.ImageGrab.grab now accepts an optional keyword argument of scale_down. This affects macOS screenshots with a bbox on a Retina screen. By default, images will be captured at 2x. If scale_down is True, they will be at 1x.
Previously, macOS screenshots with a bbox were captured at 1x by default.
When calling PdfStream.decode(), the maximum length of data to decode can now be specified. This will default to ImageFile.SAFEBLOCK.
To help other projects prepare for Python 3.15, wheels are now built for the 3.15 beta as a preview. This is not official support for Python 3.15, but rather an opportunity for you to test how Pillow works with the beta and report any problems.
Following 770, the Software Bill-of-Materials (SBOM) has now been embedded into Pillow's wheels.
Python 3.13 added an experimental free-threaded mode, and Pillow 11.0.0 added corresponding wheels. Now that Python 3.14 includes official support for it, Pillow has removed wheels for Python 3.13 free-threaded mode.
A number of changes have been made to optimize the use of C when manipulating images. This improves performance by up to 5.6 times of Image's alpha_composite, fill, filter, getchannel, linear_gradient, matrix, merge, negative, putalpha, quantize, radial_gradient, resample, split, and ImageChops operations.
https://pillow.readthedocs.io/en/stable/releasenotes/12.2.0.html
https://pillow.readthedocs.io/en/stable/releasenotes/12.2.0.html
macos-15-intel to macos-26-intel #9454 [@hugovk]_getxy refcount leaks #9487 [@hugovk]setimage() by always passing extents #9395 [@radarhere]self.decode typo #9445 [@bysiber]When decompressing GZIP data from a FITS image, Pillow did not limit the amount of data being read, meaning that it was vulnerable to GZIP decompression bombs. This was introduced in Pillow 10.3.0.
The data being read is now limited to only the necessary amount.
Pillow 12.1.1 addressed 2026-25990 by improving checks for tile extents to prevent an OOB write from specially crafted PSD images in Pillow >= 10.3.0. However, these checks did not consider integer overflow. This has been corrected.
When parsing a PDF, if a trailer refers to itself, or a more complex cyclic loop exists, then an infinite loop occurs. Pillow now keeps a record of which trailers it has already processed. PdfParser was added in Pillow 5.1.0.
If a font advances for each glyph by an exceedingly large amount, when Pillow keeps track of the current position, it may lead to an integer overflow. This has been fixed.
Passing nested lists as coordinates to APIs that accept coordinates such as ImagePath.Path, ~PIL.ImageDraw.ImageDraw.polygon and ~PIL.ImageDraw.ImageDraw.line could cause a heap buffer overflow, as nested lists were recursively unpacked beyond the allocated buffer. Coordinate lists are now validated to contain exactly two numeric coordinates. This was introduced in Pillow 11.2.1.
Attempting to encode an image with zero width or height would previously raise a SystemError. That has now been changed to a ValueError.
This does not add any new errors. SGI, ICNS and ICO formats are still able to save (0, 0) images.
~PIL.FontFile.FontFile instances can now be directly converted to ~PIL.ImageFont.ImageFont instances:
>>> from PIL import PcfFontFile
>>> with open("Tests/fonts/10x20-ISO8859-1.pcf", "rb") as fp:
... pcffont = PcfFontFile.PcfFontFile(fp)
... pcffont.to_imagefont()
...
<PIL.ImageFont.ImageFont object at 0x10457bb80>
.ImageText.Text.wrap has been added, to wrap text to fit within a given width:
from PIL import ImageText
text = ImageText.Text("Hello World!")
text.wrap(50)
print(text.text) # "Hello\nWorld!"
or within a certain width and height, returning a new .ImageText.Text instance if the text does not fit:
text = ImageText.Text("Text does not fit within height")
print(text.wrap(50, 25).text == " within height")
print(text.text) # "Text does\nnot fit"
or scaling, optionally with a font size limit:
text.wrap(50, 15, "shrink")
text.wrap(50, 15, ("shrink", 7))
text.wrap(58, 10, "grow")
text.wrap(50, 50, ("grow", 12))
The EXIF tag FrameRate has been added.
JPEG2000 images with CMYK palettes can now be read. This is the first integration of CMYK palettes into Pillow.
When opening or saving an image, Pillow now lazily loads only the required plugin based on the file extension, instead of importing all plugins upfront. This makes open 2.3-15.6x faster and save 2.2-9x faster for common formats.
Critical sections are now used to protect FreeType font objects, improving thread safety when using fonts in the free-threaded build of Python.
https://pillow.readthedocs.io/en/stable/releasenotes/12.1.1.html
https://pillow.readthedocs.io/en/stable/releasenotes/12.1.1.html
Check that tile extents do not use negative x or y offsets when decoding or encoding, and raise an error if they do, rather than allowing an OOB write.
An out-of-bounds write may be triggered when opening a specially crafted PSD image. This only affects Pillow >= 10.3.0. Reported by Yarden Porat.
A patch has been added to depends/install_libavif.sh, to allow libavif 1.3.0 to be compatible with the recently released svt-av1 4.0.0.
Deprecate getdata(), in favour of new get_flattened_data() #9292 [ @radarhere ]
https://pillow.readthedocs.io/en/stable/releasenotes/12.1.0.html
ResourceWarnings in selftest.py #9332 [@hugovk]~PIL.Image.Image.getdata has been deprecated. ~PIL.Image.Image.get_flattened_data can be used instead. This new method is identical, except that it returns a tuple of pixel values, instead of an internal Pillow data type.
To match the behaviour of ~PIL.ImageMorph.LutBuilder.build_lut, ~PIL.ImageMorph.LutBuilder.build_default_lut() now returns the new LUT.
~PIL.Image.Image.get_flattened_data is identical to the deprecated ~PIL.Image.Image.getdata, except that the new method returns a tuple of pixel values, instead of an internal Pillow data type.
When using ~PIL.ImageGrab.grab, a specific window can now be selected on macOS in addition to Windows. On macOS, this is a CGWindowID:
from PIL import ImageGrab ImageGrab.grab(window=cgwindowid)
~PIL.ImageMorph.MorphOp now supports both 1 mode and L mode images.
Remove deprecations for Pillow 12.0.0 #9053 [ @radarhere ]
https://pillow.readthedocs.io/en/stable/releasenotes/12.0.0.html
Note truncated.
Pillow has dropped support for Python 3.9, which reached end-of-life in October 2025.
ImageFile.raise_oserror() has been removed. The function was undocumented and was only useful for translating error codes returned by a codec's decode() method, which ImageFile already did automatically.
The functions IptcImageFile.dump and IptcImageFile.i, and the constant IptcImageFile.PAD have been removed. These were undocumented helper functions intended for internal use, so there is no replacement. They can each be replaced by a single line of code using builtin functions in Python.
A number of constants and a function in .ImageCms have been removed. This includes a table of flags based on LittleCMS version 1 which has been replaced with a new class .ImageCms.Flags based on LittleCMS 2 flags.
Deprecated |
Use instead |
|---|---|
ImageCms.DESCRIPTION |
No replacement |
ImageCms.VERSION |
PIL.__version__ |
ImageCms.FLAGS["MATRIXINPUT"] |
.ImageCms.Flags.CLUT_POST_LINEARIZATION |
ImageCms.FLAGS["MATRIXOUTPUT"] |
.ImageCms.Flags.FORCE_CLUT |
ImageCms.FLAGS["MATRIXONLY"] |
No replacement |
ImageCms.FLAGS["NOWHITEONWHITEFIXUP"] |
.ImageCms.Flags.NOWHITEONWHITEFIXUP |
ImageCms.FLAGS["NOPRELINEARIZATION"] |
.ImageCms.Flags.CLUT_PRE_LINEARIZATION |
ImageCms.FLAGS["GUESSDEVICECLASS"] |
.ImageCms.Flags.GUESSDEVICECLASS |
ImageCms.FLAGS["NOTCACHE"] |
.ImageCms.Flags.NOCACHE |
ImageCms.FLAGS["NOTPRECALC"] |
.ImageCms.Flags.NOOPTIMIZE |
ImageCms.FLAGS["NULLTRANSFORM"] |
.ImageCms.Flags.NULLTRANSFORM |
ImageCms.FLAGS["HIGHRESPRECALC"] |
.ImageCms.Flags.HIGHRESPRECALC |
ImageCms.FLAGS["LOWRESPRECALC"] |
.ImageCms.Flags.LOWRESPRECALC |
ImageCms.FLAGS["GAMUTCHECK"] |
.ImageCms.Flags.GAMUTCHECK |
ImageCms.FLAGS["WHITEBLACKCOMPENSATION"] |
.ImageCms.Flags.BLACKPOINTCOMPENSATION |
ImageCms.FLAGS["BLACKPOINTCOMPENSATION"] |
.ImageCms.Flags.BLACKPOINTCOMPENSATION |
ImageCms.FLAGS["SOFTPROOFING"] |
.ImageCms.Flags.SOFTPROOFING |
ImageCms.FLAGS["PRESERVEBLACK"] |
.ImageCms.Flags.NONEGATIVES |
ImageCms.FLAGS["NODEFAULTRESOURCEDEF"] |
.ImageCms.Flags.NODEFAULTRESOURCEDEF |
ImageCms.FLAGS["GRIDPOINTS"] |
.ImageCms.Flags.GRIDPOINTS() |
ImageCms.versions() |
PIL.features.version_module with feature="littlecms2", sys.version or sys.version_info, and PIL.__version__ |
ImageMath.eval() has been removed. Use ~PIL.ImageMath.lambda_eval or ~PIL.ImageMath.unsafe_eval instead.
The experimental BGR;15, BGR;16 and BGR;24 modes have been removed.
The use in .ImageCms of input modes and output modes that are not Pillow image modes has been removed. Defaulting to "L" or "1" if the mode cannot be mapped has also been removed.
Support for LibTIFF earlier than version 4 has been removed. Upgrade to a newer version of LibTIFF instead.
The hints parameter in ~PIL.ImageDraw.getdraw() has been removed.
Support for FreeType 2.9.0 has been removed. FreeType 2.9.1 is the minimum version supported.
We recommend upgrading to at least FreeType 2.10.4, which fixed a severe vulnerability introduced in FreeType 2.6 (2020-15999).
Image._show has been deprecated, and will be removed in Pillow 13 (2026-10-15). Use ~PIL.ImageShow.show instead.
ImageCms.ImageCmsProfile.product_name and the corresponding .product_info attributes have been deprecated, and will be removed in Pillow 13 (2026-10-15). They have been set to None since Pillow 2.3.0.
~PIL.Image.alpha_composite can now use LA images as well as RGBA.
PIL.ImageText.Text has been added, as a simpler way to use fonts with text strings or bytes.
Without ImageText.Text:
from PIL import Image, ImageDraw im = Image.new(mode, size) d = ImageDraw.Draw(im) d.textlength(text, font, direction, features, language, embedded_color) d.multiline_textbbox(xy, text, font, anchor, spacing, align, direction, features, language, stroke_width, embedded_color) d.text(xy, text, fill, font, anchor, spacing, align, direction, features, language, stroke_width, stroke_fill, embedded_color)
With ImageText.Text:
from PIL import ImageText text = ImageText.Text(text, font, mode, spacing, direction, features, language) text.embed_color() text.stroke(stroke_width, stroke_fill) text.get_length() text.get_bbox(xy, anchor, align) im = Image.new(mode, size) d = ImageDraw.Draw(im) d.text(xy, text, fill, anchor=anchor, align=align)
Pillow 11.3.0 had wheels built against Python 3.14 beta, available as a preview to help others prepare for 3.14, and to ensure Pillow could be used immediately at the release of 3.14.0 final (2025-10-07, 745).
Pillow 12.0.0 now officially supports Python 3.14.
In Pillow 11.3.0, the mode parameter in ~PIL.Image.fromarray() was deprecated. Part of this functionality has been restored in Pillow 12.0.0. Since pixel values do not contain information about palettes or color spaces, the parameter can be used to place grayscale L mode data within a P mode image, or read RGB data as YCbCr for example.
Valid ImageMorph operations are 4, N, 1 and M. By limiting the length to 1 character within Pillow, long execution times can be avoided if a user provided long pattern strings. Reported by Jang Choi.
Deprecate fromarray mode argument #9018 [ @radarhere ]
https://pillow.readthedocs.io/en/stable/releasenotes/11.3.0.html
Makefile #8933 [@hugovk]match parameter to pytest.warns() #9038 [@hugovk]make [-C docs] htmllive to rebuild and reload HTML files #8913 [@hugovk]There is a heap buffer overflow when writing a sufficiently large (>64k encoded with default settings) image in the DDS format due to writing into a buffer without checking for available space.
This only affects users who save untrusted data as a compressed DDS image.
Unclear how large the potential write could be. It is likely limited by process segfault, so it's not necessarily deterministic. It may be practically unbounded.
Unclear if there's a restriction on the bytes that could be emitted. It's likely that the only restriction is that the bytes would be emitted in chunks of 8 or 16.
This was introduced in Pillow 11.2.0 when the feature was added.
The mode parameter in ~PIL.Image.fromarray() has been deprecated. The mode can be automatically determined from the object's shape and type instead.
Note
Since pixel values do not contain information about palettes or color spaces, part of this functionality was restored in Pillow 12.0.0. The parameter can be used to place grayscale L mode data within a P mode image, or read RGB data as YCbCr for example.
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 deprecated. 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")
Support has been added for saving QOI images. colorspace can be used to specify the colorspace as sRGB with linear alpha, e.g. im.save("out.qoi", colorspace="sRGB"). By default, all channels will be linear.
~PIL.ImageGrab.grab is now able to use GNOME Screenshot, grim or Spectacle on Linux in order to take a snapshot of the screen.
Pillow only supports libavif 1.0.0 or later. In order to prevent errors when building from source, if a user happens to have an earlier libavif on their system, Pillow will now ignore it.
Support for reading and writing AVIF images is now included in Pillow's wheels, except for Windows ARM64 and iOS. libaom is available as an encoder and dav1d as a decoder. (Thank you Frankie Dintino and Andrew Murray!)
Pillow now provides wheels that can be used on iOS ARM64 devices, and on the iOS simulator on ARM64 and x86_64. Currently, only Python 3.13 wheels are available. (Thank you Russell Keith-Magee and Andrew Murray!)
To help other projects prepare for Python 3.14, wheels are now built for the 3.14 beta as a preview. This is not official support for Python 3.14, but rather an opportunity for you to test how Pillow works with the beta and report any problems.
Replace deprecated classifier with licence expression (PEP 639) #8850 [ @hugovk ]
https://pillow.readthedocs.io/en/stable/releasenotes/11.2.1.html
make clean or pip in tox #8754 [@hugovk]Note truncated.
Warning
The release of Pillow 11.2.0 was halted prematurely, due to hitting PyPI's project size limit and concern over the size of Pillow wheels containing libavif. The PyPI limit has now been increased and Pillow 11.2.1 has been released instead, without libavif included in the wheels. To avoid confusion, the incomplete 11.2.0 release has been removed from PyPI.
When loading some compressed DDS formats, an integer was bitshifted by 24 places to generate the 32 bits of the lookup table. This was undefined behaviour, and has been present since Pillow 3.4.0.
Image.Image.get_child_images() has been deprecated, and will be removed in Pillow 13 (2026-10-15). It will be 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.
Previously, save_all was required in order to use append_images. Now, save_all will default to True if append_images is not empty and the format supports saving multiple frames:
im.save("out.gif", append_images=ims)
In addition to "left", "center" and "right", multiline text can also be aligned using "justify" in ~PIL.ImageDraw:
from PIL import Image, ImageDraw
im = Image.new("RGB", (50, 25))
draw = ImageDraw.Draw(im)
draw.multiline_text((0, 0), "Multiline\ntext 1", align="justify")
draw.multiline_textbbox((0, 0), "Multiline\ntext 2", align="justify")
When using ~PIL.ImageGrab.grab, a specific window can be selected using the HWND:
from PIL import ImageGrab ImageGrab.grab(window=hwnd)
You can check if Pillow has been built against the MozJPEG version of the libjpeg library, and what version of MozJPEG is being used:
from PIL import features
features.check_feature("mozjpeg") # True or False
features.version_feature("mozjpeg") # "4.1.1" for example, or None
Compressed DDS images can now be saved using a pixel_format argument. DXT1, DXT3, DXT5, BC2, BC3 and BC5 are supported:
im.save("out.dds", pixel_format="DXT1")
Arrow is an in-memory data exchange format that is the spiritual successor to the NumPy array interface. It provides for zero-copy access to columnar data, which in our case is Image data.
To create an image with zero-copy shared memory from an object exporting the arrow_c_array interface protocol:
from PIL import Image import pyarrow as pa arr = pa.array([0]*(5*5*4), type=pa.uint8()) im = Image.fromarrow(arr, 'RGBA', (5, 5))
Pillow images can also be converted to Arrow objects:
from PIL import Image
import pyarrow as pa
im = Image.open('hopper.jpg')
arr = pa.array(im)
Pillow can now read and write AVIF images when built from source with libavif 1.0.0 or later.
Apply security fixes to GitHub Actions #8526 [ @hugovk ]
https://pillow.readthedocs.io/en/stable/releasenotes/11.1.0.html
gcov: true for codecov-action@v4 #8521 [@hugovk]ExifTags.IFD.Makernote has been deprecated. Instead, use ExifTags.IFD.MakerNote.
Pillow 11.0.0 added writing XMP data to JPEG and MPO images:
im.info["xmp"] = b"test"
im.save("out.jpg")
However, this meant that XMP data was automatically kept from an opened image, which is inconsistent with the rest of Pillow's behaviour. This functionality has been removed. To write XMP data, the xmp argument can still be used for JPEG files:
im.save("out.jpg", xmp=b"test")
To save XMP data to the second frame of an MPO image, encoderinfo can now be used:
second_im.encoderinfo = {"xmp": b"test"}
im.save("out.mpo", save_all=True, append_images=[second_im])
You can check if Pillow has been built against the zlib-ng version of the zlib library, and what version of zlib-ng is being used:
from PIL import features
features.check_feature("zlib_ng") # True or False
features.version_feature("zlib_ng") # "2.2.2" for example, or None
TIFF images can now be saved as BigTIFF using a big_tiff argument:
im.save("out.tiff", big_tiff=True)
When opening a JPEG 2000 image, the comment may now be read into ~PIL.Image.Image.info for J2K images, not just JP2 images.
With OpenJPEG 2.5.3 or later, Pillow can now save CMYK images as JPEG 2000 files.
C99 is now the minimum version of C required to compile Pillow from source.
Wheels are now built against zlib-ng for improved speed. In tests, saving a PNG was found to be more than twice as fast at higher compression levels.
Your coding agent can read these notes before it upgrades. Set up the MCP server →