Improved error handling

This commit is contained in:
Andrew Murray 2024-12-03 10:31:57 +11:00
parent 3730bf214b
commit c40bcbfc87
9 changed files with 155 additions and 116 deletions

View File

@ -23,8 +23,7 @@ if [[ $(uname) != CYGWIN* ]]; then
sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\ sudo apt-get -qq install libfreetype6-dev liblcms2-dev python3-tk\
ghostscript libjpeg-turbo-progs libopenjp2-7-dev\ ghostscript libjpeg-turbo-progs libopenjp2-7-dev\
cmake meson imagemagick libharfbuzz-dev libfribidi-dev\ cmake meson imagemagick libharfbuzz-dev libfribidi-dev\
sway wl-clipboard libopenblas-dev\ sway wl-clipboard libopenblas-dev nasm
ninja-build build-essential nasm
fi fi
python3 -m pip install --upgrade pip python3 -m pip install --upgrade pip

View File

@ -114,7 +114,7 @@ function install_rav1e {
curl -sLo - \ curl -sLo - \
https://github.com/xiph/rav1e/releases/download/v$RAV1E_VERSION/librav1e-$RAV1E_VERSION-$suffix.tar.gz \ https://github.com/xiph/rav1e/releases/download/v$RAV1E_VERSION/librav1e-$RAV1E_VERSION-$suffix.tar.gz \
| tar -C $BUILD_PREFIX --exclude LICENSE --exclude LICENSE --exclude '*.so' --exclude '*.dylib' -zxf - | tar -C $BUILD_PREFIX --exclude LICENSE --exclude '*.so' --exclude '*.dylib' -zxf -
if [ -z "$IS_MACOS" ]; then if [ -z "$IS_MACOS" ]; then
sed -i 's/-lgcc_s/-lgcc_eh/g' "${BUILD_PREFIX}/lib/pkgconfig/rav1e.pc" sed -i 's/-lgcc_s/-lgcc_eh/g' "${BUILD_PREFIX}/lib/pkgconfig/rav1e.pc"
@ -133,6 +133,7 @@ EOF
} }
function build_libavif { function build_libavif {
if [ -e libavif-stamp ]; then return; fi
install_rav1e install_rav1e
python3 -m pip install meson ninja python3 -m pip install meson ninja
@ -140,13 +141,11 @@ function build_libavif {
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/
fi fi
local cmake=$(get_modern_cmake)
local out_dir=$(fetch_unpack https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$LIBAVIF_VERSION.tar.gz libavif-$LIBAVIF_VERSION.tar.gz) local out_dir=$(fetch_unpack https://github.com/AOMediaCodec/libavif/archive/refs/tags/v$LIBAVIF_VERSION.tar.gz libavif-$LIBAVIF_VERSION.tar.gz)
(cd $out_dir \ (cd $out_dir \
&& $cmake \ && cmake \
-DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX \ -DCMAKE_INSTALL_PREFIX=$BUILD_PREFIX \
-DCMAKE_INSTALL_NAME_DIR=$BUILD_PREFIX/lib \ -DCMAKE_INSTALL_LIBDIR=$BUILD_PREFIX/lib \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=OFF \ -DBUILD_SHARED_LIBS=OFF \
-DAVIF_LIBSHARPYUV=LOCAL \ -DAVIF_LIBSHARPYUV=LOCAL \
@ -159,11 +158,7 @@ function build_libavif {
-DCMAKE_MODULE_PATH=/tmp/cmake/Modules \ -DCMAKE_MODULE_PATH=/tmp/cmake/Modules \
. \ . \
&& make install) && make install)
touch libavif-stamp
if [[ "$MB_ML_LIBC" == "manylinux" ]]; then
cp /usr/local/lib64/libavif.a /usr/local/lib
cp /usr/local/lib64/pkgconfig/libavif.pc /usr/local/lib/pkgconfig
fi
} }
function build { function build {

View File

@ -18,7 +18,7 @@ def test_wheel_modules() -> None:
except ImportError: except ImportError:
expected_modules.remove("tkinter") expected_modules.remove("tkinter")
# libavif is not available on windows for x86 and ARM64 architectures # libavif is not available on Windows for x86 and ARM64 architectures
if sys.platform == "win32": if sys.platform == "win32":
if platform.machine() == "ARM64" or struct.calcsize("P") == 4: if platform.machine() == "ARM64" or struct.calcsize("P") == 4:
expected_modules.remove("avif") expected_modules.remove("avif")

View File

@ -127,8 +127,6 @@ class TestUnsupportedAvif:
@skip_unless_feature("avif") @skip_unless_feature("avif")
class TestFileAvif: class TestFileAvif:
def test_version(self) -> None: def test_version(self) -> None:
_avif.AvifCodecVersions()
version = features.version_module("avif") version = features.version_module("avif")
assert version is not None assert version is not None
assert re.search(r"\d+\.\d+\.\d+$", version) assert re.search(r"\d+\.\d+\.\d+$", version)

View File

@ -1370,17 +1370,16 @@ The :py:meth:`~PIL.Image.Image.save` method supports the following options:
YUV range, either "full" or "limited". Defaults to "full" YUV range, either "full" or "limited". Defaults to "full"
**codec** **codec**
AV1 codec to use for encoding. Possible values are "aom", "rav1e", and AV1 codec to use for encoding. Specific values are "aom", "rav1e", and
"svt", depending on what codecs were compiled with libavif. Defaults to "svt", presuming the chosen codec is available. Defaults to "auto", which
"auto", which will choose the first available codec in the order of the will choose the first available codec in the order of the preceding list.
preceding list.
**tile_rows** / **tile_cols** **tile_rows** / **tile_cols**
For tile encoding, the (log 2) number of tile rows and columns to use. For tile encoding, the (log 2) number of tile rows and columns to use.
Valid values are 0-6, default 0. Valid values are 0-6, default 0.
**alpha_premultiplied** **alpha_premultiplied**
Encode the image with premultiplied alpha, defaults ``False`` Encode the image with premultiplied alpha. Defaults to ``False``
**icc_profile** **icc_profile**
The ICC Profile to include in the saved file. The ICC Profile to include in the saved file.

View File

@ -164,9 +164,11 @@ Many of Pillow's features require external libraries:
The easiest way to install external libraries is via `Homebrew The easiest way to install external libraries is via `Homebrew
<https://brew.sh/>`_. After you install Homebrew, run:: <https://brew.sh/>`_. After you install Homebrew, run::
brew install libjpeg libraqm libtiff little-cms2 openjpeg webp brew install libavif libjpeg libraqm libtiff little-cms2 openjpeg webp
To install libavif on macOS use Homebrew to install its build dependencies:: If you would like to use libavif with more codecs than just aom, then
instead of installing libavif through Homebrew directly, you can use
Homebrew to install libavif's build dependencies::
brew install aom dav1d rav1e brew install aom dav1d rav1e
@ -224,8 +226,7 @@ Many of Pillow's features require external libraries:
sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 openjpeg harfbuzz fribidi libxcb libavif sudo pkg install jpeg-turbo tiff webp lcms2 freetype2 openjpeg harfbuzz fribidi libxcb libavif
See ``depends/install_raqm_cmake.sh`` to install libraqm and See ``depends/install_raqm_cmake.sh`` to install libraqm.
``depends/install_libavif.sh`` to install libavif.
.. tab:: Android .. tab:: Android

View File

@ -24,17 +24,11 @@ _VALID_AVIF_MODES = {"RGB", "RGBA"}
def _accept(prefix: bytes) -> bool | str: def _accept(prefix: bytes) -> bool | str:
if prefix[4:8] != b"ftyp": if prefix[4:8] != b"ftyp":
return False return False
coding_brands = (b"avif", b"avis")
container_brands = (b"mif1", b"msf1")
major_brand = prefix[8:12] major_brand = prefix[8:12]
if major_brand in coding_brands: if major_brand in (
if not SUPPORTED: # coding brands
return ( b"avif",
"image file could not be identified because AVIF " b"avis",
"support not installed"
)
return True
if major_brand in container_brands:
# We accept files with AVIF container brands; we can't yet know if # We accept files with AVIF container brands; we can't yet know if
# the ftyp box has the correct compatible brands, but if it doesn't # the ftyp box has the correct compatible brands, but if it doesn't
# then the plugin will raise a SyntaxError which Pillow will catch # then the plugin will raise a SyntaxError which Pillow will catch
@ -42,6 +36,14 @@ def _accept(prefix: bytes) -> bool | str:
# #
# Also, because this file might not actually be an AVIF file, we # Also, because this file might not actually be an AVIF file, we
# don't raise an error if AVIF support isn't properly compiled. # don't raise an error if AVIF support isn't properly compiled.
b"mif1",
b"msf1",
):
if not SUPPORTED:
return (
"image file could not be identified because AVIF "
"support not installed"
)
return True return True
return False return False
@ -72,6 +74,11 @@ class AvifImageFile(ImageFile.ImageFile):
) )
raise SyntaxError(msg) raise SyntaxError(msg)
if DECODE_CODEC_CHOICE != "auto" and not _avif.decoder_codec_available(
DECODE_CODEC_CHOICE
):
msg = "Invalid opening codec"
raise ValueError(msg)
self._decoder = _avif.AvifDecoder( self._decoder = _avif.AvifDecoder(
self.fp.read(), self.fp.read(),
DECODE_CODEC_CHOICE, DECODE_CODEC_CHOICE,
@ -104,10 +111,8 @@ class AvifImageFile(ImageFile.ImageFile):
data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame( data, timescale, tsp_in_ts, dur_in_ts = self._decoder.get_frame(
self.__frame self.__frame
) )
timestamp = round(1000 * (tsp_in_ts / timescale)) self.info["timestamp"] = round(1000 * (tsp_in_ts / timescale))
duration = round(1000 * (dur_in_ts / timescale)) self.info["duration"] = round(1000 * (dur_in_ts / timescale))
self.info["timestamp"] = timestamp
self.info["duration"] = duration
self.__loaded = self.__frame self.__loaded = self.__frame
# Set tile # Set tile
@ -153,6 +158,9 @@ def _save(
speed = info.get("speed", 6) speed = info.get("speed", 6)
max_threads = info.get("max_threads", _get_default_max_threads()) max_threads = info.get("max_threads", _get_default_max_threads())
codec = info.get("codec", "auto") codec = info.get("codec", "auto")
if codec != "auto" and not _avif.encoder_codec_available(codec):
msg = "Invalid saving codec"
raise ValueError(msg)
range_ = info.get("range", "full") range_ = info.get("range", "full")
tile_rows_log2 = info.get("tile_rows", 0) tile_rows_log2 = info.get("tile_rows", 0)
tile_cols_log2 = info.get("tile_cols", 0) tile_cols_log2 = info.get("tile_cols", 0)
@ -199,7 +207,7 @@ def _save(
) )
raise ValueError(msg) raise ValueError(msg)
advanced = tuple( advanced = tuple(
[(str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced] (str(k).encode("utf-8"), str(v).encode("utf-8")) for k, v in advanced
) )
# Setup the AVIF encoder # Setup the AVIF encoder

View File

@ -218,30 +218,43 @@ _encoder_codec_available(PyObject *self, PyObject *args) {
return PyBool_FromLong(is_available); return PyBool_FromLong(is_available);
} }
static void static int
_add_codec_specific_options(avifEncoder *encoder, PyObject *opts) { _add_codec_specific_options(avifEncoder *encoder, PyObject *opts) {
Py_ssize_t i, size; Py_ssize_t i, size;
PyObject *keyval, *py_key, *py_val; PyObject *keyval, *py_key, *py_val;
char *key, *val; char *key, *val;
if (!PyTuple_Check(opts)) { if (!PyTuple_Check(opts)) {
return; PyErr_SetString(PyExc_ValueError, "Invalid advanced codec options");
return 1;
} }
size = PyTuple_GET_SIZE(opts); size = PyTuple_GET_SIZE(opts);
for (i = 0; i < size; i++) { for (i = 0; i < size; i++) {
keyval = PyTuple_GetItem(opts, i); keyval = PyTuple_GetItem(opts, i);
if (!PyTuple_Check(keyval) || PyTuple_GET_SIZE(keyval) != 2) { if (!PyTuple_Check(keyval) || PyTuple_GET_SIZE(keyval) != 2) {
return; PyErr_SetString(PyExc_ValueError, "Invalid advanced codec options");
return 1;
} }
py_key = PyTuple_GetItem(keyval, 0); py_key = PyTuple_GetItem(keyval, 0);
py_val = PyTuple_GetItem(keyval, 1); py_val = PyTuple_GetItem(keyval, 1);
if (!PyBytes_Check(py_key) || !PyBytes_Check(py_val)) { if (!PyBytes_Check(py_key) || !PyBytes_Check(py_val)) {
return; PyErr_SetString(PyExc_ValueError, "Invalid advanced codec options");
return 1;
} }
key = PyBytes_AsString(py_key); key = PyBytes_AsString(py_key);
val = PyBytes_AsString(py_val); val = PyBytes_AsString(py_val);
avifEncoderSetCodecSpecificOption(encoder, key, val);
avifResult result = avifEncoderSetCodecSpecificOption(encoder, key, val);
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Setting advanced codec options failed: %s",
avifResultToString(result)
);
return 1;
} }
}
return 0;
} }
// Encoder functions // Encoder functions
@ -336,17 +349,6 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
enc_options.codec = AVIF_CODEC_CHOICE_AUTO; enc_options.codec = AVIF_CODEC_CHOICE_AUTO;
} else { } else {
enc_options.codec = avifCodecChoiceFromName(codec); enc_options.codec = avifCodecChoiceFromName(codec);
if (enc_options.codec == AVIF_CODEC_CHOICE_AUTO) {
PyErr_Format(PyExc_ValueError, "Invalid codec: %s", codec);
return NULL;
} else {
const char *codec_name =
avifCodecName(enc_options.codec, AVIF_CODEC_FLAG_CAN_ENCODE);
if (codec_name == NULL) {
PyErr_Format(PyExc_ValueError, "AV1 Codec cannot encode: %s", codec);
return NULL;
}
}
} }
if (strcmp(range, "full") == 0) { if (strcmp(range, "full") == 0) {
@ -410,9 +412,18 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
encoder->autoTiling = enc_options.autotiling; encoder->autoTiling = enc_options.autotiling;
#endif #endif
if (advanced != Py_None) {
#if AVIF_VERSION >= 80200 #if AVIF_VERSION >= 80200
_add_codec_specific_options(encoder, advanced); if (_add_codec_specific_options(encoder, advanced)) {
return NULL;
}
#else
PyErr_SetString(
PyExc_ValueError, "Advanced codec options require libavif >= 0.8.2"
);
return NULL;
#endif #endif
}
self->encoder = encoder; self->encoder = encoder;
@ -430,14 +441,24 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
image->alphaPremultiplied = enc_options.alpha_premultiplied; image->alphaPremultiplied = enc_options.alpha_premultiplied;
#endif #endif
avifResult result;
if (PyBytes_GET_SIZE(icc_bytes)) { if (PyBytes_GET_SIZE(icc_bytes)) {
self->icc_bytes = icc_bytes; self->icc_bytes = icc_bytes;
Py_INCREF(icc_bytes); Py_INCREF(icc_bytes);
avifImageSetProfileICC(
result = avifImageSetProfileICC(
image, image,
(uint8_t *)PyBytes_AS_STRING(icc_bytes), (uint8_t *)PyBytes_AS_STRING(icc_bytes),
PyBytes_GET_SIZE(icc_bytes) PyBytes_GET_SIZE(icc_bytes)
); );
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Setting ICC profile failed: %s",
avifResultToString(result)
);
return NULL;
}
} else { } else {
image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709;
image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB;
@ -446,20 +467,38 @@ AvifEncoderNew(PyObject *self_, PyObject *args) {
if (PyBytes_GET_SIZE(exif_bytes)) { if (PyBytes_GET_SIZE(exif_bytes)) {
self->exif_bytes = exif_bytes; self->exif_bytes = exif_bytes;
Py_INCREF(exif_bytes); Py_INCREF(exif_bytes);
avifImageSetMetadataExif(
result = avifImageSetMetadataExif(
image, image,
(uint8_t *)PyBytes_AS_STRING(exif_bytes), (uint8_t *)PyBytes_AS_STRING(exif_bytes),
PyBytes_GET_SIZE(exif_bytes) PyBytes_GET_SIZE(exif_bytes)
); );
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Setting EXIF data failed: %s",
avifResultToString(result)
);
return NULL;
}
} }
if (PyBytes_GET_SIZE(xmp_bytes)) { if (PyBytes_GET_SIZE(xmp_bytes)) {
self->xmp_bytes = xmp_bytes; self->xmp_bytes = xmp_bytes;
Py_INCREF(xmp_bytes); Py_INCREF(xmp_bytes);
avifImageSetMetadataXMP(
result = avifImageSetMetadataXMP(
image, image,
(uint8_t *)PyBytes_AS_STRING(xmp_bytes), (uint8_t *)PyBytes_AS_STRING(xmp_bytes),
PyBytes_GET_SIZE(xmp_bytes) PyBytes_GET_SIZE(xmp_bytes)
); );
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Setting XMP data failed: %s",
avifResultToString(result)
);
return NULL;
}
} }
exif_orientation_to_irot_imir(image, exif_orientation); exif_orientation_to_irot_imir(image, exif_orientation);
@ -498,7 +537,6 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
PyObject *ret = Py_None; PyObject *ret = Py_None;
int is_first_frame; int is_first_frame;
int channels;
avifRGBImage rgb; avifRGBImage rgb;
avifResult result; avifResult result;
@ -561,13 +599,19 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) {
if (strcmp(mode, "RGBA") == 0) { if (strcmp(mode, "RGBA") == 0) {
rgb.format = AVIF_RGB_FORMAT_RGBA; rgb.format = AVIF_RGB_FORMAT_RGBA;
channels = 4;
} else { } else {
rgb.format = AVIF_RGB_FORMAT_RGB; rgb.format = AVIF_RGB_FORMAT_RGB;
channels = 3;
} }
avifRGBImageAllocatePixels(&rgb); result = avifRGBImageAllocatePixels(&rgb);
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Pixel allocation failed: %s",
avifResultToString(result)
);
return NULL;
}
if (rgb.rowBytes * rgb.height != size) { if (rgb.rowBytes * rgb.height != size) {
PyErr_Format( PyErr_Format(
@ -679,18 +723,6 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
codec = AVIF_CODEC_CHOICE_AUTO; codec = AVIF_CODEC_CHOICE_AUTO;
} else { } else {
codec = avifCodecChoiceFromName(codec_str); codec = avifCodecChoiceFromName(codec_str);
if (codec == AVIF_CODEC_CHOICE_AUTO) {
PyErr_Format(PyExc_ValueError, "Invalid codec: %s", codec_str);
return NULL;
} else {
const char *codec_name = avifCodecName(codec, AVIF_CODEC_FLAG_CAN_DECODE);
if (codec_name == NULL) {
PyErr_Format(
PyExc_ValueError, "AV1 Codec cannot decode: %s", codec_str
);
return NULL;
}
}
} }
self = PyObject_New(AvifDecoderObject, &AvifDecoder_Type); self = PyObject_New(AvifDecoderObject, &AvifDecoder_Type);
@ -717,14 +749,24 @@ AvifDecoderNew(PyObject *self_, PyObject *args) {
#endif #endif
self->decoder->codecChoice = codec; self->decoder->codecChoice = codec;
avifDecoderSetIOMemory( result = avifDecoderSetIOMemory(
self->decoder, self->decoder,
(uint8_t *)PyBytes_AS_STRING(self->data), (uint8_t *)PyBytes_AS_STRING(self->data),
PyBytes_GET_SIZE(self->data) PyBytes_GET_SIZE(self->data)
); );
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Setting IO memory failed: %s",
avifResultToString(result)
);
avifDecoderDestroy(self->decoder);
self->decoder = NULL;
Py_DECREF(self);
return NULL;
}
result = avifDecoderParse(self->decoder); result = avifDecoderParse(self->decoder);
if (result != AVIF_RESULT_OK) { if (result != AVIF_RESULT_OK) {
PyErr_Format( PyErr_Format(
exc_type_for_avif_result(result), exc_type_for_avif_result(result),
@ -815,7 +857,6 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
} }
result = avifDecoderNthImage(decoder, frame_index); result = avifDecoderNthImage(decoder, frame_index);
if (result != AVIF_RESULT_OK) { if (result != AVIF_RESULT_OK) {
PyErr_Format( PyErr_Format(
exc_type_for_avif_result(result), exc_type_for_avif_result(result),
@ -847,7 +888,15 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) {
return NULL; return NULL;
} }
avifRGBImageAllocatePixels(&rgb); result = avifRGBImageAllocatePixels(&rgb);
if (result != AVIF_RESULT_OK) {
PyErr_Format(
exc_type_for_avif_result(result),
"Pixel allocation failed: %s",
avifResultToString(result)
);
return NULL;
}
Py_BEGIN_ALLOW_THREADS result = avifImageYUVToRGB(image, &rgb); Py_BEGIN_ALLOW_THREADS result = avifImageYUVToRGB(image, &rgb);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
@ -893,10 +942,7 @@ static struct PyMethodDef _encoder_methods[] = {
// AvifDecoder type definition // AvifDecoder type definition
static PyTypeObject AvifEncoder_Type = { static PyTypeObject AvifEncoder_Type = {
// clang-format off PyVarObject_HEAD_INIT(NULL, 0).tp_name = "AvifEncoder",
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "AvifEncoder",
// clang-format on
.tp_basicsize = sizeof(AvifEncoderObject), .tp_basicsize = sizeof(AvifEncoderObject),
.tp_dealloc = (destructor)_encoder_dealloc, .tp_dealloc = (destructor)_encoder_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT, .tp_flags = Py_TPFLAGS_DEFAULT,
@ -912,10 +958,7 @@ static struct PyMethodDef _decoder_methods[] = {
// AvifDecoder type definition // AvifDecoder type definition
static PyTypeObject AvifDecoder_Type = { static PyTypeObject AvifDecoder_Type = {
// clang-format off PyVarObject_HEAD_INIT(NULL, 0).tp_name = "AvifDecoder",
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "AvifDecoder",
// clang-format on
.tp_basicsize = sizeof(AvifDecoderObject), .tp_basicsize = sizeof(AvifDecoderObject),
.tp_itemsize = 0, .tp_itemsize = 0,
.tp_dealloc = (destructor)_decoder_dealloc, .tp_dealloc = (destructor)_decoder_dealloc,
@ -923,13 +966,6 @@ static PyTypeObject AvifDecoder_Type = {
.tp_methods = _decoder_methods, .tp_methods = _decoder_methods,
}; };
PyObject *
AvifCodecVersions() {
char codecVersions[256];
avifCodecVersions(codecVersions);
return PyUnicode_FromString(codecVersions);
}
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/* Module Setup */ /* Module Setup */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
@ -937,7 +973,6 @@ AvifCodecVersions() {
static PyMethodDef avifMethods[] = { static PyMethodDef avifMethods[] = {
{"AvifDecoder", AvifDecoderNew, METH_VARARGS}, {"AvifDecoder", AvifDecoderNew, METH_VARARGS},
{"AvifEncoder", AvifEncoderNew, METH_VARARGS}, {"AvifEncoder", AvifEncoderNew, METH_VARARGS},
{"AvifCodecVersions", AvifCodecVersions, METH_NOARGS},
{"decoder_codec_available", _decoder_codec_available, METH_VARARGS}, {"decoder_codec_available", _decoder_codec_available, METH_VARARGS},
{"encoder_codec_available", _encoder_codec_available, METH_VARARGS}, {"encoder_codec_available", _encoder_codec_available, METH_VARARGS},
{NULL, NULL} {NULL, NULL}

View File

@ -122,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.2", "MESON": "1.6.0",
"LIBAVIF": "1.1.1", "LIBAVIF": "1.1.1",
"RAV1E": "0.7.1", "RAV1E": "0.7.1",
} }
@ -673,12 +673,15 @@ def build_dep(name: str, prefs: dict[str, str], verbose: bool) -> str:
def build_dep_all(disabled: list[str], prefs: dict[str, str], verbose: bool) -> None: def build_dep_all(disabled: list[str], prefs: dict[str, str], verbose: bool) -> None:
lines = [r'call "{build_dir}\build_env.cmd"'] lines = [r'call "{build_dir}\build_env.cmd"']
gha_groups = "GITHUB_ACTIONS" in os.environ gha_groups = "GITHUB_ACTIONS" in os.environ
scripts = ["install_meson.cmd"]
for dep_name in DEPS: for dep_name in DEPS:
print() print()
if dep_name in disabled: if dep_name in disabled:
print(f"Skipping disabled dependency {dep_name}") print(f"Skipping disabled dependency {dep_name}")
continue continue
scripts = []
if dep_name == "libavif":
scripts.append("install_meson.cmd")
scripts.append(build_dep(dep_name, prefs, verbose)) scripts.append(build_dep(dep_name, prefs, verbose))
for script in scripts: for script in scripts:
@ -830,6 +833,7 @@ def main() -> None:
print() print()
write_script(".gitignore", ["*"], prefs, args.verbose) write_script(".gitignore", ["*"], prefs, args.verbose)
if "libavif" not in disabled:
write_script( write_script(
"install_meson.cmd", "install_meson.cmd",
[ [