mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-05-29 18:23:24 +03:00
Merge pull request #7303 from radarhere/bgr
Support BGR;15, BGR;16 and BGR;24 access, unpacking and putdata
This commit is contained in:
commit
24d711bd38
|
@ -130,9 +130,16 @@ class TestImageGetPixel(AccessTest):
|
||||||
bands = Image.getmodebands(mode)
|
bands = Image.getmodebands(mode)
|
||||||
if bands == 1:
|
if bands == 1:
|
||||||
return 1
|
return 1
|
||||||
|
if mode in ("BGR;15", "BGR;16"):
|
||||||
|
# These modes have less than 8 bits per band
|
||||||
|
# So (1, 2, 3) cannot be roundtripped
|
||||||
|
return (16, 32, 49)
|
||||||
return tuple(range(1, bands + 1))
|
return tuple(range(1, bands + 1))
|
||||||
|
|
||||||
def check(self, mode, expected_color=None):
|
def check(self, mode, expected_color=None):
|
||||||
|
if self._need_cffi_access and mode.startswith("BGR;"):
|
||||||
|
pytest.skip("Support not added to deprecated module for BGR;* modes")
|
||||||
|
|
||||||
if not expected_color:
|
if not expected_color:
|
||||||
expected_color = self.color(mode)
|
expected_color = self.color(mode)
|
||||||
|
|
||||||
|
@ -203,6 +210,9 @@ class TestImageGetPixel(AccessTest):
|
||||||
"F",
|
"F",
|
||||||
"P",
|
"P",
|
||||||
"PA",
|
"PA",
|
||||||
|
"BGR;15",
|
||||||
|
"BGR;16",
|
||||||
|
"BGR;24",
|
||||||
"RGB",
|
"RGB",
|
||||||
"RGBA",
|
"RGBA",
|
||||||
"RGBX",
|
"RGBX",
|
||||||
|
|
|
@ -76,6 +76,15 @@ def test_mode_F():
|
||||||
assert list(im.getdata()) == target
|
assert list(im.getdata()) == target
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("mode", ("BGR;15", "BGR;16", "BGR;24"))
|
||||||
|
def test_mode_BGR(mode):
|
||||||
|
data = [(16, 32, 49), (32, 32, 98)]
|
||||||
|
im = Image.new(mode, (1, 2))
|
||||||
|
im.putdata(data)
|
||||||
|
|
||||||
|
assert list(im.getdata()) == data
|
||||||
|
|
||||||
|
|
||||||
def test_array_B():
|
def test_array_B():
|
||||||
# shouldn't segfault
|
# shouldn't segfault
|
||||||
# see https://github.com/python-pillow/Pillow/issues/1008
|
# see https://github.com/python-pillow/Pillow/issues/1008
|
||||||
|
|
|
@ -344,6 +344,13 @@ class TestLibUnpack:
|
||||||
"RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233)
|
"RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_BGR(self):
|
||||||
|
self.assert_unpack("BGR;15", "BGR;15", 3, (8, 131, 0), (24, 0, 8), (41, 131, 8))
|
||||||
|
self.assert_unpack(
|
||||||
|
"BGR;16", "BGR;16", 3, (8, 64, 0), (24, 129, 0), (41, 194, 0)
|
||||||
|
)
|
||||||
|
self.assert_unpack("BGR;24", "BGR;24", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9))
|
||||||
|
|
||||||
def test_RGBA(self):
|
def test_RGBA(self):
|
||||||
self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
|
self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6))
|
||||||
self.assert_unpack(
|
self.assert_unpack(
|
||||||
|
|
|
@ -475,8 +475,10 @@ getpixel(Imaging im, ImagingAccess access, int x, int y) {
|
||||||
case IMAGING_TYPE_FLOAT32:
|
case IMAGING_TYPE_FLOAT32:
|
||||||
return PyFloat_FromDouble(pixel.f);
|
return PyFloat_FromDouble(pixel.f);
|
||||||
case IMAGING_TYPE_SPECIAL:
|
case IMAGING_TYPE_SPECIAL:
|
||||||
if (strncmp(im->mode, "I;16", 4) == 0) {
|
if (im->bands == 1) {
|
||||||
return PyLong_FromLong(pixel.h);
|
return PyLong_FromLong(pixel.h);
|
||||||
|
} else {
|
||||||
|
return Py_BuildValue("BBB", pixel.b[0], pixel.b[1], pixel.b[2]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -599,7 +601,7 @@ getink(PyObject *color, Imaging im, char *ink) {
|
||||||
} else if (tupleSize != 3) {
|
} else if (tupleSize != 3) {
|
||||||
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or three elements");
|
PyErr_SetString(PyExc_TypeError, "color must be int, or tuple of one or three elements");
|
||||||
return NULL;
|
return NULL;
|
||||||
} else if (!PyArg_ParseTuple(color, "Lii", &r, &g, &b)) {
|
} else if (!PyArg_ParseTuple(color, "iiL", &b, &g, &r)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!strcmp(im->mode, "BGR;15")) {
|
if (!strcmp(im->mode, "BGR;15")) {
|
||||||
|
@ -1571,21 +1573,46 @@ if (PySequence_Check(op)) { \
|
||||||
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
PyErr_SetString(PyExc_TypeError, must_be_sequence);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int endian = strncmp(image->mode, "I;16", 4) == 0 ? (strcmp(image->mode, "I;16B") == 0 ? 2 : 1) : 0;
|
|
||||||
double value;
|
double value;
|
||||||
for (i = x = y = 0; i < n; i++) {
|
if (image->bands == 1) {
|
||||||
set_value_to_item(seq, i);
|
int bigendian;
|
||||||
if (scale != 1.0 || offset != 0.0) {
|
if (image->type == IMAGING_TYPE_SPECIAL) {
|
||||||
value = value * scale + offset;
|
// I;16*
|
||||||
|
bigendian = strcmp(image->mode, "I;16B") == 0;
|
||||||
}
|
}
|
||||||
if (endian == 0) {
|
for (i = x = y = 0; i < n; i++) {
|
||||||
image->image8[y][x] = (UINT8)CLIP8(value);
|
set_value_to_item(seq, i);
|
||||||
} else {
|
if (scale != 1.0 || offset != 0.0) {
|
||||||
image->image8[y][x * 2 + (endian == 2 ? 1 : 0)] = CLIP8((int)value % 256);
|
value = value * scale + offset;
|
||||||
image->image8[y][x * 2 + (endian == 2 ? 0 : 1)] = CLIP8((int)value >> 8);
|
}
|
||||||
|
if (image->type == IMAGING_TYPE_SPECIAL) {
|
||||||
|
image->image8[y][x * 2 + (bigendian ? 1 : 0)] = CLIP8((int)value % 256);
|
||||||
|
image->image8[y][x * 2 + (bigendian ? 0 : 1)] = CLIP8((int)value >> 8);
|
||||||
|
} else {
|
||||||
|
image->image8[y][x] = (UINT8)CLIP8(value);
|
||||||
|
}
|
||||||
|
if (++x >= (int)image->xsize) {
|
||||||
|
x = 0, y++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (++x >= (int)image->xsize) {
|
} else {
|
||||||
x = 0, y++;
|
// BGR;*
|
||||||
|
int b;
|
||||||
|
for (i = x = y = 0; i < n; i++) {
|
||||||
|
char ink[4];
|
||||||
|
|
||||||
|
op = PySequence_Fast_GET_ITEM(seq, i);
|
||||||
|
if (!op || !getink(op, image, ink)) {
|
||||||
|
Py_DECREF(seq);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* FIXME: what about scale and offset? */
|
||||||
|
for (b = 0; b < image->pixelsize; b++) {
|
||||||
|
image->image8[y][x * image->pixelsize + b] = ink[b];
|
||||||
|
}
|
||||||
|
if (++x >= (int)image->xsize) {
|
||||||
|
x = 0, y++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PyErr_Clear(); /* Avoid weird exceptions */
|
PyErr_Clear(); /* Avoid weird exceptions */
|
||||||
|
|
|
@ -12,8 +12,8 @@
|
||||||
#include "Imaging.h"
|
#include "Imaging.h"
|
||||||
|
|
||||||
/* use make_hash.py from the pillow-scripts repository to calculate these values */
|
/* use make_hash.py from the pillow-scripts repository to calculate these values */
|
||||||
#define ACCESS_TABLE_SIZE 27
|
#define ACCESS_TABLE_SIZE 35
|
||||||
#define ACCESS_TABLE_HASH 33051
|
#define ACCESS_TABLE_HASH 8940
|
||||||
|
|
||||||
static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
|
static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE];
|
||||||
|
|
||||||
|
@ -87,6 +87,31 @@ get_pixel_16(Imaging im, int x, int y, void *color) {
|
||||||
memcpy(color, in, sizeof(UINT16));
|
memcpy(color, in, sizeof(UINT16));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_pixel_BGR15(Imaging im, int x, int y, void *color) {
|
||||||
|
UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
|
||||||
|
UINT16 pixel = in[0] + (in[1] << 8);
|
||||||
|
char *out = color;
|
||||||
|
out[0] = (pixel & 31) * 255 / 31;
|
||||||
|
out[1] = ((pixel >> 5) & 31) * 255 / 31;
|
||||||
|
out[2] = ((pixel >> 10) & 31) * 255 / 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_pixel_BGR16(Imaging im, int x, int y, void *color) {
|
||||||
|
UINT8 *in = (UINT8 *)&im->image8[y][x * 2];
|
||||||
|
UINT16 pixel = in[0] + (in[1] << 8);
|
||||||
|
char *out = color;
|
||||||
|
out[0] = (pixel & 31) * 255 / 31;
|
||||||
|
out[1] = ((pixel >> 5) & 63) * 255 / 63;
|
||||||
|
out[2] = ((pixel >> 11) & 31) * 255 / 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_pixel_BGR24(Imaging im, int x, int y, void *color) {
|
||||||
|
memcpy(color, &im->image8[y][x * 3], sizeof(UINT8) * 3);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_pixel_32(Imaging im, int x, int y, void *color) {
|
get_pixel_32(Imaging im, int x, int y, void *color) {
|
||||||
memcpy(color, &im->image32[y][x], sizeof(INT32));
|
memcpy(color, &im->image32[y][x], sizeof(INT32));
|
||||||
|
@ -134,6 +159,16 @@ put_pixel_16B(Imaging im, int x, int y, const void *color) {
|
||||||
out[1] = in[0];
|
out[1] = in[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_pixel_BGR1516(Imaging im, int x, int y, const void *color) {
|
||||||
|
memcpy(&im->image8[y][x * 2], color, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
put_pixel_BGR24(Imaging im, int x, int y, const void *color) {
|
||||||
|
memcpy(&im->image8[y][x * 3], color, 3);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
put_pixel_32L(Imaging im, int x, int y, const void *color) {
|
put_pixel_32L(Imaging im, int x, int y, const void *color) {
|
||||||
memcpy(&im->image8[y][x * 4], color, 4);
|
memcpy(&im->image8[y][x * 4], color, 4);
|
||||||
|
@ -178,6 +213,9 @@ ImagingAccessInit() {
|
||||||
ADD("F", get_pixel_32, put_pixel_32);
|
ADD("F", get_pixel_32, put_pixel_32);
|
||||||
ADD("P", get_pixel_8, put_pixel_8);
|
ADD("P", get_pixel_8, put_pixel_8);
|
||||||
ADD("PA", get_pixel_32_2bands, put_pixel_32);
|
ADD("PA", get_pixel_32_2bands, put_pixel_32);
|
||||||
|
ADD("BGR;15", get_pixel_BGR15, put_pixel_BGR1516);
|
||||||
|
ADD("BGR;16", get_pixel_BGR16, put_pixel_BGR1516);
|
||||||
|
ADD("BGR;24", get_pixel_BGR24, put_pixel_BGR24);
|
||||||
ADD("RGB", get_pixel_32, put_pixel_32);
|
ADD("RGB", get_pixel_32, put_pixel_32);
|
||||||
ADD("RGBA", get_pixel_32, put_pixel_32);
|
ADD("RGBA", get_pixel_32, put_pixel_32);
|
||||||
ADD("RGBa", get_pixel_32, put_pixel_32);
|
ADD("RGBa", get_pixel_32, put_pixel_32);
|
||||||
|
|
|
@ -1239,6 +1239,12 @@ copy2(UINT8 *out, const UINT8 *in, int pixels) {
|
||||||
memcpy(out, in, pixels * 2);
|
memcpy(out, in, pixels * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
copy3(UINT8 *out, const UINT8 *in, int pixels) {
|
||||||
|
/* BGR;24 */
|
||||||
|
memcpy(out, in, pixels * 3);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
copy4(UINT8 *out, const UINT8 *in, int pixels) {
|
copy4(UINT8 *out, const UINT8 *in, int pixels) {
|
||||||
/* RGBA, CMYK quadruples */
|
/* RGBA, CMYK quadruples */
|
||||||
|
@ -1592,6 +1598,10 @@ static struct {
|
||||||
{"RGB", "B;16B", 16, band216B},
|
{"RGB", "B;16B", 16, band216B},
|
||||||
{"RGB", "CMYK", 32, cmyk2rgb},
|
{"RGB", "CMYK", 32, cmyk2rgb},
|
||||||
|
|
||||||
|
{"BGR;15", "BGR;15", 16, copy2},
|
||||||
|
{"BGR;16", "BGR;16", 16, copy2},
|
||||||
|
{"BGR;24", "BGR;24", 24, copy3},
|
||||||
|
|
||||||
/* true colour w. alpha */
|
/* true colour w. alpha */
|
||||||
{"RGBA", "LA", 16, unpackRGBALA},
|
{"RGBA", "LA", 16, unpackRGBALA},
|
||||||
{"RGBA", "LA;16B", 32, unpackRGBALA16B},
|
{"RGBA", "LA;16B", 32, unpackRGBALA16B},
|
||||||
|
|
Loading…
Reference in New Issue
Block a user