Simplified code (#3)

* Removed unnecessary meson install

* Use the same Python as the build script

* Use python3

* Simplified code

* Updated meson

---------

Co-authored-by: Andrew Murray <radarhere@users.noreply.github.com>
This commit is contained in:
Andrew Murray 2024-10-19 16:15:53 +11:00 committed by GitHub
parent 8b8bbba0f7
commit 58ef69228d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 65 additions and 106 deletions

View File

@ -86,8 +86,6 @@ jobs:
choco install nasm --no-progress choco install nasm --no-progress
echo "C:\Program Files\NASM" >> $env:GITHUB_PATH echo "C:\Program Files\NASM" >> $env:GITHUB_PATH
python -m pip install meson
choco install ghostscript --version=10.4.0 --no-progress choco install ghostscript --version=10.4.0 --no-progress
echo "C:\Program Files\gs\gs10.04.0\bin" >> $env:GITHUB_PATH echo "C:\Program Files\gs\gs10.04.0\bin" >> $env:GITHUB_PATH

View File

@ -102,7 +102,7 @@ EOF
function build_libavif { function build_libavif {
install_rav1e install_rav1e
python -m pip install meson ninja python3 -m pip install meson ninja
if [[ "$PLAT" == "x86_64" ]]; then if [[ "$PLAT" == "x86_64" ]]; then
build_simple nasm 2.16.03 https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/ build_simple nasm 2.16.03 https://www.nasm.us/pub/nasm/releasebuilds/2.16.03/

View File

@ -4,7 +4,6 @@ import gc
import os import os
import re import re
import warnings import warnings
import xml.etree.ElementTree
from collections.abc import Generator from collections.abc import Generator
from contextlib import contextmanager from contextlib import contextmanager
from io import BytesIO from io import BytesIO
@ -43,25 +42,13 @@ except ImportError:
TEST_AVIF_FILE = "Tests/images/avif/hopper.avif" TEST_AVIF_FILE = "Tests/images/avif/hopper.avif"
def assert_xmp_orientation(xmp: bytes | None, expected: int) -> None: def assert_xmp_orientation(xmp: bytes, expected: int) -> None:
assert isinstance(xmp, bytes) assert int(xmp.split(b'tiff:Orientation="')[1].split(b'"')[0]) == expected
root = xml.etree.ElementTree.fromstring(xmp)
orientation = None
for elem in root.iter():
if elem.tag.endswith("}Description"):
tag_orientation = elem.attrib.get(
"{http://ns.adobe.com/tiff/1.0/}Orientation"
)
if tag_orientation:
orientation = int(tag_orientation)
break
assert orientation == expected
def roundtrip(im: ImageFile.ImageFile, **options: Any) -> ImageFile.ImageFile: def roundtrip(im: ImageFile.ImageFile, **options: Any) -> ImageFile.ImageFile:
out = BytesIO() out = BytesIO()
im.save(out, "AVIF", **options) im.save(out, "AVIF", **options)
out.seek(0)
return Image.open(out) return Image.open(out)
@ -82,7 +69,7 @@ def skip_unless_avif_encoder(codec_name: str) -> pytest.MarkDecorator:
def is_docker_qemu() -> bool: def is_docker_qemu() -> bool:
try: try:
init_proc_exe = os.readlink("/proc/1/exe") init_proc_exe = os.readlink("/proc/1/exe")
except: # noqa: E722 except (FileNotFoundError, PermissionError):
return False return False
else: else:
return "qemu" in init_proc_exe return "qemu" in init_proc_exe
@ -125,18 +112,16 @@ class TestUnsupportedAvif:
def test_unsupported(self, monkeypatch: pytest.MonkeyPatch) -> None: def test_unsupported(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(AvifImagePlugin, "SUPPORTED", False) monkeypatch.setattr(AvifImagePlugin, "SUPPORTED", False)
file_path = "Tests/images/avif/hopper.avif" with pytest.warns(UserWarning):
pytest.warns( with pytest.raises(UnidentifiedImageError):
UserWarning, with Image.open(TEST_AVIF_FILE):
lambda: pytest.raises(UnidentifiedImageError, Image.open, file_path), pass
)
def test_unsupported_open(self, monkeypatch: pytest.MonkeyPatch) -> None: def test_unsupported_open(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(AvifImagePlugin, "SUPPORTED", False) monkeypatch.setattr(AvifImagePlugin, "SUPPORTED", False)
file_path = "Tests/images/avif/hopper.avif"
with pytest.raises(SyntaxError): with pytest.raises(SyntaxError):
AvifImagePlugin.AvifImageFile(file_path) AvifImagePlugin.AvifImageFile(TEST_AVIF_FILE)
@skip_unless_feature("avif") @skip_unless_feature("avif")
@ -154,12 +139,11 @@ class TestFileAvif:
Does it have the bits we expect? Does it have the bits we expect?
""" """
with Image.open("Tests/images/avif/hopper.avif") as image: with Image.open(TEST_AVIF_FILE) as image:
assert image.mode == "RGB" assert image.mode == "RGB"
assert image.size == (128, 128) assert image.size == (128, 128)
assert image.format == "AVIF" assert image.format == "AVIF"
assert image.get_format_mimetype() == "image/avif" assert image.get_format_mimetype() == "image/avif"
image.load()
image.getdata() image.getdata()
# generated with: # generated with:
@ -176,7 +160,6 @@ class TestFileAvif:
assert image.mode == "RGB" assert image.mode == "RGB"
assert image.size == (128, 128) assert image.size == (128, 128)
assert image.format == "AVIF" assert image.format == "AVIF"
image.load()
image.getdata() image.getdata()
if mode == "RGB": if mode == "RGB":
@ -240,10 +223,10 @@ class TestFileAvif:
im.save(test_file) im.save(test_file)
def test_no_resource_warning(self, tmp_path: Path) -> None: def test_no_resource_warning(self, tmp_path: Path) -> None:
with Image.open(TEST_AVIF_FILE) as image: with Image.open(TEST_AVIF_FILE) as im:
temp_file = str(tmp_path / "temp.avif") temp_file = str(tmp_path / "temp.avif")
with warnings.catch_warnings(): with warnings.catch_warnings():
image.save(temp_file) im.save(temp_file)
@pytest.mark.parametrize("major_brand", [b"avif", b"avis", b"mif1", b"msf1"]) @pytest.mark.parametrize("major_brand", [b"avif", b"avis", b"mif1", b"msf1"])
def test_accept_ftyp_brands(self, major_brand: bytes) -> None: def test_accept_ftyp_brands(self, major_brand: bytes) -> None:
@ -272,9 +255,7 @@ class TestFileAvif:
with Image.open(out_gif) as reread: with Image.open(out_gif) as reread:
reread_value = reread.convert("RGB").getpixel((1, 1)) reread_value = reread.convert("RGB").getpixel((1, 1))
difference = sum( difference = sum([abs(original_value[i] - reread_value[i]) for i in range(3)])
[abs(original_value[i] - reread_value[i]) for i in range(0, 3)]
)
assert difference < 5 assert difference < 5
def test_save_single_frame(self, tmp_path: Path) -> None: def test_save_single_frame(self, tmp_path: Path) -> None:
@ -296,7 +277,7 @@ class TestFileAvif:
assert_image(im, "RGBA", (64, 64)) assert_image(im, "RGBA", (64, 64))
# image has 876 transparent pixels # image has 876 transparent pixels
assert im.getchannel("A").getcolors()[0][0] == 876 assert im.getchannel("A").getcolors()[0] == (876, 0)
def test_save_transparent(self, tmp_path: Path) -> None: def test_save_transparent(self, tmp_path: Path) -> None:
im = Image.new("RGBA", (10, 10), (0, 0, 0, 0)) im = Image.new("RGBA", (10, 10), (0, 0, 0, 0))
@ -305,7 +286,7 @@ class TestFileAvif:
test_file = str(tmp_path / "temp.avif") test_file = str(tmp_path / "temp.avif")
im.save(test_file) im.save(test_file)
# check if saved image contains same transparency # check if saved image contains the same transparency
with Image.open(test_file) as im: with Image.open(test_file) as im:
assert_image(im, "RGBA", (10, 10)) assert_image(im, "RGBA", (10, 10))
assert im.getcolors() == [(100, (0, 0, 0, 0))] assert im.getcolors() == [(100, (0, 0, 0, 0))]
@ -346,7 +327,7 @@ class TestFileAvif:
exif = im.getexif() exif = im.getexif()
assert exif[274] == 1 assert exif[274] == 1
def test_exif_save(self, tmp_path: Path) -> None: def test_exif_save_default(self, tmp_path: Path) -> None:
with Image.open("Tests/images/avif/exif.avif") as im: with Image.open("Tests/images/avif/exif.avif") as im:
test_file = str(tmp_path / "temp.avif") test_file = str(tmp_path / "temp.avif")
im.save(test_file) im.save(test_file)
@ -355,24 +336,14 @@ class TestFileAvif:
exif = reloaded.getexif() exif = reloaded.getexif()
assert exif[274] == 1 assert exif[274] == 1
def test_exif_obj_argument(self, tmp_path: Path) -> None: @pytest.mark.parametrize("bytes", [True, False])
def test_exif_save_argument(self, tmp_path: Path, bytes: bool) -> None:
exif = Image.Exif() exif = Image.Exif()
exif[274] = 1 exif[274] = 1
exif_data = exif.tobytes() exif_data = exif.tobytes()
with Image.open(TEST_AVIF_FILE) as im: with Image.open(TEST_AVIF_FILE) as im:
test_file = str(tmp_path / "temp.avif") test_file = str(tmp_path / "temp.avif")
im.save(test_file, exif=exif) im.save(test_file, exif=exif_data if bytes else exif)
with Image.open(test_file) as reloaded:
assert reloaded.info["exif"] == exif_data
def test_exif_bytes_argument(self, tmp_path: Path) -> None:
exif = Image.Exif()
exif[274] = 1
exif_data = exif.tobytes()
with Image.open(TEST_AVIF_FILE) as im:
test_file = str(tmp_path / "temp.avif")
im.save(test_file, exif=exif_data)
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
assert reloaded.info["exif"] == exif_data assert reloaded.info["exif"] == exif_data
@ -385,7 +356,7 @@ class TestFileAvif:
def test_xmp(self) -> None: def test_xmp(self) -> None:
with Image.open("Tests/images/avif/xmp_tags_orientation.avif") as im: with Image.open("Tests/images/avif/xmp_tags_orientation.avif") as im:
xmp = im.info.get("xmp") xmp = im.info["xmp"]
assert_xmp_orientation(xmp, 3) assert_xmp_orientation(xmp, 3)
def test_xmp_save(self, tmp_path: Path) -> None: def test_xmp_save(self, tmp_path: Path) -> None:
@ -394,7 +365,7 @@ class TestFileAvif:
im.save(test_file) im.save(test_file)
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
xmp = reloaded.info.get("xmp") xmp = reloaded.info["xmp"]
assert_xmp_orientation(xmp, 3) assert_xmp_orientation(xmp, 3)
def test_xmp_save_from_png(self, tmp_path: Path) -> None: def test_xmp_save_from_png(self, tmp_path: Path) -> None:
@ -403,7 +374,7 @@ class TestFileAvif:
im.save(test_file) im.save(test_file)
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
xmp = reloaded.info.get("xmp") xmp = reloaded.info["xmp"]
assert_xmp_orientation(xmp, 3) assert_xmp_orientation(xmp, 3)
def test_xmp_save_argument(self, tmp_path: Path) -> None: def test_xmp_save_argument(self, tmp_path: Path) -> None:
@ -420,12 +391,12 @@ class TestFileAvif:
'<?xpacket end="r"?>', '<?xpacket end="r"?>',
] ]
) )
with Image.open("Tests/images/avif/hopper.avif") as im: with Image.open(TEST_AVIF_FILE) as im:
test_file = str(tmp_path / "temp.avif") test_file = str(tmp_path / "temp.avif")
im.save(test_file, xmp=xmp_arg) im.save(test_file, xmp=xmp_arg)
with Image.open(test_file) as reloaded: with Image.open(test_file) as reloaded:
xmp = reloaded.info.get("xmp") xmp = reloaded.info["xmp"]
assert_xmp_orientation(xmp, 1) assert_xmp_orientation(xmp, 1)
def test_tell(self) -> None: def test_tell(self) -> None:
@ -514,33 +485,29 @@ class TestFileAvif:
@skip_unless_avif_decoder("aom") @skip_unless_avif_decoder("aom")
@skip_unless_feature("avif") @skip_unless_feature("avif")
def test_decoder_codec_param(self) -> None: def test_decoder_codec_param(self, monkeypatch: pytest.MonkeyPatch) -> None:
AvifImagePlugin.DECODE_CODEC_CHOICE = "aom" monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "aom")
try:
with Image.open(TEST_AVIF_FILE) as im: with Image.open(TEST_AVIF_FILE) as im:
assert im.size == (128, 128) assert im.size == (128, 128)
finally:
AvifImagePlugin.DECODE_CODEC_CHOICE = "auto"
@skip_unless_avif_encoder("rav1e") @skip_unless_avif_encoder("rav1e")
@skip_unless_feature("avif") @skip_unless_feature("avif")
def test_decoder_codec_cannot_decode(self, tmp_path: Path) -> None: def test_decoder_codec_cannot_decode(
AvifImagePlugin.DECODE_CODEC_CHOICE = "rav1e" self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path
try: ) -> None:
with pytest.raises(ValueError): monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "rav1e")
with Image.open(TEST_AVIF_FILE):
pass with pytest.raises(ValueError):
finally: with Image.open(TEST_AVIF_FILE):
AvifImagePlugin.DECODE_CODEC_CHOICE = "auto" pass
def test_decoder_codec_invalid(self, monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(AvifImagePlugin, "DECODE_CODEC_CHOICE", "foo")
def test_decoder_codec_invalid(self) -> None:
AvifImagePlugin.DECODE_CODEC_CHOICE = "foo"
try:
with pytest.raises(ValueError): with pytest.raises(ValueError):
with Image.open(TEST_AVIF_FILE): with Image.open(TEST_AVIF_FILE):
pass pass
finally:
AvifImagePlugin.DECODE_CODEC_CHOICE = "auto"
@skip_unless_avif_encoder("aom") @skip_unless_avif_encoder("aom")
@skip_unless_feature("avif") @skip_unless_feature("avif")
@ -560,7 +527,7 @@ class TestFileAvif:
assert _avif.encoder_codec_available("foo") is False assert _avif.encoder_codec_available("foo") is False
def test_encoder_quality_valueerror(self, tmp_path: Path) -> None: def test_encoder_quality_valueerror(self, tmp_path: Path) -> None:
with Image.open("Tests/images/avif/hopper.avif") as im: with Image.open(TEST_AVIF_FILE) as im:
test_file = str(tmp_path / "temp.avif") test_file = str(tmp_path / "temp.avif")
with pytest.raises(ValueError): with pytest.raises(ValueError):
im.save(test_file, quality="invalid") im.save(test_file, quality="invalid")
@ -583,22 +550,20 @@ class TestFileAvif:
assert _avif.decoder_codec_available("foo") is False assert _avif.decoder_codec_available("foo") is False
@pytest.mark.parametrize("upsampling", ["fastest", "best", "nearest", "bilinear"]) @pytest.mark.parametrize("upsampling", ["fastest", "best", "nearest", "bilinear"])
def test_decoder_upsampling(self, upsampling: str) -> None: def test_decoder_upsampling(
AvifImagePlugin.CHROMA_UPSAMPLING = upsampling self, monkeypatch: pytest.MonkeyPatch, upsampling: str
try: ) -> None:
monkeypatch.setattr(AvifImagePlugin, "CHROMA_UPSAMPLING", upsampling)
with Image.open(TEST_AVIF_FILE): with Image.open(TEST_AVIF_FILE):
pass pass
finally:
AvifImagePlugin.CHROMA_UPSAMPLING = "auto"
def test_decoder_upsampling_invalid(self) -> None: def test_decoder_upsampling_invalid(self, monkeypatch: pytest.MonkeyPatch) -> None:
AvifImagePlugin.CHROMA_UPSAMPLING = "foo" monkeypatch.setattr(AvifImagePlugin, "CHROMA_UPSAMPLING", "foo")
try:
with pytest.raises(ValueError): with pytest.raises(ValueError):
with Image.open(TEST_AVIF_FILE): with Image.open(TEST_AVIF_FILE):
pass pass
finally:
AvifImagePlugin.CHROMA_UPSAMPLING = "auto"
def test_p_mode_transparency(self) -> None: def test_p_mode_transparency(self) -> None:
im = Image.new("P", size=(64, 64)) im = Image.new("P", size=(64, 64))
@ -612,7 +577,8 @@ class TestFileAvif:
buf_out = BytesIO() buf_out = BytesIO()
im_png.save(buf_out, format="AVIF", quality=100) im_png.save(buf_out, format="AVIF", quality=100)
assert_image_similar(im_png.convert("RGBA"), Image.open(buf_out), 1) with Image.open(buf_out) as expected:
assert_image_similar(im_png.convert("RGBA"), expected, 1)
def test_decoder_strict_flags(self) -> None: def test_decoder_strict_flags(self) -> None:
# This would fail if full avif strictFlags were enabled # This would fail if full avif strictFlags were enabled
@ -648,7 +614,7 @@ class TestAvifAnimation:
correctly. correctly.
""" """
with Image.open("Tests/images/avif/hopper.avif") as im: with Image.open(TEST_AVIF_FILE) as im:
assert im.n_frames == 1 assert im.n_frames == 1
assert not im.is_animated assert not im.is_animated
@ -671,13 +637,9 @@ class TestAvifAnimation:
assert im.n_frames == orig.n_frames assert im.n_frames == orig.n_frames
# Compare first and second-to-last frames to the original animated GIF # Compare first and second-to-last frames to the original animated GIF
orig.load()
im.load()
assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0) assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0)
orig.seek(orig.n_frames - 2) orig.seek(orig.n_frames - 2)
im.seek(im.n_frames - 2) im.seek(im.n_frames - 2)
orig.load()
im.load()
assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0) assert_image_similar(im.convert("RGB"), orig.convert("RGB"), 25.0)
def test_write_animation_RGB(self, tmp_path: Path) -> None: def test_write_animation_RGB(self, tmp_path: Path) -> None:
@ -691,12 +653,10 @@ class TestAvifAnimation:
assert im.n_frames == 4 assert im.n_frames == 4
# Compare first frame to original # Compare first frame to original
im.load()
assert_image_similar(im, frame1.convert("RGBA"), 25.0) assert_image_similar(im, frame1.convert("RGBA"), 25.0)
# Compare second frame to original # Compare second frame to original
im.seek(1) im.seek(1)
im.load()
assert_image_similar(im, frame2.convert("RGBA"), 25.0) assert_image_similar(im, frame2.convert("RGBA"), 25.0)
with self.star_frames() as frames: with self.star_frames() as frames:
@ -725,7 +685,7 @@ class TestAvifAnimation:
frame1 = Image.new("RGB", (100, 100)) frame1 = Image.new("RGB", (100, 100))
frame2 = Image.new("RGB", (150, 150)) frame2 = Image.new("RGB", (150, 150))
with pytest.raises(ValueError): with pytest.raises(ValueError):
frame1.save(temp_file, save_all=True, append_images=[frame2], duration=100) frame1.save(temp_file, save_all=True, append_images=[frame2])
def test_heif_raises_unidentified_image_error(self) -> None: def test_heif_raises_unidentified_image_error(self) -> None:
with pytest.raises(UnidentifiedImageError): with pytest.raises(UnidentifiedImageError):

View File

@ -72,7 +72,7 @@ class AvifImageFile(ImageFile.ImageFile):
self._size = width, height self._size = width, height
self.n_frames = n_frames self.n_frames = n_frames
self.is_animated = self.n_frames > 1 self.is_animated = self.n_frames > 1
self._mode = self.rawmode = mode self._mode = mode
if icc: if icc:
self.info["icc_profile"] = icc self.info["icc_profile"] = icc
@ -103,7 +103,7 @@ class AvifImageFile(ImageFile.ImageFile):
if self.fp and self._exclusive_fp: if self.fp and self._exclusive_fp:
self.fp.close() self.fp.close()
self.fp = BytesIO(data) self.fp = BytesIO(data)
self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.rawmode)] self.tile = [ImageFile._Tile("raw", (0, 0) + self.size, 0, self.mode)]
return super().load() return super().load()

View File

@ -7,6 +7,7 @@ import re
import shutil import shutil
import struct import struct
import subprocess import subprocess
import sys
from typing import Any from typing import Any
@ -121,7 +122,7 @@ V = {
"TIFF": "4.6.0", "TIFF": "4.6.0",
"XZ": "5.6.3", "XZ": "5.6.3",
"ZLIB": "1.3.1", "ZLIB": "1.3.1",
"MESON": "1.5.1", "MESON": "1.5.2",
"LIBAVIF": "1.1.1", "LIBAVIF": "1.1.1",
"RAV1E": "0.7.1", "RAV1E": "0.7.1",
} }
@ -838,7 +839,7 @@ def main() -> None:
"@echo " + ("=" * 70), "@echo " + ("=" * 70),
f"@echo ==== {'Building meson':<60} ====", f"@echo ==== {'Building meson':<60} ====",
"@echo " + ("=" * 70), "@echo " + ("=" * 70),
f"python -mpip install meson=={V['MESON']}", f"{sys.executable} -m pip install meson=={V['MESON']}",
], ],
prefs, prefs,
args.verbose, args.verbose,