| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -251,6 +251,7 @@ | |||
| 251 | 251 | # https://www.sphinx-doc.org/en/master/usage/extensions/extlinks.html | |
| 252 | 252 | _repo = "https://github.com/python-pillow/Pillow/" | |
| 253 | 253 | extlinks = { | |
| 254 | + "ghsa": (_repo + "security/advisories/GHSA-%s", "GHSA-%s"), | ||
| 254 | 255 | "issue": (_repo + "issues/%s", "#%s"), | |
| 255 | 256 | "pr": (_repo + "pull/%s", "#%s"), | |
| 256 | 257 | "pypi": ("https://pypi.org/project/%s/", "%s"), | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -8,7 +8,7 @@ The :py:mod:`~PIL.ImagePath` module is used to store and manipulate 2-dimensiona | |||
| 8 | 8 | vector data. Path objects can be passed to the methods on the | |
| 9 | 9 | :py:mod:`~PIL.ImageDraw` module. | |
| 10 | 10 | ||
| 11 | - .. py:class:: PIL.ImagePath.Path | ||
| 11 | + .. py:class:: Path | ||
| 12 | 12 | ||
| 13 | 13 | A path object. The coordinate list can be any sequence object containing | |
| 14 | 14 | either 2-tuples [(x, y), …] or numeric values [x, y, …]. | |
@@ -27,7 +27,7 @@ vector data. Path objects can be passed to the methods on the | |||
| 27 | 27 | :param xy: A sequence. The sequence can contain 2-tuples [(x, y), ...] | |
| 28 | 28 | or a flat list of numbers [x, y, ...]. | |
| 29 | 29 | ||
| 30 | - .. py:method:: PIL.ImagePath.Path.compact(distance=2) | ||
| 30 | + .. py:method:: Path.compact(distance=2) | ||
| 31 | 31 | ||
| 32 | 32 | Compacts the path, by removing points that are close to each other. This | |
| 33 | 33 | method modifies the path in place, and returns the number of points left in | |
@@ -38,17 +38,17 @@ vector data. Path objects can be passed to the methods on the | |||
| 38 | 38 | ||
| 39 | 39 | .. _Manhattan distance: https://en.wikipedia.org/wiki/Manhattan_distance | |
| 40 | 40 | ||
| 41 | - .. py:method:: PIL.ImagePath.Path.getbbox() | ||
| 41 | + .. py:method:: Path.getbbox() | ||
| 42 | 42 | ||
| 43 | 43 | Gets the bounding box of the path. | |
| 44 | 44 | ||
| 45 | 45 | :return: ``(x0, y0, x1, y1)`` | |
| 46 | 46 | ||
| 47 | - .. py:method:: PIL.ImagePath.Path.map(function) | ||
| 47 | + .. py:method:: Path.map(function) | ||
| 48 | 48 | ||
| 49 | 49 | Maps the path through a function. | |
| 50 | 50 | ||
| 51 | - .. py:method:: PIL.ImagePath.Path.tolist(flat=False) | ||
| 51 | + .. py:method:: Path.tolist(flat=False) | ||
| 52 | 52 | ||
| 53 | 53 | Converts the path to a Python list [(x, y), …]. | |
| 54 | 54 | ||
@@ -57,7 +57,7 @@ vector data. Path objects can be passed to the methods on the | |||
| 57 | 57 | returns a flat list [x, y, ...] instead. | |
| 58 | 58 | :return: A list of coordinates. See ``flat``. | |
| 59 | 59 | ||
| 60 | - .. py:method:: PIL.ImagePath.Path.transform(matrix) | ||
| 60 | + .. py:method:: Path.transform(matrix) | ||
| 61 | 61 | ||
| 62 | 62 | Transforms the path in place, using an affine transform. The matrix is a | |
| 63 | 63 | 6-tuple (a, b, c, d, e, f), and each point is mapped as follows:: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,15 +4,61 @@ | |||
| 4 | 4 | Security | |
| 5 | 5 | ======== | |
| 6 | 6 | ||
| 7 | - TODO | ||
| 8 | - ^^^^ | ||
| 7 | + CVE identifiers will be added to these entries as they are assigned. | ||
| 9 | 8 | ||
| 10 | - TODO | ||
| 9 | + Critical | ||
| 10 | + ^^^^^^^^ | ||
| 11 | 11 | ||
| 12 | - :cve:`YYYY-XXXXX`: TODO | ||
| 13 | - ^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 12 | + * :cve:`2026-96639`, :ghsa:`v9pv-5gc8-w2m6`: Stale native image storage reused after mode transitions | ||
| 13 | + * :ghsa:`5x8w-8jj5-q52h`, :ghsa:`8g5g-8vmr-9782`: JPEG decoder buffer overflow from scanlines wider than tile extents | ||
| 14 | + | ||
| 15 | + High | ||
| 16 | + ^^^^ | ||
| 14 | 17 | ||
| 15 | - TODO | ||
| 18 | + * :cve:`2026-96644`, :ghsa:`9v9v-9qvf-h2hj`: WMF/EMF heap out-of-bounds read from dimension truncation | ||
| 19 | + * :cve:`2026-96637`, :ghsa:`g842-9rc4-69pw`: SPIDER decompression bomb bypass via seek() | ||
| 20 | + * :cve:`2026-96643`, :ghsa:`g4qv-2jxx-769h`: Unbounded Exif header replacement loop | ||
| 21 | + * :cve:`2026-96778`, :ghsa:`g7cr-3p24-7wf7`: JPEG comment write after ICC profile fills encoder buffer | ||
| 22 | + * :ghsa:`462x-pgg6-55fp`, :ghsa:`c6hw-5grf-ff96`: TIFF tile and YCbCr decoding out-of-bounds read from undersized libtiff buffers | ||
| 23 | + * :ghsa:`p4wg-p73j-c528`: PDF parsing stack exhaustion from long trailer chains and deep or cyclic page trees | ||
| 24 | + * :cve:`2026-96640`, :ghsa:`mrfp-p49p-3hf2`: PDF append resource exhaustion from repeated page tree references | ||
| 25 | + * :ghsa:`pchr-8j38-3x4p`: TIFF encoder accepted an incorrectly sized Colormap for non-8-bit images | ||
| 26 | + * :ghsa:`332p-7hrc-92wf`: TIFF encoder heap buffer overflow when saving to a file object | ||
| 27 | + * :ghsa:`xcvg-w56q-r89m`: TIFF encoder heap buffer overflow when tags override the image size | ||
| 28 | + * :ghsa:`xvh5-g6gv-559v`: TIFF encoder memory disclosure and crash from mismatched tag values | ||
| 29 | + * :ghsa:`q45j-58j2-45rg`: TIFF decoding returned uninitialized memory for short JPEG strips | ||
| 30 | + * :ghsa:`78g4-xqwv-q3g8`: Bundled OpenJPEG heap buffer overflow when reading tile-part data | ||
| 31 | + | ||
| 32 | + Medium | ||
| 33 | + ^^^^^^ | ||
| 34 | + | ||
| 35 | + * :ghsa:`4rr5-89j8-mwwm`: TIFF encoder use-after-free write | ||
| 36 | + * :cve:`2026-96636`, :ghsa:`p8hx-v2p6-rp84`: MPO, DCX and MIC decompression bomb bypass via seek() | ||
| 37 | + * :ghsa:`f2g6-542v-9j58`: PDF page tree stack exhaustion via cyclic ``/Kids`` reference | ||
| 38 | + * :ghsa:`5xm2-6676-qcp9`: APNG decompression bomb bypass via delayed disposal-frame sizing | ||
| 39 | + * :cve:`2026-96642`, :ghsa:`3j72-p6qg-6xp7`: TarIO negative size field causes infinite CPU-spin loop | ||
| 40 | + * :cve:`2026-96638`, :ghsa:`24rc-8hj2-v98c`: BMP RLE decoder memory-amplification denial of service | ||
| 41 | + * :ghsa:`gg2r-wvfm-q9rx`: MSP RLE decoder expands a tiny file into unbounded memory | ||
| 42 | + * :ghsa:`wqgw-9xfh-qf2g`: TIFF and Exif IFD parsing memory and CPU amplification from shared tag data | ||
| 43 | + * :ghsa:`jg86-v3jv-hrpm`: Quadratic time when writing many objects to a PDF | ||
| 44 | + * :ghsa:`254f-3936-288h`: PdfParser unbounded recursion via deeply nested objects | ||
| 45 | + * :ghsa:`rfgq-q3w2-pmv2`: Image.quantize() crash from an empty target palette | ||
| 46 | + * :ghsa:`xgh8-jp6q-p5x8`: XBM header parsing regular expression denial of service | ||
| 47 | + * :ghsa:`22hg-r758-rrw9`, :ghsa:`74r2-7ff9-mjj2`, :ghsa:`fc9g-5qg7-mf45`: GIF comment handling quadratic-time blowup from repeated concatenation | ||
| 48 | + * :ghsa:`27h8-gf7j-v5hc`: Out-of-bounds read in rank-based filters for zero-dimension images | ||
| 49 | + * :cve:`2026-96641`, :ghsa:`4rm8-3hmm-39fg`: Integer underflow in PILfont text width calculation | ||
| 50 | + * :ghsa:`cp9v-662q-vvx9`: Image.merge() buffer overflow when merging 32-bit images as narrower bands | ||
| 51 | + * :ghsa:`j4m9-6w36-pw47`: Uninitialized glyph pointer freed on font rendering error path | ||
| 52 | + * :ghsa:`7mwm-ghpf-9vrm`: Double free in ``Image.transform()`` after an allocation failure | ||
| 53 | + * :ghsa:`4558-3h8r-v8xp`: ``P;2L`` and ``P;4L`` raw mode decoders read past the end of their input | ||
| 54 | + * :ghsa:`w889-685w-c8fh`: EPS filename argument injection into Ghostscript | ||
| 55 | + | ||
| 56 | + Low | ||
| 57 | + ^^^ | ||
| 58 | + | ||
| 59 | + * :ghsa:`65qm-jvmh-6pqg`: GIF decompression bomb check used a size discarded on failure | ||
| 60 | + * :ghsa:`vx6w-vv9f-6gvg`: EPS decompression bomb bypass via Ghostscript rendering | ||
| 61 | + * :ghsa:`58r4-6rv3-gfh8`: ImageMorph.MorphOp.apply() out-of-bounds write on zero-width images | ||
| 16 | 62 | ||
| 17 | 63 | Backwards incompatible changes | |
| 18 | 64 | ============================== | |
@@ -99,10 +145,26 @@ intended for internal use, so there is no replacement. | |||
| 99 | 145 | API changes | |
| 100 | 146 | =========== | |
| 101 | 147 | ||
| 102 | - TODO | ||
| 103 | - ^^^^ | ||
| 148 | + ImageColor.getcolor() with premultiplied alpha modes | ||
| 149 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 150 | + | ||
| 151 | + When ``mode`` is ``RGBa`` or ``La``, :py:func:`~PIL.ImageColor.getcolor` now returns | ||
| 152 | + color values premultiplied by the alpha channel, matching how pixels are stored in | ||
| 153 | + those modes. Previously, the unmultiplied values were returned. | ||
| 154 | + | ||
| 155 | + Duplicate TIFF tags | ||
| 156 | + ^^^^^^^^^^^^^^^^^^^ | ||
| 157 | + | ||
| 158 | + If a TIFF IFD contains the same tag more than once, the first value is now kept. | ||
| 159 | + Previously, the last value overwrote the earlier ones. | ||
| 104 | 160 | ||
| 105 | - TODO | ||
| 161 | + Saving small ICO images | ||
| 162 | + ^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 163 | + | ||
| 164 | + When saving an image smaller than 16x16 pixels as an ICO without a ``sizes`` | ||
| 165 | + argument, the image's own size is now used. Previously, none of the default sizes | ||
| 166 | + matched, and an ICO containing no images was written. If no size in ``sizes`` fits | ||
| 167 | + within the image, a :py:exc:`ValueError` is now raised. | ||
| 106 | 168 | ||
| 107 | 169 | API additions | |
| 108 | 170 | ============= | |
@@ -131,6 +193,21 @@ Added ``escape`` argument to ``PSDraw.text()`` | |||
| 131 | 193 | The default, ``False``, preserves the existing handling of backslashes and PostScript | |
| 132 | 194 | escape sequences. | |
| 133 | 195 | ||
| 196 | + ImageOps invert, posterize and solarize of P images | ||
| 197 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 198 | + | ||
| 199 | + :py:func:`~PIL.ImageOps.invert`, :py:func:`~PIL.ImageOps.posterize` and | ||
| 200 | + :py:func:`~PIL.ImageOps.solarize` now support P mode images. The operation is applied | ||
| 201 | + to the palette colors, leaving any alpha values in the palette unchanged. Previously, | ||
| 202 | + these functions raised :py:exc:`NotImplementedError` for P mode. | ||
| 203 | + | ||
| 204 | + Path-like objects for font files | ||
| 205 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 206 | + | ||
| 207 | + :py:func:`~PIL.ImageFont.load`, :py:func:`~PIL.ImageFont.load_path` and | ||
| 208 | + :py:meth:`~PIL.FontFile.FontFile.save` now accept :py:class:`os.PathLike` objects, | ||
| 209 | + such as :py:class:`pathlib.Path`, in addition to strings. | ||
| 210 | + | ||
| 134 | 211 | Other changes | |
| 135 | 212 | ============= | |
| 136 | 213 | ||
@@ -143,6 +220,16 @@ immediately at the release of 3.15.0 final (2026-10-01, :pep:`790`). | |||
| 143 | 220 | ||
| 144 | 221 | Pillow 13.0.0 now officially supports Python 3.15. | |
| 145 | 222 | ||
| 223 | + Faster import | ||
| 224 | + ^^^^^^^^^^^^^ | ||
| 225 | + | ||
| 226 | + Importing Pillow takes around half the time it did in Pillow 12.3.0. ``PIL.Image`` no | ||
| 227 | + longer imports ``logging``, modules that are only needed for some operations, such as | ||
| 228 | + ``tempfile``, are now imported on first use, and on Python 3.15 Pillow also declares | ||
| 229 | + ``__lazy_modules__`` to defer its remaining standard library imports (:pep:`810`). On an | ||
| 230 | + Apple Silicon Mac, ``from PIL import Image`` took 24 ms on Python 3.14 and 23 ms on | ||
| 231 | + Python 3.15 with Pillow 12.3.0, and now takes 12 ms and 10 ms. | ||
| 232 | + | ||
| 146 | 233 | PyPy 3.12 | |
| 147 | 234 | ^^^^^^^^^ | |
| 148 | 235 | ||
@@ -164,6 +251,20 @@ These libraries are now compiled with ``-O2``. Compared to Pillow 12.3.0, the wh | |||
| 164 | 251 | PNG, JPEG, WebP and AVIF are unaffected, as those libraries were already built with | |
| 165 | 252 | optimisation. | |
| 166 | 253 | ||
| 254 | + Performance improvements | ||
| 255 | + ^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 256 | + | ||
| 257 | + Building on the optimizations in Pillow 12.3.0, more of the C code has been | ||
| 258 | + restructured so that compilers can vectorize it. Compared to Pillow 12.3.0, | ||
| 259 | + :py:func:`~PIL.ImageChops.offset` is up to 46 times faster, | ||
| 260 | + :py:meth:`~PIL.Image.Image.getbbox` up to 24 times faster, | ||
| 261 | + flipping and rotating by 180 degrees with | ||
| 262 | + :py:meth:`~PIL.Image.Image.transpose` up to 10 times faster, | ||
| 263 | + :py:meth:`~PIL.Image.Image.filter` up to 3.5 times faster, | ||
| 264 | + :py:func:`~PIL.ImageChops.difference` up to 3 times faster, and converting P and PA | ||
| 265 | + images to RGB and RGBA up to 2.5 times faster. Saving an optimized GIF with a shared | ||
| 266 | + palette is around 6 times faster and uses less memory. | ||
| 267 | + | ||
| 167 | 268 | Wheels now use HarfBuzz for hinting | |
| 168 | 269 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 169 | 270 | ||
@@ -183,6 +284,13 @@ installed on the system with the expected name (e.g. ``libharfbuzz.so.0``). | |||
| 183 | 284 | All wheels are now linked against the HarfBuzz that Pillow ships, | |
| 184 | 285 | which may slightly change how text is rendered in scripts that rely on the auto-hinter. | |
| 185 | 286 | ||
| 287 | + Thread safety for free-threaded Python | ||
| 288 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 289 | + | ||
| 290 | + Critical sections now protect most operations on core image objects, such as | ||
| 291 | + conversion, pasting, filtering and pixel access, improving thread safety in the | ||
| 292 | + free-threaded build of Python. AVIF decoding also no longer blocks other threads. | ||
| 293 | + | ||
| 186 | 294 | Resizing images with alpha | |
| 187 | 295 | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 188 | 296 | ||
@@ -199,6 +307,27 @@ Preserved transparency when padding or expanding images in ImageOps | |||
| 199 | 307 | pixels in L, P and RGB images previously became opaque when a border was added. | |
| 200 | 308 | New palette colors are allocated without using reserved transparency entries. | |
| 201 | 309 | ||
| 310 | + Fixed reading FITS images with more than 8 bits per pixel | ||
| 311 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 312 | + | ||
| 313 | + FITS data is big-endian, but Pillow was reading 16-bit and 32-bit integer data, and | ||
| 314 | + 32-bit and 64-bit floating point data, in the native byte order. These images now | ||
| 315 | + load with the correct pixel values. | ||
| 316 | + | ||
| 317 | + Fixed accuracy of 16-bit image filters and conversions | ||
| 318 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 319 | + | ||
| 320 | + Applying a kernel filter to an ``I;16`` image gave incorrect results for pixel values | ||
| 321 | + above 255, and converting an ``I;16N`` image to ``I`` or ``F`` clipped values to 255. | ||
| 322 | + Both now preserve the full 16-bit range. | ||
| 323 | + | ||
| 324 | + Saving APNG frames with different palettes | ||
| 325 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 326 | + | ||
| 327 | + An APNG file can only contain a single palette. When saving P mode frames with | ||
| 328 | + different palettes, the image is now saved as RGB, or RGBA if any palette contains | ||
| 329 | + alpha, instead of writing the later frames with the wrong colors. | ||
| 330 | + | ||
| 202 | 331 | Fixed ImageStat variance rounding | |
| 203 | 332 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 204 | 333 | ||
@@ -294,3 +423,11 @@ FriBiDi itself is not included in Pillow's wheels. | |||
| 294 | 423 | ||
| 295 | 424 | The shim's source files now include SPDX license identifiers, and the SBOM has been | |
| 296 | 425 | corrected. | |
| 426 | + | ||
| 427 | + ImagePath.Path.compact() on an empty path | ||
| 428 | + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 429 | + | ||
| 430 | + :py:meth:`~PIL.ImagePath.Path.compact` is documented to return the number of | ||
| 431 | + points removed. On a path with no points, it instead added a point whose | ||
| 432 | + y coordinate was read from uninitialized memory, and returned ``-1``. | ||
| 433 | + ``compact()`` now leaves an empty path unchanged and returns ``0``. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments