diff --git a/Tests/test_color_lut.py b/Tests/test_color_lut.py index 085f07fcc38..196b1943a39 100644 --- a/Tests/test_color_lut.py +++ b/Tests/test_color_lut.py @@ -140,7 +140,7 @@ def test_correct_args( def test_wrong_mode( self, image_mode: str, lut_mode: str, table_channels: int, table_size: int ) -> None: - with pytest.raises(ValueError, match="wrong mode"): + with pytest.raises(ValueError, match="bands"): im = Image.new(image_mode, (10, 10), 0) im.im.color_lut_3d( lut_mode, diff --git a/Tests/test_image_convert.py b/Tests/test_image_convert.py index f596f009025..f72af583ade 100644 --- a/Tests/test_image_convert.py +++ b/Tests/test_image_convert.py @@ -46,7 +46,7 @@ def convert(im: Image.Image, mode: str) -> None: def test_unsupported_conversion() -> None: im = hopper() - with pytest.raises(ValueError, match="image has wrong mode"): + with pytest.raises(ValueError): im.convert("INVALID") @@ -318,7 +318,7 @@ def test_matrix_wrong_mode() -> None: im = hopper("L") # Act / Assert - with pytest.raises(ValueError, match="image has wrong mode"): + with pytest.raises(ValueError, match="image must have exactly 3 bands"): im.convert(mode="L", matrix=rgb2xyz_matrix) diff --git a/Tests/test_image_paste.py b/Tests/test_image_paste.py index 976b1b2b681..53d63e53c24 100644 --- a/Tests/test_image_paste.py +++ b/Tests/test_image_paste.py @@ -370,7 +370,9 @@ def test_overflow(self, box: tuple[int, int, int, int]) -> None: im = Image.new("1", (1, 1)) im.paste(1, box) - with pytest.raises(ValueError, match="images do not match"): + with pytest.raises( + ValueError, match="image dimensions and pixel size must match" + ): im.paste(im.copy(), box) def test_incorrect_abbreviated_form(self) -> None: diff --git a/Tests/test_image_putalpha.py b/Tests/test_image_putalpha.py index 404e3433e57..917e9dd5aad 100644 --- a/Tests/test_image_putalpha.py +++ b/Tests/test_image_putalpha.py @@ -41,7 +41,7 @@ def test_promote() -> None: assert im.mode == "RGBA" assert im.getpixel((0, 0)) == (1, 2, 3, 4) - with pytest.raises(ValueError, match="image has wrong mode"): + with pytest.raises(ValueError, match="RGB"): im.im.setalpha() diff --git a/Tests/test_imagewin.py b/Tests/test_imagewin.py index 18f7527a045..73a502e27a9 100644 --- a/Tests/test_imagewin.py +++ b/Tests/test_imagewin.py @@ -101,7 +101,7 @@ def test_dib_paste_bbox(self) -> None: # Assert assert dib.size == (128, 128) - with pytest.raises(ValueError, match="images do not match"): + with pytest.raises(ValueError, match="box must match image size"): dib.paste(im, (0, 0, 1, 1)) def test_dib_frombytes_tobytes_roundtrip(self) -> None: diff --git a/src/_imaging.c b/src/_imaging.c index 9303dcd34fb..a23aa368b76 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -371,14 +371,31 @@ ImagingError_MemoryError(void) { } void * -ImagingError_Mismatch(void) { - PyErr_SetString(PyExc_ValueError, "images do not match"); +ImagingError_Mismatch(const char *message) { + PyErr_SetString( + PyExc_ValueError, (message) ? (char *)message : "images do not match" + ); return NULL; } void * -ImagingError_ModeError(void) { - PyErr_SetString(PyExc_ValueError, "image has wrong mode"); +ImagingError_ModeError(const char *message) { + PyErr_SetString( + PyExc_ValueError, (message) ? (char *)message : "image has wrong mode" + ); + return NULL; +} + +// Derives from both NotImplementedError and ValueError +// (as the functions above raise ValueErrors). +static PyObject *ImagingNotSupportedError = NULL; + +void * +ImagingError_NotSupportedError(const char *message) { + PyErr_SetString( + ImagingNotSupportedError ? ImagingNotSupportedError : PyExc_NotImplementedError, + (message) ? (char *)message : "operation not supported" + ); return NULL; } @@ -2077,7 +2094,7 @@ im_setalpha(ImagingObject *self, PyObject *args) { /* attempt to modify the mode of an image in place */ Imaging im = self->image; if (im->mode != IMAGING_MODE_RGB && im->mode != IMAGING_MODE_RGBX) { - return ImagingError_ModeError(); + return ImagingError_ModeError("only RGB/RGBX modes supported"); } im->mode = IMAGING_MODE_RGBA; im->bands = 4; @@ -4319,6 +4336,24 @@ setup_module(PyObject *m) { return -1; } + if (ImagingNotSupportedError == NULL) { + // NotSupportedError derives from both NotImplementedError and ValueError, + // for compatibility with `except ValueError`. + PyObject *bases = PyTuple_Pack(2, PyExc_NotImplementedError, PyExc_ValueError); + if (bases == NULL) { + return -1; + } + ImagingNotSupportedError = + PyErr_NewException("PIL._imaging.NotSupportedError", bases, NULL); + Py_DECREF(bases); + if (ImagingNotSupportedError == NULL) { + return -1; + } + } + if (PyModule_AddObjectRef(m, "NotSupportedError", ImagingNotSupportedError) < 0) { + return -1; + } + #ifdef HAVE_LIBJPEG { extern const char *ImagingJpegVersion(void); diff --git a/src/display.c b/src/display.c index a950cffc127..cc1d3e2e24e 100644 --- a/src/display.c +++ b/src/display.c @@ -135,12 +135,12 @@ _paste(ImagingDisplayObject *display, PyObject *args) { if (xy[2] <= xy[0]) { xy[2] = xy[0] + im->xsize; } else if (xy[2] - xy[0] != im->xsize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("box must match image size"); } if (xy[3] <= xy[1]) { xy[3] = xy[1] + im->ysize; } else if (xy[3] - xy[1] != im->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("box must match image size"); } ImagingPasteDIB(display->dib, im, xy); diff --git a/src/libImaging/AlphaComposite.c b/src/libImaging/AlphaComposite.c index d1a1e7ad34a..a12f7398e66 100644 --- a/src/libImaging/AlphaComposite.c +++ b/src/libImaging/AlphaComposite.c @@ -24,14 +24,16 @@ ImagingAlphaComposite(Imaging imDst, Imaging imSrc) { Imaging imOut; /* Check arguments */ - if (!imDst || !imSrc || - (imDst->mode != IMAGING_MODE_RGBA && imDst->mode != IMAGING_MODE_LA)) { - return ImagingError_ModeError(); + if (!imDst || !imSrc) { + return ImagingError_ValueError("imDst and imSrc must not be NULL"); + } + if (imDst->mode != IMAGING_MODE_RGBA && imDst->mode != IMAGING_MODE_LA) { + return ImagingError_ModeError("destination image must have alpha channel"); } if (imDst->mode != imSrc->mode || imDst->xsize != imSrc->xsize || imDst->ysize != imSrc->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("image modes and dimensions must match"); } imOut = ImagingNewDirty(imDst->mode, imDst->xsize, imDst->ysize); diff --git a/src/libImaging/Bands.c b/src/libImaging/Bands.c index 410b722bde4..ae4bd88ee13 100644 --- a/src/libImaging/Bands.c +++ b/src/libImaging/Bands.c @@ -23,8 +23,12 @@ ImagingGetBand(Imaging imIn, int band) { int x, y; /* Check arguments */ - if (!imIn || imIn->type != IMAGING_TYPE_UINT8) { - return (Imaging)ImagingError_ModeError(); + if (!imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + + if (imIn->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_NotSupportedError("only 8-bit images supported"); } if (band < 0 || band >= imIn->bands) { @@ -80,8 +84,13 @@ ImagingSplit(Imaging imIn, Imaging bands[4]) { int i, j, x, y; /* Check arguments */ - if (!imIn || imIn->type != IMAGING_TYPE_UINT8) { - (void)ImagingError_ModeError(); + if (!imIn) { + (void)ImagingError_ValueError(NULL); + return -1; + } + + if (imIn->type != IMAGING_TYPE_UINT8) { + (void)ImagingError_NotSupportedError("only 8-bit images supported"); return -1; } @@ -185,8 +194,11 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) { int x, y; /* Check arguments */ - if (!imIn || imIn->bands != 1 || !imOut) { - return (Imaging)ImagingError_ModeError(); + if (!imIn || !imOut) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->bands != 1) { + return (Imaging)ImagingError_ModeError("source image must have exactly 1 band"); } if (band < 0 || band >= imOut->bands) { @@ -195,7 +207,7 @@ ImagingPutBand(Imaging imOut, Imaging imIn, int band) { if (imIn->type != imOut->type || imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("image types and sizes must match"); } /* Shortcuts */ @@ -231,8 +243,16 @@ ImagingFillBand(Imaging imOut, int band, int color) { int x, y; /* Check arguments */ - if (!imOut || imOut->type != IMAGING_TYPE_UINT8) { - return (Imaging)ImagingError_ModeError(); + if (!imOut) { + return (Imaging)ImagingError_ValueError(NULL); + } + + if (!imOut) { + return (Imaging)ImagingError_ValueError("only 8-bit images supported"); + } + + if (imOut->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_NotSupportedError("only 8-bit images supported"); } if (band < 0 || band >= imOut->bands) { @@ -277,11 +297,13 @@ ImagingMerge(const ModeID mode, Imaging bands[4]) { break; } if (bands[i]->bands != 1) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError( + "source image must have exactly 1 band" + ); } if (bands[i]->xsize != firstBand->xsize || bands[i]->ysize != firstBand->ysize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("image sizes must match"); } } bandsCount = i; diff --git a/src/libImaging/Blend.c b/src/libImaging/Blend.c index 19662abf044..3f861915978 100644 --- a/src/libImaging/Blend.c +++ b/src/libImaging/Blend.c @@ -23,15 +23,20 @@ ImagingBlend(Imaging imIn1, Imaging imIn2, float alpha) { int x, y; /* Check arguments */ - if (!imIn1 || !imIn2 || imIn1->type != IMAGING_TYPE_UINT8 || imIn1->palette || + if (!imIn1 || !imIn2) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn1->type != IMAGING_TYPE_UINT8 || imIn1->palette || imIn1->mode == IMAGING_MODE_1 || imIn2->palette || imIn2->mode == IMAGING_MODE_1) { - return ImagingError_ModeError(); + return ImagingError_ModeError( + "images must have 8-bit data and must not use mode P or 1" + ); } if (imIn1->type != imIn2->type || imIn1->bands != imIn2->bands || imIn1->xsize != imIn2->xsize || imIn1->ysize != imIn2->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("image types, band count and sizes must match"); } /* Shortcuts */ diff --git a/src/libImaging/BoxBlur.c b/src/libImaging/BoxBlur.c index b1a8fd04a19..5830e9518f6 100644 --- a/src/libImaging/BoxBlur.c +++ b/src/libImaging/BoxBlur.c @@ -253,18 +253,20 @@ ImagingBoxBlur(Imaging imOut, Imaging imIn, float xradius, float yradius, int n) if (imIn->mode != imOut->mode || imIn->type != imOut->type || imIn->bands != imOut->bands || imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("image mode, type, bands and size must match"); } if (imIn->type != IMAGING_TYPE_UINT8) { - return ImagingError_ModeError(); + return ImagingError_NotSupportedError("non-uint8 images not supported"); } if (imIn->mode != IMAGING_MODE_RGB && imIn->mode != IMAGING_MODE_RGBA && imIn->mode != IMAGING_MODE_RGBa && imIn->mode != IMAGING_MODE_RGBX && imIn->mode != IMAGING_MODE_CMYK && imIn->mode != IMAGING_MODE_L && imIn->mode != IMAGING_MODE_LA && imIn->mode != IMAGING_MODE_La) { - return ImagingError_ModeError(); + return ImagingError_NotSupportedError( + "BoxBlur operation not supported in this mode" + ); } /* Apply blur in one dimension. diff --git a/src/libImaging/Chops.c b/src/libImaging/Chops.c index 557c2f52f10..537fc888be1 100644 --- a/src/libImaging/Chops.c +++ b/src/libImaging/Chops.c @@ -68,14 +68,19 @@ static Imaging create(Imaging im1, Imaging im2, const ModeID mode) { int xsize, ysize; + if (!im1 || !im2) { + return (Imaging)ImagingError_ValueError(NULL); + } - if (!im1 || !im2 || im1->type != IMAGING_TYPE_UINT8 || - (mode != IMAGING_MODE_UNKNOWN && - (im1->mode != IMAGING_MODE_1 || im2->mode != IMAGING_MODE_1))) { - return (Imaging)ImagingError_ModeError(); + if (im1->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_ModeError("images must have 8-bit data"); + } + if (mode != IMAGING_MODE_UNKNOWN && + (im1->mode != IMAGING_MODE_1 || im2->mode != IMAGING_MODE_1)) { + return (Imaging)ImagingError_ModeError("both images must have mode 1"); } if (im1->type != im2->type || im1->bands != im2->bands) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("image types and band count must match"); } xsize = (im1->xsize < im2->xsize) ? im1->xsize : im2->xsize; diff --git a/src/libImaging/ColorLUT.c b/src/libImaging/ColorLUT.c index 5559de689b2..fc07d3d53ab 100644 --- a/src/libImaging/ColorLUT.c +++ b/src/libImaging/ColorLUT.c @@ -87,14 +87,23 @@ ImagingColorLUT3D_linear( return NULL; } - if (imIn->type != IMAGING_TYPE_UINT8 || imOut->type != IMAGING_TYPE_UINT8 || - imIn->bands < 3 || imOut->bands < table_channels) { - return (Imaging)ImagingError_ModeError(); + if (imIn->type != IMAGING_TYPE_UINT8 || imOut->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_NotSupportedError( + "only 8-bit image modes are supported" + ); + } + if (imIn->bands < 3) { + return (Imaging)ImagingError_ModeError("input image needs at least 3 bands"); + } + if (imOut->bands < table_channels) { + return (Imaging)ImagingError_ValueError( + "output image needs at least as many bands as the table" + ); } - - /* In case we have one extra band in imOut and don't have in imIn.*/ if (imOut->bands > table_channels && imOut->bands > imIn->bands) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError( + "output image has more bands than input image and table" + ); } ImagingSectionEnter(&cookie); diff --git a/src/libImaging/Convert.c b/src/libImaging/Convert.c index 4a35a9a1fb1..acad10167cf 100644 --- a/src/libImaging/Convert.c +++ b/src/libImaging/Convert.c @@ -1608,13 +1608,13 @@ ImagingConvert( ImagingShuffler convert; if (!imIn) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } if (mode == IMAGING_MODE_UNKNOWN) { /* Map palette image to full depth */ if (!imIn->palette) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError("image has no palette"); } mode = imIn->palette->mode; } else { @@ -1683,7 +1683,7 @@ ImagingConvertTransparent(Imaging imIn, const ModeID mode, int r, int g, int b) int y; if (!imIn) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } if (imIn->mode == IMAGING_MODE_RGB && diff --git a/src/libImaging/Crop.c b/src/libImaging/Crop.c index 2425b4cd589..7379671fe86 100644 --- a/src/libImaging/Crop.c +++ b/src/libImaging/Crop.c @@ -25,7 +25,7 @@ ImagingCrop(Imaging imIn, int sx0, int sy0, int sx1, int sy1) { INT32 zero = 0; if (!imIn) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } xsize = sx1 - sx0; diff --git a/src/libImaging/Dib.c b/src/libImaging/Dib.c index 2afe71d4ac9..599f886ba30 100644 --- a/src/libImaging/Dib.c +++ b/src/libImaging/Dib.c @@ -59,7 +59,9 @@ ImagingNewDIB(const ModeID mode, int xsize, int ysize) { /* Check mode */ if (mode != IMAGING_MODE_1 && mode != IMAGING_MODE_L && mode != IMAGING_MODE_RGB) { - return (ImagingDIB)ImagingError_ModeError(); + return (ImagingDIB)ImagingError_NotSupportedError( + "only modes I/L/RGB supported" + ); } const int pixelsize = mode == IMAGING_MODE_RGB ? 3 : 1; diff --git a/src/libImaging/Effects.c b/src/libImaging/Effects.c index c05c5764e44..cee7aeeab18 100644 --- a/src/libImaging/Effects.c +++ b/src/libImaging/Effects.c @@ -33,7 +33,9 @@ ImagingEffectMandelbrot(int xsize, int ysize, double extent[4], int quality) { width = extent[2] - extent[0]; height = extent[3] - extent[1]; if (width < 0.0 || height < 0.0 || quality < 2) { - return (Imaging)ImagingError_ValueError(NULL); + return (Imaging)ImagingError_ValueError( + "width and height must be >=0 and quality >= 2" + ); } im = ImagingNewDirty(IMAGING_MODE_L, xsize, ysize); diff --git a/src/libImaging/Fill.c b/src/libImaging/Fill.c index 6f730921358..3efd74852e4 100644 --- a/src/libImaging/Fill.c +++ b/src/libImaging/Fill.c @@ -78,7 +78,9 @@ ImagingFillLinearGradient(const ModeID mode) { if (mode != IMAGING_MODE_1 && mode != IMAGING_MODE_F && mode != IMAGING_MODE_I && mode != IMAGING_MODE_L && mode != IMAGING_MODE_P) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "only modes 1/F/I/L/P supported" + ); } im = ImagingNewDirty(mode, 256, 256); @@ -117,7 +119,9 @@ ImagingFillRadialGradient(const ModeID mode) { if (mode != IMAGING_MODE_1 && mode != IMAGING_MODE_F && mode != IMAGING_MODE_I && mode != IMAGING_MODE_L && mode != IMAGING_MODE_P) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "only modes 1/F/I/L/P supported" + ); } im = ImagingNewDirty(mode, 256, 256); diff --git a/src/libImaging/Filter.c b/src/libImaging/Filter.c index 3492a871f21..3cbd1ca0090 100644 --- a/src/libImaging/Filter.c +++ b/src/libImaging/Filter.c @@ -487,7 +487,9 @@ ImagingFilter(Imaging im, int xsize, int ysize, const FLOAT32 *kernel, FLOAT32 o ImagingSectionCookie cookie; if (im->type == IMAGING_TYPE_FLOAT32) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError( + "32-bit floating point image types not supported" + ); } if (im->xsize < xsize || im->ysize < ysize) { diff --git a/src/libImaging/Geometry.c b/src/libImaging/Geometry.c index 1bf92e26efa..85571baf111 100644 --- a/src/libImaging/Geometry.c +++ b/src/libImaging/Geometry.c @@ -19,11 +19,14 @@ ImagingFlipLeftRight(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xr; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("images must have the same size"); } ImagingCopyPalette(imOut, imIn); @@ -62,11 +65,14 @@ ImagingFlipTopBottom(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int y, yr; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("images must have the same size"); } ImagingCopyPalette(imOut, imIn); @@ -89,11 +95,16 @@ ImagingRotate90(Imaging imOut, Imaging imIn) { int x, y, xx, yy, xr, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch( + "output size must be the transpose of the input size" + ); } ImagingCopyPalette(imOut, imIn); @@ -149,11 +160,16 @@ ImagingTranspose(Imaging imOut, Imaging imIn) { int x, y, xx, yy, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch( + "output size must be the transpose of the input size" + ); } ImagingCopyPalette(imOut, imIn); @@ -208,11 +224,16 @@ ImagingTransverse(Imaging imOut, Imaging imIn) { int x, y, xr, yr, xx, yy, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch( + "output size must be the transpose of the input size" + ); } ImagingCopyPalette(imOut, imIn); @@ -268,11 +289,14 @@ ImagingRotate180(Imaging imOut, Imaging imIn) { ImagingSectionCookie cookie; int x, y, xr, yr; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch("images must have the same size"); } ImagingCopyPalette(imOut, imIn); @@ -313,11 +337,16 @@ ImagingRotate270(Imaging imOut, Imaging imIn) { int x, y, xx, yy, yr, xxsize, yysize; int xxx, yyy, xxxsize, yyysize; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) { - return (Imaging)ImagingError_Mismatch(); + return (Imaging)ImagingError_Mismatch( + "output size must be the transpose of the input size" + ); } ImagingCopyPalette(imOut, imIn); @@ -784,8 +813,11 @@ ImagingGenericTransform( char *out; double xx, yy; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } ImagingTransformFilter filter = getfilter(imIn, filterid); @@ -841,8 +873,11 @@ ImagingScaleAffine( int xmin, xmax; int *xintab; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } ImagingCopyPalette(imOut, imIn); @@ -1028,8 +1063,11 @@ ImagingTransformAffine( double xx, yy; double xo, yo; - if (!imOut || !imIn || imIn->mode != imOut->mode) { - return (Imaging)ImagingError_ModeError(); + if (!imOut || !imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != imOut->mode) { + return (Imaging)ImagingError_ModeError("images must have the same mode"); } if (filterid || imIn->type == IMAGING_TYPE_I16) { diff --git a/src/libImaging/GetBBox.c b/src/libImaging/GetBBox.c index 45fe717c5c2..53a549f06eb 100644 --- a/src/libImaging/GetBBox.c +++ b/src/libImaging/GetBBox.c @@ -152,7 +152,7 @@ ImagingGetExtrema(Imaging im, void *extrema) { FLOAT32 fmin, fmax; if (im->bands != 1) { - (void)ImagingError_ModeError(); + (void)ImagingError_ModeError("image must have exactly 1 band"); return -1; /* mismatch */ } @@ -242,7 +242,7 @@ ImagingGetExtrema(Imaging im, void *extrema) { } /* FALL THROUGH */ default: - (void)ImagingError_ModeError(); + (void)ImagingError_NotSupportedError("mode not supported"); return -1; } return 1; /* ok */ @@ -304,7 +304,7 @@ getcolors32(Imaging im, int maxcolors, int *size) { } if (!im->image32) { - return ImagingError_ModeError(); + return ImagingError_ModeError("image must have 32-bit data"); } table = calloc(code_size + 1, sizeof(ImagingColorItem)); diff --git a/src/libImaging/Histo.c b/src/libImaging/Histo.c index 7af60003511..8a405d68aa1 100644 --- a/src/libImaging/Histo.c +++ b/src/libImaging/Histo.c @@ -65,13 +65,13 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void *minmax) { FLOAT32 fmin, fmax, scale; if (!im) { - return ImagingError_ModeError(); + return ImagingError_ValueError(NULL); } if (imMask) { /* Validate mask */ if (im->xsize != imMask->xsize || im->ysize != imMask->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("mask and image size must match"); } if (imMask->mode != IMAGING_MODE_1 && imMask->mode != IMAGING_MODE_L) { return ImagingError_ValueError("bad transparency mask"); @@ -98,7 +98,7 @@ ImagingGetHistogram(Imaging im, Imaging imMask, void *minmax) { } else { /* yes, we need the braces. C isn't Python! */ if (im->type != IMAGING_TYPE_UINT8) { ImagingHistogramDelete(h); - return ImagingError_ModeError(); + return ImagingError_ModeError("image must have 8-bit data"); } ImagingSectionEnter(&cookie); for (y = 0; y < im->ysize; y++) { diff --git a/src/libImaging/Imaging.h b/src/libImaging/Imaging.h index 20f74b519a3..891709971da 100644 --- a/src/libImaging/Imaging.h +++ b/src/libImaging/Imaging.h @@ -268,11 +268,15 @@ ImagingSectionLeave(ImagingSectionCookie *cookie); extern void * ImagingError_MemoryError(void); extern void * -ImagingError_ModeError(void); /* maps to ValueError by default */ +ImagingError_ModeError(const char *message); /* maps to ValueError by default */ extern void * -ImagingError_Mismatch(void); /* maps to ValueError by default */ +ImagingError_Mismatch(const char *message); /* maps to ValueError by default */ extern void * ImagingError_ValueError(const char *message); +extern void * +ImagingError_NotSupportedError( + const char *message +); /* derives from NotImplementedError and ValueError */ /* Transform callbacks */ /* ------------------- */ diff --git a/src/libImaging/Matrix.c b/src/libImaging/Matrix.c index 02676c9e31a..3eaa59e9bda 100644 --- a/src/libImaging/Matrix.c +++ b/src/libImaging/Matrix.c @@ -23,8 +23,11 @@ ImagingConvertMatrix(Imaging im, const ModeID mode, const float m[12]) { ImagingSectionCookie cookie; /* Assume there's enough data in the buffer */ - if (!im || im->bands != 3) { - return (Imaging)ImagingError_ModeError(); + if (!im) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (im->bands != 3) { + return (Imaging)ImagingError_ModeError("image must have exactly 3 bands"); } if (mode == IMAGING_MODE_L) { @@ -77,7 +80,9 @@ ImagingConvertMatrix(Imaging im, const ModeID mode, const float m[12]) { ImagingSectionLeave(&cookie); } } else { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "only conversions to modes L and RGB are supported" + ); } return imOut; diff --git a/src/libImaging/ModeFilter.c b/src/libImaging/ModeFilter.c index 757cbc3fb86..99fed34c520 100644 --- a/src/libImaging/ModeFilter.c +++ b/src/libImaging/ModeFilter.c @@ -24,8 +24,11 @@ ImagingModeFilter(Imaging im, int size) { UINT8 maxpixel; int histogram[256]; - if (!im || im->bands != 1 || im->type != IMAGING_TYPE_UINT8) { - return (Imaging)ImagingError_ModeError(); + if (!im) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (im->bands != 1 || im->type != IMAGING_TYPE_UINT8) { + return (Imaging)ImagingError_ModeError("image must have 8-bit data in 1 band"); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); diff --git a/src/libImaging/Negative.c b/src/libImaging/Negative.c index 114e8608e87..f8acb7293b9 100644 --- a/src/libImaging/Negative.c +++ b/src/libImaging/Negative.c @@ -24,7 +24,7 @@ ImagingNegative(Imaging im) { int x, y; if (!im) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } imOut = ImagingNewDirty(im->mode, im->xsize, im->ysize); diff --git a/src/libImaging/Offset.c b/src/libImaging/Offset.c index 48c60b3c4f2..2506b637415 100644 --- a/src/libImaging/Offset.c +++ b/src/libImaging/Offset.c @@ -25,7 +25,7 @@ Imaging ImagingOffset(Imaging im, int xoffset, int yoffset) { if (!im) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } int xsize = im->xsize, ysize = im->ysize; diff --git a/src/libImaging/Palette.c b/src/libImaging/Palette.c index b2dacf656b5..4d7791b8aab 100644 --- a/src/libImaging/Palette.c +++ b/src/libImaging/Palette.c @@ -29,7 +29,9 @@ ImagingPaletteNew(const ModeID mode) { if (mode != IMAGING_MODE_RGB && mode != IMAGING_MODE_RGBA && mode != IMAGING_MODE_CMYK) { - return (ImagingPalette)ImagingError_ModeError(); + return (ImagingPalette)ImagingError_ModeError( + "only RGB/RGBA/CMYK images supported" + ); } palette = calloc(1, sizeof(struct ImagingPaletteInstance)); diff --git a/src/libImaging/Paste.c b/src/libImaging/Paste.c index 0396cf58095..4c74b409659 100644 --- a/src/libImaging/Paste.c +++ b/src/libImaging/Paste.c @@ -280,7 +280,7 @@ ImagingPaste( ImagingSectionCookie cookie; if (!imOut || !imIn) { - (void)ImagingError_ModeError(); + (void)ImagingError_ValueError(NULL); return -1; } @@ -290,12 +290,12 @@ ImagingPaste( ysize = (int64_t)dy1 - dy0; if (xsize != imIn->xsize || ysize != imIn->ysize || pixelsize != imIn->pixelsize) { - (void)ImagingError_Mismatch(); + (void)ImagingError_Mismatch("image dimensions and pixel size must match"); return -1; } if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { - (void)ImagingError_Mismatch(); + (void)ImagingError_Mismatch("mask size must match image size"); return -1; } @@ -603,7 +603,7 @@ ImagingFill2( int sx0, sy0; if (!imOut || !ink) { - (void)ImagingError_ModeError(); + (void)ImagingError_ValueError(NULL); return -1; } @@ -613,7 +613,7 @@ ImagingFill2( ysize = (int64_t)dy1 - dy0; if (imMask && (xsize != imMask->xsize || ysize != imMask->ysize)) { - (void)ImagingError_Mismatch(); + (void)ImagingError_Mismatch("mask size must match image size"); return -1; } diff --git a/src/libImaging/Point.c b/src/libImaging/Point.c index dcf88daa586..ddca85b74c2 100644 --- a/src/libImaging/Point.c +++ b/src/libImaging/Point.c @@ -137,7 +137,7 @@ ImagingPoint(Imaging imIn, ModeID mode, const void *table) { void (*point)(Imaging imIn, Imaging imOut, im_point_context *context); if (!imIn) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ValueError(NULL); } if (mode == IMAGING_MODE_UNKNOWN) { @@ -210,9 +210,12 @@ ImagingPointTransform(Imaging imIn, double scale, double offset) { Imaging imOut; int x, y; - if (!imIn || (imIn->mode != IMAGING_MODE_I && imIn->mode != IMAGING_MODE_I_16 && - imIn->mode != IMAGING_MODE_F)) { - return (Imaging)ImagingError_ModeError(); + if (!imIn) { + return (Imaging)ImagingError_ValueError(NULL); + } + if (imIn->mode != IMAGING_MODE_I && imIn->mode != IMAGING_MODE_I_16 && + imIn->mode != IMAGING_MODE_F) { + return (Imaging)ImagingError_NotSupportedError("only modes I/I;16/F supported"); } imOut = ImagingNew(imIn->mode, imIn->xsize, imIn->ysize); diff --git a/src/libImaging/Quant.c b/src/libImaging/Quant.c index 99c2dbac3af..0713018e208 100644 --- a/src/libImaging/Quant.c +++ b/src/libImaging/Quant.c @@ -1678,7 +1678,7 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { ImagingSectionCookie cookie; if (!im) { - return ImagingError_ModeError(); + return ImagingError_ValueError(NULL); } if (colors < 1 || colors > 256) { /* FIXME: for colors > 256, consider returning an RGB image @@ -1688,12 +1688,11 @@ ImagingQuantize(Imaging im, int colors, int mode, int kmeans) { if (im->mode != IMAGING_MODE_L && im->mode != IMAGING_MODE_P && im->mode != IMAGING_MODE_RGB && im->mode != IMAGING_MODE_RGBA) { - return ImagingError_ModeError(); + return ImagingError_NotSupportedError("only modes L/P/RGB/RGBA supported"); } - /* only octree and imagequant supports RGBA */ if (im->mode == IMAGING_MODE_RGBA && mode != 2 && mode != 3) { - return ImagingError_ModeError(); + return ImagingError_ModeError("only octree and imagequant support RGBA"); } // Hoisted here as these are invariant over the loops below. diff --git a/src/libImaging/RankFilter.c b/src/libImaging/RankFilter.c index fc8ce2db96d..07e34fffb47 100644 --- a/src/libImaging/RankFilter.c +++ b/src/libImaging/RankFilter.c @@ -64,8 +64,16 @@ MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) int x, y; int i, margin, size2; - if (!im || im->bands != 1 || im->type == IMAGING_TYPE_I16) { - return (Imaging)ImagingError_ModeError(); + if (!im) { + return (Imaging)ImagingError_ValueError(NULL); + } + + if (!im) { + return (Imaging)ImagingError_ValueError(NULL); + } + + if (im->bands != 1 || im->type == IMAGING_TYPE_I16) { + return (Imaging)ImagingError_ModeError("image must be 1-band, 8-bpc"); } if (!(size & 1)) { @@ -121,7 +129,7 @@ MakeRankFunction(UINT8) MakeRankFunction(INT32) MakeRankFunction(FLOAT32) } else { /* safety net (we shouldn't end up here) */ ImagingDelete(imOut); - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_ModeError(NULL); } ImagingCopyPalette(imOut, im); diff --git a/src/libImaging/Reduce.c b/src/libImaging/Reduce.c index 7e5634bed46..9269686a496 100644 --- a/src/libImaging/Reduce.c +++ b/src/libImaging/Reduce.c @@ -1454,7 +1454,9 @@ ImagingReduce(Imaging imIn, int xscale, int yscale, int box[4]) { if (imIn->mode == IMAGING_MODE_P || imIn->mode == IMAGING_MODE_1 || imIn->type == IMAGING_TYPE_I16) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "mode P/mode I/16-bit images not supported" + ); } /* Round the size up. Dividing before adding avoids overflowing for a diff --git a/src/libImaging/Resample.c b/src/libImaging/Resample.c index fee4cf8d9dc..5c3a6bcc8f3 100644 --- a/src/libImaging/Resample.c +++ b/src/libImaging/Resample.c @@ -758,7 +758,9 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) { ResampleFunction ResampleVertical; if (imIn->mode == IMAGING_MODE_P || imIn->mode == IMAGING_MODE_1) { - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "modes P and 1 are not supported" + ); } if (imIn->type == IMAGING_TYPE_I16) { @@ -779,7 +781,9 @@ ImagingResample(Imaging imIn, int xsize, int ysize, int filter, float box[4]) { ResampleVertical = _ImagingResampleVertical_32bpc; break; default: - return (Imaging)ImagingError_ModeError(); + return (Imaging)ImagingError_NotSupportedError( + "special image types are not supported" + ); } } diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 1c3f912f808..1259b9e5e44 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -748,7 +748,7 @@ ImagingNew2Dirty(const ModeID mode, Imaging imOut, Imaging imIn) { /* make sure images match */ if (imOut->mode != mode || imOut->xsize != imIn->xsize || imOut->ysize != imIn->ysize) { - return ImagingError_Mismatch(); + return ImagingError_Mismatch("image modes and dimensions must match"); } } else { /* create new image */