Skip to content

Commit

Permalink
Merge branch 'main' into iptc
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Jan 1, 2024
2 parents 17911d6 + f2c6f11 commit 3ef7b93
Show file tree
Hide file tree
Showing 29 changed files with 289 additions and 119 deletions.
18 changes: 18 additions & 0 deletions .github/problem-matchers/gcc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"__comment": "Based on vscode-cpptools' Extension/package.json gcc rule",
"problemMatcher": [
{
"owner": "gcc-problem-matcher",
"pattern": [
{
"regexp": "^\\s*(.*):(\\d+):(\\d+):\\s+(?:fatal\\s+)?(warning|error):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
]
}
]
}
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ jobs:
env:
GHA_PYTHON_VERSION: ${{ matrix.python-version }}

- name: Register gcc problem matcher
if: "matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'"
run: echo "::add-matcher::.github/problem-matchers/gcc.json"

- name: Build
run: |
.ci/build.sh
Expand Down
27 changes: 27 additions & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,36 @@ Changelog (Pillow)
10.2.0 (unreleased)
-------------------

- Allow uncompressed TIFF images to be saved in chunks #7650
[radarhere]

- Concatenate multiple JPEG EXIF markers #7496
[radarhere]

- Changed IPTC tile tuple to match other plugins #7661
[radarhere]

- Do not assign new fp attribute when exiting context manager #7566
[radarhere]

- Support arbitrary masks for uncompressed RGB DDS images #7589
[radarhere, akx]

- Support setting ROWSPERSTRIP tag #7654
[radarhere]

- Apply ImageFont.MAX_STRING_LENGTH to ImageFont.getmask() #7662
[radarhere]

- Optimise ``ImageColor`` using ``functools.lru_cache`` #7657
[hugovk]

- Restricted environment keys for ImageMath.eval() #7655
[wiredfool, radarhere]

- Optimise ``ImageMode.getmode`` using ``functools.lru_cache`` #7641
[hugovk, radarhere]

- Fix incorrect color blending for overlapping glyphs #7497
[ZachNagengast, nulano, radarhere]

Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is

Pillow is the friendly PIL fork. It is

Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors.
Copyright © 2010-2024 by Jeffrey A. Clark (Alex) and contributors.

Like PIL, Pillow is licensed under the open source HPND License:

Expand Down
Binary file added Tests/images/bgr15.dds
Binary file not shown.
Binary file added Tests/images/bgr15.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tests/images/multiple_exif.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
Binary file removed Tests/images/unsupported_bitcount_rgb.dds
Binary file not shown.
13 changes: 4 additions & 9 deletions Tests/test_file_dds.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
TEST_FILE_UNCOMPRESSED_L = "Tests/images/uncompressed_l.dds"
TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA = "Tests/images/uncompressed_la.dds"
TEST_FILE_UNCOMPRESSED_RGB = "Tests/images/hopper.dds"
TEST_FILE_UNCOMPRESSED_BGR15 = "Tests/images/bgr15.dds"
TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA = "Tests/images/uncompressed_rgb.dds"


Expand Down Expand Up @@ -249,6 +250,7 @@ def test_dx10_r8g8b8a8_unorm_srgb():
("L", (128, 128), TEST_FILE_UNCOMPRESSED_L),
("LA", (128, 128), TEST_FILE_UNCOMPRESSED_L_WITH_ALPHA),
("RGB", (128, 128), TEST_FILE_UNCOMPRESSED_RGB),
("RGB", (128, 128), TEST_FILE_UNCOMPRESSED_BGR15),
("RGBA", (800, 600), TEST_FILE_UNCOMPRESSED_RGB_WITH_ALPHA),
],
)
Expand Down Expand Up @@ -341,16 +343,9 @@ def test_palette():
assert_image_equal_tofile(im, "Tests/images/transparent.gif")


@pytest.mark.parametrize(
"test_file",
(
"Tests/images/unsupported_bitcount_rgb.dds",
"Tests/images/unsupported_bitcount_luminance.dds",
),
)
def test_unsupported_bitcount(test_file):
def test_unsupported_bitcount():
with pytest.raises(OSError):
with Image.open(test_file):
with Image.open("Tests/images/unsupported_bitcount.dds"):
pass


Expand Down
20 changes: 12 additions & 8 deletions Tests/test_file_iptc.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,28 @@ def test_i():
c = b"a"

# Act
ret = IptcImagePlugin.i(c)
with pytest.warns(DeprecationWarning):
ret = IptcImagePlugin.i(c)

# Assert
assert ret == 97


def test_dump():
def test_dump(monkeypatch):
# Arrange
c = b"abc"
# Temporarily redirect stdout
old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()
mystdout = StringIO()
monkeypatch.setattr(sys, "stdout", mystdout)

# Act
IptcImagePlugin.dump(c)

# Reset stdout
sys.stdout = old_stdout
with pytest.warns(DeprecationWarning):
IptcImagePlugin.dump(c)

# Assert
assert mystdout.getvalue() == "61 62 63 \n"


def test_pad_deprecation():
with pytest.warns(DeprecationWarning):
assert IptcImagePlugin.PAD == b"\0\0\0\0"
4 changes: 4 additions & 0 deletions Tests/test_file_jpeg.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,6 +840,10 @@ def test_ifd_offset_exif(self):
# Act / Assert
assert im._getexif()[306] == "2017:03:13 23:03:09"

def test_multiple_exif(self):
with Image.open("Tests/images/multiple_exif.jpg") as im:
assert im.info["exif"] == b"Exif\x00\x00firstsecond"

@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
)
Expand Down
33 changes: 31 additions & 2 deletions Tests/test_file_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,13 +484,13 @@ def test_modify_exif(self, tmp_path):
outfile = str(tmp_path / "temp.tif")
with Image.open("Tests/images/ifd_tag_type.tiff") as im:
exif = im.getexif()
exif[256] = 100
exif[264] = 100

im.save(outfile, exif=exif)

with Image.open(outfile) as im:
exif = im.getexif()
assert exif[256] == 100
assert exif[264] == 100

def test_reload_exif_after_seek(self):
with Image.open("Tests/images/multipage.tiff") as im:
Expand Down Expand Up @@ -612,6 +612,14 @@ def test_roundtrip_tiff_uint16(self, tmp_path):

assert_image_equal_tofile(im, tmpfile)

def test_rowsperstrip(self, tmp_path):
outfile = str(tmp_path / "temp.tif")
im = hopper()
im.save(outfile, tiffinfo={278: 256})

with Image.open(outfile) as im:
assert im.tag_v2[278] == 256

def test_strip_raw(self):
infile = "Tests/images/tiff_strip_raw.tif"
with Image.open(infile) as im:
Expand Down Expand Up @@ -773,6 +781,27 @@ def test_get_photoshop_blocks(self):
4001,
]

def test_tiff_chunks(self, tmp_path):
tmpfile = str(tmp_path / "temp.tif")

im = hopper()
with open(tmpfile, "wb") as fp:
for y in range(0, 128, 32):
chunk = im.crop((0, y, 128, y + 32))
if y == 0:
chunk.save(
fp,
"TIFF",
tiffinfo={
TiffImagePlugin.IMAGEWIDTH: 128,
TiffImagePlugin.IMAGELENGTH: 128,
},
)
else:
fp.write(chunk.tobytes())

assert_image_equal_tofile(im, tmpfile)

def test_close_on_load_exclusive(self, tmp_path):
# similar to test_fd_leak, but runs on unixlike os
tmpfile = str(tmp_path / "temp.tif")
Expand Down
3 changes: 3 additions & 0 deletions Tests/test_file_tiff_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def test_write_metadata(tmp_path):
"""Test metadata writing through the python code"""
with Image.open("Tests/images/hopper.tif") as img:
f = str(tmp_path / "temp.tiff")
del img.tag[278]
img.save(f, tiffinfo=img.tag)

original = img.tag_v2.named()
Expand Down Expand Up @@ -159,9 +160,11 @@ def test_change_stripbytecounts_tag_type(tmp_path):
out = str(tmp_path / "temp.tiff")
with Image.open("Tests/images/hopper.tif") as im:
info = im.tag_v2
del info[278]

# Resize the image so that STRIPBYTECOUNTS will be larger than a SHORT
im = im.resize((500, 500))
info[TiffImagePlugin.IMAGEWIDTH] = im.width

# STRIPBYTECOUNTS can be a SHORT or a LONG
info.tagtype[TiffImagePlugin.STRIPBYTECOUNTS] = TiffTags.SHORT
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,11 @@ def test_fli_overrun2(self):
except OSError as e:
assert str(e) == "buffer overrun when reading image file"

def test_exit_fp(self):
with Image.new("L", (1, 1)) as im:
pass
assert not hasattr(im, "fp")

def test_close_graceful(self, caplog):
with Image.open("Tests/images/hopper.jpg") as im:
copy = im.copy()
Expand Down
2 changes: 2 additions & 0 deletions Tests/test_imagefont.py
Original file line number Diff line number Diff line change
Expand Up @@ -1058,6 +1058,8 @@ def test_too_many_characters(font):
imagefont.getlength("A" * 1_000_001)
with pytest.raises(ValueError):
imagefont.getbbox("A" * 1_000_001)
with pytest.raises(ValueError):
imagefont.getmask("A" * 1_000_001)


@pytest.mark.parametrize(
Expand Down
2 changes: 1 addition & 1 deletion docs/COPYING
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ The Python Imaging Library (PIL) is

Pillow is the friendly PIL fork. It is

Copyright © 2010-2023 by Jeffrey A. Clark (Alex) and contributors
Copyright © 2010-2024 by Jeffrey A. Clark (Alex) and contributors

Like PIL, Pillow is licensed under the open source PIL
Software License:
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
# General information about the project.
project = "Pillow (PIL Fork)"
copyright = (
"1995-2011 Fredrik Lundh, 2010-2023 Jeffrey A. Clark (Alex) and contributors"
"1995-2011 Fredrik Lundh, 2010-2024 Jeffrey A. Clark (Alex) and contributors"
)
author = "Fredrik Lundh, Jeffrey A. Clark (Alex), contributors"

Expand Down
11 changes: 11 additions & 0 deletions docs/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,17 @@ ImageFile.raise_oserror
error codes returned by a codec's ``decode()`` method, which ImageFile already does
automatically.

IptcImageFile helper functions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.. deprecated:: 10.2.0

The functions ``IptcImageFile.dump`` and ``IptcImageFile.i``, and the constant
``IptcImageFile.PAD`` have been deprecated and will be removed in Pillow
12.0.0 (2025-10-15). These are 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.

Removed features
----------------

Expand Down
25 changes: 20 additions & 5 deletions docs/releasenotes/10.2.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ ImageFile.raise_oserror
error codes returned by a codec's ``decode()`` method, which ImageFile already does
automatically.

TODO
^^^^
IptcImageFile helper functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

TODO
The functions ``IptcImageFile.dump`` and ``IptcImageFile.i``, and the constant
``IptcImageFile.PAD`` have been deprecated and will be removed in Pillow
12.0.0 (2025-10-15). These are 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.

API Changes
===========
Expand Down Expand Up @@ -62,8 +66,19 @@ output only the quantization and Huffman tables for the image.
Security
========

Restricted environment keys for ImageMath.eval
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ImageFont.getmask: Applied ImageFont.MAX_STRING_LENGTH
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

To protect against potential DOS attacks when using arbitrary strings as text input,
Pillow will now raise a :py:exc:`ValueError` if the number of characters passed into
:py:meth:`PIL.ImageFont.ImageFont.getmask` is over a certain limit,
:py:data:`PIL.ImageFont.MAX_STRING_LENGTH`.

This threshold can be changed by setting :py:data:`PIL.ImageFont.MAX_STRING_LENGTH`. It
can be disabled by setting ``ImageFont.MAX_STRING_LENGTH = None``.

ImageMath.eval: Restricted environment keys
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

:cve:`2023-50447`: If an attacker has control over the keys passed to the
``environment`` argument of :py:meth:`PIL.ImageMath.eval`, they may be able to execute
Expand Down

0 comments on commit 3ef7b93

Please sign in to comment.