diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 609352f22..d019d3e7f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,8 @@ repos: rev: 6.0.0 hooks: - id: flake8 - additional_dependencies: [flake8-2020, flake8-implicit-str-concat] + additional_dependencies: + [flake8-2020, flake8-errmsg, flake8-implicit-str-concat] - repo: https://github.com/pre-commit/pygrep-hooks rev: v1.9.0 diff --git a/CHANGES.rst b/CHANGES.rst index 76fc230a8..904c73629 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,30 @@ Changelog (Pillow) 9.4.0 (unreleased) ------------------ +- Improve exception traceback readability #6836 + [hugovk, radarhere] + +- Do not attempt to read IFD1 if absent #6840 + [radarhere] + +- Fixed writing int as ASCII tag #6800 + [radarhere] + +- If available, use wl-paste or xclip for grabclipboard() on Linux #6783 + [radarhere] + +- Added signed option when saving JPEG2000 images #6709 + [radarhere] + +- Patch OpenJPEG to include ARM64 fix #6718 + [radarhere] + +- Added support for I;16 modes in putdata() #6825 + [radarhere] + +- Added conversion from RGBa to RGB #6708 + [radarhere] + - Added DDS support for uncompressed L and LA images #6820 [radarhere, REDxEYE] diff --git a/Tests/test_file_jpeg2k.py b/Tests/test_file_jpeg2k.py index cd142e67f..0229b2243 100644 --- a/Tests/test_file_jpeg2k.py +++ b/Tests/test_file_jpeg2k.py @@ -252,6 +252,20 @@ def test_mct(): assert_image_similar(im, jp2, 1.0e-3) +def test_sgnd(tmp_path): + outfile = str(tmp_path / "temp.jp2") + + im = Image.new("L", (1, 1)) + im.save(outfile) + with Image.open(outfile) as reloaded: + assert reloaded.getpixel((0, 0)) == 0 + + im = Image.new("L", (1, 1)) + im.save(outfile, signed=True) + with Image.open(outfile) as reloaded_signed: + assert reloaded_signed.getpixel((0, 0)) == 128 + + def test_rgba(): # Arrange with Image.open("Tests/images/rgb_trns_ycbc.j2k") as j2k: diff --git a/Tests/test_file_tiff_metadata.py b/Tests/test_file_tiff_metadata.py index b90dde3d9..48797ea08 100644 --- a/Tests/test_file_tiff_metadata.py +++ b/Tests/test_file_tiff_metadata.py @@ -185,20 +185,21 @@ def test_iptc(tmp_path): im.save(out) -def test_writing_bytes_to_ascii(tmp_path): - im = hopper() +@pytest.mark.parametrize("value, expected", ((b"test", "test"), (1, "1"))) +def test_writing_other_types_to_ascii(value, expected, tmp_path): info = TiffImagePlugin.ImageFileDirectory_v2() tag = TiffTags.TAGS_V2[271] assert tag.type == TiffTags.ASCII - info[271] = b"test" + info[271] = value + im = hopper() out = str(tmp_path / "temp.tiff") im.save(out, tiffinfo=info) with Image.open(out) as reloaded: - assert reloaded.tag_v2[271] == "test" + assert reloaded.tag_v2[271] == expected def test_writing_int_to_bytes(tmp_path): diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index 902d8bf8f..0a7202a33 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -104,6 +104,13 @@ def test_rgba_p(): assert_image_similar(im, comparable, 20) +def test_rgba(): + with Image.open("Tests/images/transparent.png") as im: + assert im.mode == "RGBA" + + assert_image_similar(im.convert("RGBa").convert("RGB"), im.convert("RGB"), 1.5) + + def test_trns_p(tmp_path): im = hopper("P") im.info["transparency"] = 0 diff --git a/Tests/test_image_putdata.py b/Tests/test_image_putdata.py index 3d60e52a2..0e6293349 100644 --- a/Tests/test_image_putdata.py +++ b/Tests/test_image_putdata.py @@ -55,10 +55,11 @@ def test_mode_with_L_with_float(): assert im.getpixel((0, 0)) == 2 -def test_mode_i(): +@pytest.mark.parametrize("mode", ("I", "I;16", "I;16L", "I;16B")) +def test_mode_i(mode): src = hopper("L") data = list(src.getdata()) - im = Image.new("I", src.size, 0) + im = Image.new(mode, src.size, 0) im.putdata(data, 2, 256) target = [2 * elt + 256 for elt in data] diff --git a/Tests/test_imagegrab.py b/Tests/test_imagegrab.py index 5e0eca28b..317db4c01 100644 --- a/Tests/test_imagegrab.py +++ b/Tests/test_imagegrab.py @@ -64,9 +64,13 @@ $bmp = New-Object Drawing.Bitmap 200, 200 ) p.communicate() else: - with pytest.raises(NotImplementedError) as e: - ImageGrab.grabclipboard() - assert str(e.value) == "ImageGrab.grabclipboard() is macOS and Windows only" + if not shutil.which("wl-paste"): + with pytest.raises( + NotImplementedError, + match="wl-paste or xclip is required for" + r" ImageGrab.grabclipboard\(\) on Linux", + ): + ImageGrab.grabclipboard() return ImageGrab.grabclipboard() diff --git a/docs/example/DdsImagePlugin.py b/docs/example/DdsImagePlugin.py index ec3938b36..26451533e 100644 --- a/docs/example/DdsImagePlugin.py +++ b/docs/example/DdsImagePlugin.py @@ -211,13 +211,16 @@ class DdsImageFile(ImageFile.ImageFile): def _open(self): if not _accept(self.fp.read(4)): - raise SyntaxError("not a DDS file") + msg = "not a DDS file" + raise SyntaxError(msg) (header_size,) = struct.unpack("