This commit is contained in:
Andrew Murray 2025-04-04 19:10:22 +03:00 committed by GitHub
commit d2d305168c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 67 additions and 13 deletions

View File

@ -14,6 +14,7 @@ import pytest
from PIL import (
AvifImagePlugin,
GifImagePlugin,
Image,
ImageDraw,
ImageFile,
@ -240,6 +241,7 @@ class TestFileAvif:
with Image.open("Tests/images/chi.gif") as im:
im.save(temp_file)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 1
def test_invalid_file(self) -> None:
@ -596,10 +598,12 @@ class TestAvifAnimation:
"""
with Image.open(TEST_AVIF_FILE) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 1
assert not im.is_animated
with Image.open("Tests/images/avif/star.avifs") as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated
@ -610,11 +614,13 @@ class TestAvifAnimation:
"""
with Image.open("Tests/images/avif/star.gif") as original:
assert isinstance(original, GifImagePlugin.GifImageFile)
assert original.n_frames > 1
temp_file = tmp_path / "temp.avif"
original.save(temp_file, save_all=True)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == original.n_frames
# Compare first frame in P mode to frame from original GIF
@ -634,6 +640,7 @@ class TestAvifAnimation:
def check(temp_file: Path) -> None:
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 4
# Compare first frame to original
@ -706,6 +713,7 @@ class TestAvifAnimation:
)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated
@ -735,6 +743,7 @@ class TestAvifAnimation:
)
with Image.open(temp_file) as im:
assert isinstance(im, AvifImagePlugin.AvifImageFile)
assert im.n_frames == 5
assert im.is_animated

View File

@ -43,6 +43,7 @@ def test_sanity() -> None:
def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(ImageFile, "LOAD_TRUNCATED_IMAGES", True)
with Image.open(animated_test_file_with_prefix_chunk) as im:
assert isinstance(im, FliImagePlugin.FliImageFile)
assert im.mode == "P"
assert im.size == (320, 200)
assert im.format == "FLI"
@ -50,6 +51,7 @@ def test_prefix_chunk(monkeypatch: pytest.MonkeyPatch) -> None:
assert im.is_animated
palette = im.getpalette()
assert palette is not None
assert palette[3:6] == [255, 255, 255]
assert palette[381:384] == [204, 204, 12]
assert palette[765:] == [252, 0, 0]

View File

@ -280,6 +280,7 @@ def test_roundtrip_save_all(tmp_path: Path) -> None:
im.save(out, save_all=True)
with Image.open(out) as reread:
assert isinstance(reread, GifImagePlugin.GifImageFile)
assert reread.n_frames == 5
@ -1357,8 +1358,10 @@ def test_palette_save_all_P(tmp_path: Path) -> None:
with Image.open(out) as im:
# Assert that the frames are correct, and each frame has the same palette
assert isinstance(im, GifImagePlugin.GifImageFile)
assert_image_equal(im.convert("RGB"), frames[0].convert("RGB"))
assert im.palette is not None
assert im.global_palette is not None
assert im.palette.palette == im.global_palette.palette
im.seek(1)

View File

@ -334,8 +334,10 @@ class TestFileJpeg:
# Reading
with Image.open("Tests/images/exif_gps.jpg") as im:
exif = im._getexif()
assert exif[gps_index] == expected_exif_gps
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[gps_index] == expected_exif_gps
# Writing
f = tmp_path / "temp.jpg"
@ -344,8 +346,10 @@ class TestFileJpeg:
hopper().save(f, exif=exif)
with Image.open(f) as reloaded:
exif = reloaded._getexif()
assert exif[gps_index] == expected_exif_gps
assert isinstance(reloaded, JpegImagePlugin.JpegImageFile)
exif_data = reloaded._getexif()
assert exif_data is not None
assert exif_data[gps_index] == expected_exif_gps
def test_empty_exif_gps(self) -> None:
with Image.open("Tests/images/empty_gps_ifd.jpg") as im:
@ -372,6 +376,7 @@ class TestFileJpeg:
exifs = []
for i in range(2):
with Image.open("Tests/images/exif-200dpcm.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exifs.append(im._getexif())
assert exifs[0] == exifs[1]
@ -405,13 +410,17 @@ class TestFileJpeg:
}
with Image.open("Tests/images/exif_gps.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif = im._getexif()
assert exif is not None
for tag, value in expected_exif.items():
assert value == exif[tag]
def test_exif_gps_typeerror(self) -> None:
with Image.open("Tests/images/exif_gps_typeerror.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
# Should not raise a TypeError
im._getexif()
@ -491,7 +500,9 @@ class TestFileJpeg:
def test_exif(self) -> None:
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
info = im._getexif()
assert info is not None
assert info[305] == "Adobe Photoshop CS Macintosh"
def test_get_child_images(self) -> None:
@ -676,11 +687,13 @@ class TestFileJpeg:
def test_save_multiple_16bit_qtables(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
im2 = self.roundtrip(im, qtables="keep")
assert im.quantization == im2.quantization
def test_save_single_16bit_qtable(self) -> None:
with Image.open("Tests/images/hopper_16bit_qtables.jpg") as im:
assert isinstance(im, JpegImagePlugin.JpegImageFile)
im2 = self.roundtrip(im, qtables={0: im.quantization[0]})
assert len(im2.quantization) == 1
assert im2.quantization[0] == im.quantization[0]
@ -889,7 +902,10 @@ class TestFileJpeg:
# in contrast to normal 8
with Image.open("Tests/images/exif-ifd-offset.jpg") as im:
# Act / Assert
assert im._getexif()[306] == "2017:03:13 23:03:09"
assert isinstance(im, JpegImagePlugin.JpegImageFile)
exif = im._getexif()
assert exif is not None
assert exif[306] == "2017:03:13 23:03:09"
def test_multiple_exif(self) -> None:
with Image.open("Tests/images/multiple_exif.jpg") as im:

View File

@ -120,9 +120,11 @@ def test_ignore_frame_size() -> None:
# Ignore the different size of the second frame
# since this is not a "Large Thumbnail" image
with Image.open("Tests/images/ignore_frame_size.mpo") as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
assert im.size == (64, 64)
im.seek(1)
assert im.mpinfo is not None
assert (
im.mpinfo[0xB002][1]["Attribute"]["MPType"]
== "Multi-Frame Image: (Disparity)"
@ -155,7 +157,9 @@ def test_reload_exif_after_seek() -> None:
@pytest.mark.parametrize("test_file", test_files)
def test_mp(test_file: str) -> None:
with Image.open(test_file) as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
assert mpinfo[45056] == b"0100"
assert mpinfo[45057] == 2
@ -164,7 +168,9 @@ def test_mp_offset() -> None:
# This image has been manually hexedited to have an IFD offset of 10
# in APP2 data, in contrast to normal 8
with Image.open("Tests/images/sugarshack_ifd_offset.mpo") as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
assert mpinfo[45056] == b"0100"
assert mpinfo[45057] == 2
@ -180,7 +186,9 @@ def test_mp_no_data() -> None:
@pytest.mark.parametrize("test_file", test_files)
def test_mp_attribute(test_file: str) -> None:
with Image.open(test_file) as im:
assert isinstance(im, MpoImagePlugin.MpoImageFile)
mpinfo = im._getmp()
assert mpinfo is not None
for frame_number, mpentry in enumerate(mpinfo[0xB002]):
mpattr = mpentry["Attribute"]
if frame_number:

View File

@ -671,6 +671,9 @@ class TestFilePng:
im.save(out, bits=4, save_all=save_all)
with Image.open(out) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
assert reloaded.png is not None
assert reloaded.png.im_palette is not None
assert len(reloaded.png.im_palette[1]) == 48
def test_plte_length(self, tmp_path: Path) -> None:
@ -681,6 +684,9 @@ class TestFilePng:
im.save(out)
with Image.open(out) as reloaded:
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
assert reloaded.png is not None
assert reloaded.png.im_palette is not None
assert len(reloaded.png.im_palette[1]) == 3
def test_getxmp(self) -> None:
@ -702,13 +708,17 @@ class TestFilePng:
def test_exif(self) -> None:
# With an EXIF chunk
with Image.open("Tests/images/exif.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# With an ImageMagick zTXt chunk
with Image.open("Tests/images/exif_imagemagick.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# Assert that info still can be extracted
# when the image is no longer a PngImageFile instance
@ -717,8 +727,10 @@ class TestFilePng:
# With a tEXt chunk
with Image.open("Tests/images/exif_text.png") as im:
exif = im._getexif()
assert exif[274] == 1
assert isinstance(im, PngImagePlugin.PngImageFile)
exif_data = im._getexif()
assert exif_data is not None
assert exif_data[274] == 1
# With XMP tags
with Image.open("Tests/images/xmp_tags_orientation.png") as im:
@ -740,8 +752,10 @@ class TestFilePng:
im.save(test_file, exif=im.getexif())
with Image.open(test_file) as reloaded:
exif = reloaded._getexif()
assert exif[274] == 1
assert isinstance(reloaded, PngImagePlugin.PngImageFile)
exif_data = reloaded._getexif()
assert exif_data is not None
assert exif_data[274] == 1
@mark_if_feature_version(
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"

View File

@ -22,11 +22,13 @@ except ImportError:
def test_read_exif_metadata() -> None:
file_path = "Tests/images/flower.webp"
with Image.open(file_path) as image:
assert isinstance(image, WebPImagePlugin.WebPImageFile)
assert image.format == "WEBP"
exif_data = image.info.get("exif", None)
assert exif_data
exif = image._getexif()
assert exif is not None
# Camera make
assert exif[271] == "Canon"