diff --git a/Tests/test_file_avif.py b/Tests/test_file_avif.py index 38b4d5309..b71d975a9 100644 --- a/Tests/test_file_avif.py +++ b/Tests/test_file_avif.py @@ -94,7 +94,20 @@ class TestFileAvif: def test_version(self) -> None: version = features.version_module("avif") assert version is not None - assert re.search(r"\d+\.\d+\.\d+$", version) + assert re.search(r"^\d+\.\d+\.\d+$", version) + + def test_codec_version(self) -> None: + assert AvifImagePlugin.get_codec_version("unknown") is None + + for codec_name in ("aom", "dav1d", "rav1e", "svt"): + codec_version = AvifImagePlugin.get_codec_version(codec_name) + if _avif.decoder_codec_available( + codec_name + ) or _avif.encoder_codec_available(codec_name): + assert codec_version is not None + assert re.search(r"^v?\d+\.\d+\.\d+(-([a-z\d])+)*$", codec_version) + else: + assert codec_version is None def test_read(self) -> None: """ diff --git a/src/PIL/AvifImagePlugin.py b/src/PIL/AvifImagePlugin.py index 55116af3c..b2c5ab15d 100644 --- a/src/PIL/AvifImagePlugin.py +++ b/src/PIL/AvifImagePlugin.py @@ -20,6 +20,14 @@ DECODE_CODEC_CHOICE = "auto" DEFAULT_MAX_THREADS = 0 +def get_codec_version(codec_name: str) -> str | None: + versions = _avif.codec_versions() + for version in versions.split(", "): + if version.split(" [")[0] == codec_name: + return version.split(":")[-1].split(" ")[0] + return None + + def _accept(prefix: bytes) -> bool | str: if prefix[4:8] != b"ftyp": return False diff --git a/src/_avif.c b/src/_avif.c index 5c99ee52e..6fec85f02 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -182,6 +182,13 @@ _encoder_codec_available(PyObject *self, PyObject *args) { return PyBool_FromLong(is_available); } +PyObject * +_codec_versions(PyObject *self, PyObject *args) { + char buffer[256]; + avifCodecVersions(buffer); + return PyUnicode_FromString(buffer); +} + #if AVIF_VERSION >= 80200 // 0.8.2 static int _add_codec_specific_options(avifEncoder *encoder, PyObject *opts) { @@ -910,6 +917,7 @@ static PyMethodDef avifMethods[] = { {"AvifEncoder", AvifEncoderNew, METH_VARARGS}, {"decoder_codec_available", _decoder_codec_available, METH_VARARGS}, {"encoder_codec_available", _encoder_codec_available, METH_VARARGS}, + {"codec_versions", _codec_versions, METH_NOARGS}, {NULL, NULL} };