diff --git a/src/_avif.c b/src/_avif.c index 82f5b954e88..c50068b860e 100644 --- a/src/_avif.c +++ b/src/_avif.c @@ -106,30 +106,43 @@ _encoder_codec_available(PyObject *self, PyObject *args) { return PyBool_FromLong(is_available); } -static void +static int _add_codec_specific_options(avifEncoder *encoder, PyObject *opts) { Py_ssize_t i, size; PyObject *keyval, *py_key, *py_val; char *key, *val; if (!PyTuple_Check(opts)) { - return; + PyErr_SetString(PyExc_ValueError, "Invalid advanced codec options"); + return 1; } size = PyTuple_GET_SIZE(opts); for (i = 0; i < size; i++) { keyval = PyTuple_GetItem(opts, i); 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_val = PyTuple_GetItem(keyval, 1); 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); 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 @@ -296,9 +309,18 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { encoder->autoTiling = enc_options.autotiling; #endif + if (advanced != Py_None) { #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 + } self->encoder = encoder; @@ -316,14 +338,24 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { image->alphaPremultiplied = enc_options.alpha_premultiplied; #endif + avifResult result; if (PyBytes_GET_SIZE(icc_bytes)) { self->icc_bytes = icc_bytes; Py_INCREF(icc_bytes); - avifImageSetProfileICC( + + result = avifImageSetProfileICC( image, (uint8_t *)PyBytes_AS_STRING(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 { image->colorPrimaries = AVIF_COLOR_PRIMARIES_BT709; image->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_SRGB; @@ -332,20 +364,38 @@ AvifEncoderNew(PyObject *self_, PyObject *args) { if (PyBytes_GET_SIZE(exif_bytes)) { self->exif_bytes = exif_bytes; Py_INCREF(exif_bytes); - avifImageSetMetadataExif( + + result = avifImageSetMetadataExif( image, (uint8_t *)PyBytes_AS_STRING(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)) { self->xmp_bytes = xmp_bytes; Py_INCREF(xmp_bytes); - avifImageSetMetadataXMP( + + result = avifImageSetMetadataXMP( image, (uint8_t *)PyBytes_AS_STRING(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; + } } self->image = image; @@ -449,7 +499,15 @@ _encoder_add(AvifEncoderObject *self, PyObject *args) { rgb.format = AVIF_RGB_FORMAT_RGB; } - 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) { PyErr_Format( @@ -599,14 +657,24 @@ AvifDecoderNew(PyObject *self_, PyObject *args) { #endif self->decoder->codecChoice = codec; - avifDecoderSetIOMemory( + result = avifDecoderSetIOMemory( self->decoder, (uint8_t *)PyBytes_AS_STRING(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); - if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), @@ -697,7 +765,6 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) { } result = avifDecoderNthImage(decoder, frame_index); - if (result != AVIF_RESULT_OK) { PyErr_Format( exc_type_for_avif_result(result), @@ -729,7 +796,15 @@ _decoder_get_frame(AvifDecoderObject *self, PyObject *args) { 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_END_ALLOW_THREADS