Skip to content

Commit

Permalink
Improved error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
radarhere committed Nov 18, 2024
1 parent 0ac0612 commit 070a985
Showing 1 changed file with 89 additions and 14 deletions.
103 changes: 89 additions & 14 deletions src/_avif.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 070a985

Please sign in to comment.