diff --git a/Tests/test_image.py b/Tests/test_image.py index c22628509..17f1edb00 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -48,6 +48,9 @@ class TestImage: "RGBX", "RGBA", "RGBa", + "BGR;15", + "BGR;16", + "BGR;24", "CMYK", "YCbCr", "LAB", @@ -57,9 +60,7 @@ class TestImage: def test_image_modes_success(self, mode): Image.new(mode, (1, 1)) - @pytest.mark.parametrize( - "mode", ("", "bad", "very very long", "BGR;15", "BGR;16", "BGR;24") - ) + @pytest.mark.parametrize("mode", ("", "bad", "very very long")) def test_image_modes_fail(self, mode): with pytest.raises(ValueError) as e: Image.new(mode, (1, 1)) diff --git a/Tests/test_image_access.py b/Tests/test_image_access.py index 4079d9358..29eed745e 100644 --- a/Tests/test_image_access.py +++ b/Tests/test_image_access.py @@ -363,8 +363,8 @@ class TestCffi(AccessTest): class TestImagePutPixelError(AccessTest): - IMAGE_MODES1 = ["L", "LA", "RGB", "RGBA"] - IMAGE_MODES2 = ["I", "I;16", "BGR;15"] + IMAGE_MODES1 = ["LA", "RGB", "RGBA", "BGR;15"] + IMAGE_MODES2 = ["L", "I", "I;16"] INVALID_TYPES = ["foo", 1.0, None] @pytest.mark.parametrize("mode", IMAGE_MODES1) @@ -379,6 +379,11 @@ class TestImagePutPixelError(AccessTest): ( ("L", (0, 2), "color must be int or single-element tuple"), ("LA", (0, 3), "color must be int, or tuple of one or two elements"), + ( + "BGR;15", + (0, 2), + "color must be int, or tuple of one or three elements", + ), ( "RGB", (0, 2, 5), @@ -407,11 +412,6 @@ class TestImagePutPixelError(AccessTest): with pytest.raises(OverflowError): im.putpixel((0, 0), 2**80) - def test_putpixel_unrecognized_mode(self): - im = hopper("BGR;15") - with pytest.raises(ValueError, match="unrecognized image mode"): - im.putpixel((0, 0), 0) - class TestEmbeddable: @pytest.mark.xfail(reason="failing test") diff --git a/src/PIL/ImageMode.py b/src/PIL/ImageMode.py index 8b1506e9b..a0b335142 100644 --- a/src/PIL/ImageMode.py +++ b/src/PIL/ImageMode.py @@ -58,9 +58,9 @@ def getmode(mode): "HSV": ("RGB", "L", ("H", "S", "V"), "|u1"), # extra experimental modes "RGBa": ("RGB", "L", ("R", "G", "B", "a"), "|u1"), - "BGR;15": ("RGB", "L", ("B", "G", "R"), endian + "u2"), - "BGR;16": ("RGB", "L", ("B", "G", "R"), endian + "u2"), - "BGR;24": ("RGB", "L", ("B", "G", "R"), endian + "u3"), + "BGR;15": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;16": ("RGB", "L", ("B", "G", "R"), "|u1"), + "BGR;24": ("RGB", "L", ("B", "G", "R"), "|u1"), "LA": ("L", "L", ("L", "A"), "|u1"), "La": ("L", "L", ("L", "a"), "|u1"), "PA": ("RGB", "L", ("P", "A"), "|u1"), diff --git a/src/_imaging.c b/src/_imaging.c index e7e403c95..3b17d638e 100644 --- a/src/_imaging.c +++ b/src/_imaging.c @@ -517,15 +517,13 @@ getink(PyObject *color, Imaging im, char *ink) { return NULL; } rIsInt = 1; - } else if (im->type == IMAGING_TYPE_UINT8) { - if (!PyTuple_Check(color)) { - PyErr_SetString(PyExc_TypeError, "color must be int or tuple"); - return NULL; - } - } else { + } else if (im->bands == 1) { PyErr_SetString( PyExc_TypeError, "color must be int or single-element tuple"); return NULL; + } else if (!PyTuple_Check(color)) { + PyErr_SetString(PyExc_TypeError, "color must be int or tuple"); + return NULL; } } @@ -596,6 +594,41 @@ getink(PyObject *color, Imaging im, char *ink) { ink[1] = (UINT8)(r >> 8); ink[2] = ink[3] = 0; return ink; + } else { + if (rIsInt) { + b = (UINT8)(r >> 16); + g = (UINT8)(r >> 8); + r = (UINT8)r; + } else if (tupleSize != 3) { + PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or three elements"); + return NULL; + } else if (!PyArg_ParseTuple(color, "Lii", &r, &g, &b)) { + return NULL; + } + if (!strcmp(im->mode, "BGR;15")) { + UINT16 v = ((((UINT16)r) << 7) & 0x7c00) + + ((((UINT16)g) << 2) & 0x03e0) + + ((((UINT16)b) >> 3) & 0x001f); + + ink[0] = (UINT8)v; + ink[1] = (UINT8)(v >> 8); + ink[2] = ink[3] = 0; + return ink; + } else if (!strcmp(im->mode, "BGR;16")) { + UINT16 v = ((((UINT16)r) << 8) & 0xf800) + + ((((UINT16)g) << 3) & 0x07e0) + + ((((UINT16)b) >> 3) & 0x001f); + ink[0] = (UINT8)v; + ink[1] = (UINT8)(v >> 8); + ink[2] = ink[3] = 0; + return ink; + } else if (!strcmp(im->mode, "BGR;24")) { + ink[0] = (UINT8)b; + ink[1] = (UINT8)g; + ink[2] = (UINT8)r; + ink[3] = 0; + return ink; + } } } diff --git a/src/libImaging/Storage.c b/src/libImaging/Storage.c index 7730b4be8..7cf00ef35 100644 --- a/src/libImaging/Storage.c +++ b/src/libImaging/Storage.c @@ -131,7 +131,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } else if (strcmp(mode, "BGR;15") == 0) { /* EXPERIMENTAL */ /* 15-bit reversed true colour */ - im->bands = 1; + im->bands = 3; im->pixelsize = 2; im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; @@ -139,7 +139,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } else if (strcmp(mode, "BGR;16") == 0) { /* EXPERIMENTAL */ /* 16-bit reversed true colour */ - im->bands = 1; + im->bands = 3; im->pixelsize = 2; im->linesize = (xsize * 2 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL; @@ -147,7 +147,7 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, int size) { } else if (strcmp(mode, "BGR;24") == 0) { /* EXPERIMENTAL */ /* 24-bit reversed true colour */ - im->bands = 1; + im->bands = 3; im->pixelsize = 3; im->linesize = (xsize * 3 + 3) & -4; im->type = IMAGING_TYPE_SPECIAL;