diff --git a/Tests/test_file_webp.py b/Tests/test_file_webp.py index 14a2d2317a1..b0a8c51ba01 100644 --- a/Tests/test_file_webp.py +++ b/Tests/test_file_webp.py @@ -2,7 +2,6 @@ import io import re -import sys import warnings from typing import Any @@ -158,21 +157,13 @@ def test_write_unsupported_mode_P(self, tmp_path: Path) -> None: self._roundtrip(tmp_path, "P", 50.0) - @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system") - def test_write_encoding_error_message(self, tmp_path: Path) -> None: - im = Image.new("RGB", (15000, 15000)) - with pytest.raises(ValueError, match="encoding error 6"): - im.save(tmp_path / "temp.webp", method=0) - - @pytest.mark.skipif(sys.maxsize <= 2**32, reason="Requires 64-bit system") def test_write_encoding_error_bad_dimension(self, tmp_path: Path) -> None: im = Image.new("L", (16384, 1)) - with pytest.raises(ValueError) as e: + with pytest.raises( + ValueError, + match="encoding error 5: image size exceeds WebP limit of 16383 pixels", + ): im.save(tmp_path / "temp.webp") - assert ( - str(e.value) - == "encoding error 5: Image size exceeds WebP limit of 16383 pixels" - ) def test_WebPEncode_with_invalid_args(self) -> None: """ diff --git a/docs/releasenotes/13.0.0.rst b/docs/releasenotes/13.0.0.rst index 694093b01ab..636d51a1d96 100644 --- a/docs/releasenotes/13.0.0.rst +++ b/docs/releasenotes/13.0.0.rst @@ -134,6 +134,12 @@ escape sequences. Other changes ============= +WebP encoding errors now include a description +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When libwebp fails to encode an image, the raised :py:exc:`ValueError` now +consistently describes the error rather than only reporting a numeric code. + PNG palettes are no longer padded when saving with the ``bits`` argument ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/_webp.c b/src/_webp.c index 9f9fbf3978a..5aa7cb170ec 100644 --- a/src/_webp.c +++ b/src/_webp.c @@ -73,6 +73,30 @@ HandleMuxError(WebPMuxError err, char *chunk) { return NULL; } +/* -------------------------------------------------------------------- */ +/* WebP Encoder Error Mapping */ +/* -------------------------------------------------------------------- */ + +#define WEBP_STR_HELPER(x) #x +#define WEBP_STR(x) WEBP_STR_HELPER(x) + +static const char *const kEncoderErrorMessages[VP8_ENC_ERROR_LAST] = { + "ok", + "out of memory allocating objects", + "out of memory re-allocating byte buffer", + "NULL parameter passed to function", + "configuration is invalid", + "image size exceeds WebP limit of " WEBP_STR(WEBP_MAX_DIMENSION) " pixels", + "partition #0 is bigger than 512K", + "partition is bigger than 16M", + "picture writer returned an I/O error", + "file would be bigger than 4G", + "encoding aborted by user" +}; + +#undef WEBP_STR +#undef WEBP_STR_HELPER + /* -------------------------------------------------------------------- */ /* Frame import */ /* -------------------------------------------------------------------- */ @@ -647,17 +671,12 @@ WebPEncode_wrapper(PyObject *self, PyObject *args) { ret_size = writer.size; if (!ok) { - int error_code = (&pic)->error_code; - char message[50] = ""; - if (error_code == VP8_ENC_ERROR_BAD_DIMENSION) { - sprintf( - message, - ": Image size exceeds WebP limit of %d pixels", - WEBP_MAX_DIMENSION - ); - } - PyErr_Format(PyExc_ValueError, "encoding error %d%s", error_code, message); free(output); + WebPEncodingError error_code = pic.error_code; + const char *message = error_code > VP8_ENC_OK && error_code < VP8_ENC_ERROR_LAST + ? kEncoderErrorMessages[error_code] + : "unknown error"; + PyErr_Format(PyExc_ValueError, "encoding error %d: %s", error_code, message); return NULL; }