Skip to content

Commit 24d711b

Browse files
authored
Merge pull request #7303 from radarhere/bgr
Support BGR;15, BGR;16 and BGR;24 access, unpacking and putdata
2 parents b5d4239 + 4e7f61f commit 24d711b

File tree

6 files changed

+117
-16
lines changed

6 files changed

+117
-16
lines changed

Tests/test_image_access.py

+10
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,16 @@ def color(mode):
130130
bands = Image.getmodebands(mode)
131131
if bands == 1:
132132
return 1
133+
if mode in ("BGR;15", "BGR;16"):
134+
# These modes have less than 8 bits per band
135+
# So (1, 2, 3) cannot be roundtripped
136+
return (16, 32, 49)
133137
return tuple(range(1, bands + 1))
134138

135139
def check(self, mode, expected_color=None):
140+
if self._need_cffi_access and mode.startswith("BGR;"):
141+
pytest.skip("Support not added to deprecated module for BGR;* modes")
142+
136143
if not expected_color:
137144
expected_color = self.color(mode)
138145

@@ -203,6 +210,9 @@ def check(self, mode, expected_color=None):
203210
"F",
204211
"P",
205212
"PA",
213+
"BGR;15",
214+
"BGR;16",
215+
"BGR;24",
206216
"RGB",
207217
"RGBA",
208218
"RGBX",

Tests/test_image_putdata.py

+9
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ def test_mode_F():
7676
assert list(im.getdata()) == target
7777

7878

79+
@pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24"))
80+
def test_mode_BGR(mode):
81+
data = [(16, 32, 49), (32, 32, 98)]
82+
im = Image.new(mode, (1, 2))
83+
im.putdata(data)
84+
85+
assert list(im.getdata()) == data
86+
87+
7988
def test_array_B():
8089
# shouldn't segfault
8190
# see https://github.com/python-pillow/Pillow/issues/1008

Tests/test_lib_pack.py

+7
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,13 @@ def test_RGB(self):
344344
"RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233)
345345
)
346346

347+
def test_BGR(self):
348+
self.assert_unpack("BGR;15", "BGR;15", 3, (8, 131, 0), (24, 0, 8), (41, 131, 8))
349+
self.assert_unpack(
350+
"BGR;16", "BGR;16", 3, (8, 64, 0), (24, 129, 0), (41, 194, 0)
351+
)
352+
self.assert_unpack("BGR;24", "BGR;24", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
353+
347354
def test_RGBA(self):
348355
self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
349356
self.assert_unpack(

src/_imaging.c

+41-14
Original file line numberDiff line numberDiff line change
@@ -475,8 +475,10 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) {
475475
case IMAGING_TYPE_FLOAT32:
476476
return PyFloat_FromDouble(pixel.f);
477477
case IMAGING_TYPE_SPECIAL:
478-
if (strncmp(im->mode, "I;16", 4) == 0) {
478+
if (im->bands == 1) {
479479
return PyLong_FromLong(pixel.h);
480+
} else {
481+
return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]);
480482
}
481483
break;
482484
}
@@ -599,7 +601,7 @@ getink(PyObject *color, Imaging im, char *ink) {
599601
} else if (tupleSize != 3) {
600602
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or three elements");
601603
return NULL;
602-
} else if (!PyArg_ParseTuple(color, "Lii", &r, &g, &b)) {
604+
} else if (!PyArg_ParseTuple(color, "iiL", &b, &g, &r)) {
603605
return NULL;
604606
}
605607
if (!strcmp(im->mode, "BGR;15")) {
@@ -1571,21 +1573,46 @@ if (PySequence_Check(op)) { \
15711573
PyErr_SetString(PyExc_TypeError, must_be_sequence);
15721574
return NULL;
15731575
}
1574-
int endian = strncmp(image->mode, "I;16", 4) == 0 ? (strcmp(image->mode, "I;16B") == 0 ? 2 : 1) : 0;
15751576
double value;
1576-
for (i = x = y = 0; i < n; i++) {
1577-
set_value_to_item(seq, i);
1578-
if (scale != 1.0 || offset != 0.0) {
1579-
value = value * scale + offset;
1577+
if (image->bands == 1) {
1578+
int bigendian;
1579+
if (image->type == IMAGING_TYPE_SPECIAL) {
1580+
// I;16*
1581+
bigendian = strcmp(image->mode, "I;16B") == 0;
15801582
}
1581-
if (endian == 0) {
1582-
image->image8[y][x] = (UINT8)CLIP8(value);
1583-
} else {
1584-
image->image8[y][x * 2 + (endian == 2 ? 1 : 0)] = CLIP8((int)value % 256);
1585-
image->image8[y][x * 2 + (endian == 2 ? 0 : 1)] = CLIP8((int)value >> 8);
1583+
for (i = x = y = 0; i < n; i++) {
1584+
set_value_to_item(seq, i);
1585+
if (scale != 1.0 || offset != 0.0) {
1586+
value = value * scale + offset;
1587+
}
1588+
if (image->type == IMAGING_TYPE_SPECIAL) {
1589+
image->image8[y][x * 2 + (bigendian ? 1 : 0)] = CLIP8((int)value % 256);
1590+
image->image8[y][x * 2 + (bigendian ? 0 : 1)] = CLIP8((int)value >> 8);
1591+
} else {
1592+
image->image8[y][x] = (UINT8)CLIP8(value);
1593+
}
1594+
if (++x >= (int)image->xsize) {
1595+
x = 0, y++;
1596+
}
15861597
}
1587-
if (++x >= (int)image->xsize) {
1588-
x = 0, y++;
1598+
} else {
1599+
// BGR;*
1600+
int b;
1601+
for (i = x = y = 0; i < n; i++) {
1602+
char ink[4];
1603+
1604+
op = PySequence_Fast_GET_ITEM(seq, i);
1605+
if (!op || !getink(op, image, ink)) {
1606+
Py_DECREF(seq);
1607+
return NULL;
1608+
}
1609+
/* FIXME: what about scale and offset? */
1610+
for (b = 0; b < image->pixelsize; b++) {
1611+
image->image8[y][x * image->pixelsize + b] = ink[b];
1612+
}
1613+
if (++x >= (int)image->xsize) {
1614+
x = 0, y++;
1615+
}
15891616
}
15901617
}
15911618
PyErr_Clear(); /* Avoid weird exceptions */

src/libImaging/Access.c

+40-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
#include "Imaging.h"
1313

1414
/* use make_hash.py from the pillow-scripts repository to calculate these values */
15-
#define ACCESS_TABLE_SIZE 27
16-
#define ACCESS_TABLE_HASH 33051
15+
#define ACCESS_TABLE_SIZE 35
16+
#define ACCESS_TABLE_HASH 8940
1717

1818
static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
1919

@@ -87,6 +87,31 @@ get_pixel_16(Imaging im, int x, int y, void *color) {
8787
memcpy(color, in, sizeof(UINT16));
8888
}
8989

90+
static void
91+
get_pixel_BGR15(Imaging im, int x, int y, void *color) {
92+
UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
93+
UINT16 pixel = in[0] + (in[1] << 8);
94+
char *out = color;
95+
out[0] = (pixel & 31) * 255 / 31;
96+
out[1] = ((pixel >> 5) & 31) * 255 / 31;
97+
out[2] = ((pixel >> 10) & 31) * 255 / 31;
98+
}
99+
100+
static void
101+
get_pixel_BGR16(Imaging im, int x, int y, void *color) {
102+
UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
103+
UINT16 pixel = in[0] + (in[1] << 8);
104+
char *out = color;
105+
out[0] = (pixel & 31) * 255 / 31;
106+
out[1] = ((pixel >> 5) & 63) * 255 / 63;
107+
out[2] = ((pixel >> 11) & 31) * 255 / 31;
108+
}
109+
110+
static void
111+
get_pixel_BGR24(Imaging im, int x, int y, void *color) {
112+
memcpy(color, &im->image8[y][x * 3], sizeof(UINT8) * 3);
113+
}
114+
90115
static void
91116
get_pixel_32(Imaging im, int x, int y, void *color) {
92117
memcpy(color, &im->image32[y][x], sizeof(INT32));
@@ -134,6 +159,16 @@ put_pixel_16B(Imaging im, int x, int y, const void *color) {
134159
out[1] = in[0];
135160
}
136161

162+
static void
163+
put_pixel_BGR1516(Imaging im, int x, int y, const void *color) {
164+
memcpy(&im->image8[y][x * 2], color, 2);
165+
}
166+
167+
static void
168+
put_pixel_BGR24(Imaging im, int x, int y, const void *color) {
169+
memcpy(&im->image8[y][x * 3], color, 3);
170+
}
171+
137172
static void
138173
put_pixel_32L(Imaging im, int x, int y, const void *color) {
139174
memcpy(&im->image8[y][x * 4], color, 4);
@@ -178,6 +213,9 @@ ImagingAccessInit() {
178213
ADD("F", get_pixel_32, put_pixel_32);
179214
ADD("P", get_pixel_8, put_pixel_8);
180215
ADD("PA", get_pixel_32_2bands, put_pixel_32);
216+
ADD("BGR;15", get_pixel_BGR15, put_pixel_BGR1516);
217+
ADD("BGR;16", get_pixel_BGR16, put_pixel_BGR1516);
218+
ADD("BGR;24", get_pixel_BGR24, put_pixel_BGR24);
181219
ADD("RGB", get_pixel_32, put_pixel_32);
182220
ADD("RGBA", get_pixel_32, put_pixel_32);
183221
ADD("RGBa", get_pixel_32, put_pixel_32);

src/libImaging/Unpack.c

+10
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,12 @@ copy2(UINT8 *out, const UINT8 *in, int pixels) {
12391239
memcpy(out, in, pixels * 2);
12401240
}
12411241

1242+
static void
1243+
copy3(UINT8 *out, const UINT8 *in, int pixels) {
1244+
/* BGR;24 */
1245+
memcpy(out, in, pixels * 3);
1246+
}
1247+
12421248
static void
12431249
copy4(UINT8 *out, const UINT8 *in, int pixels) {
12441250
/* RGBA, CMYK quadruples */
@@ -1592,6 +1598,10 @@ static struct {
15921598
{"RGB", "B;16B", 16, band216B},
15931599
{"RGB", "CMYK", 32, cmyk2rgb},
15941600

1601+
{"BGR;15", "BGR;15", 16, copy2},
1602+
{"BGR;16", "BGR;16", 16, copy2},
1603+
{"BGR;24", "BGR;24", 24, copy3},
1604+
15951605
/* true colour w. alpha */
15961606
{"RGBA", "LA", 16, unpackRGBALA},
15971607
{"RGBA", "LA;16B", 32, unpackRGBALA16B},

0 commit comments

Comments
 (0)