From 53eb33dd6d4f077c9c40a3b71d270e35727cdefd Mon Sep 17 00:00:00 2001 From: Arjen Nienhuis Date: Sat, 6 Aug 2016 10:54:58 +0200 Subject: [PATCH 1/5] Add BGRa for compatibility with cairo --- PIL/ImageMode.py | 1 + libImaging/Convert.c | 37 +++++++++++++++++++++++++++++++++++++ libImaging/Pack.c | 1 + libImaging/Storage.c | 5 +++++ libImaging/Unpack.c | 26 ++++++++++++++++++++++++++ 5 files changed, 70 insertions(+) diff --git a/PIL/ImageMode.py b/PIL/ImageMode.py index f78a8df90..44d466b0e 100644 --- a/PIL/ImageMode.py +++ b/PIL/ImageMode.py @@ -40,6 +40,7 @@ def getmode(mode): _modes[m] = ModeDescriptor(m, bands, basemode, basetype) # extra experimental modes _modes["RGBa"] = ModeDescriptor("RGBa", ("R", "G", "B", "a"), "RGB", "L") + _modes["BGRa"] = ModeDescriptor("BGRa", ("B", "G", "R", "a"), "BGR", "L") _modes["LA"] = ModeDescriptor("LA", ("L", "A"), "L", "L") _modes["La"] = ModeDescriptor("La", ("L", "a"), "L", "L") _modes["PA"] = ModeDescriptor("PA", ("P", "A"), "RGB", "L") diff --git a/libImaging/Convert.c b/libImaging/Convert.c index 9c562d4be..872460fdf 100644 --- a/libImaging/Convert.c +++ b/libImaging/Convert.c @@ -454,6 +454,21 @@ rgbA2rgba(UINT8* out, const UINT8* in, int xsize) } } +static void +rgbA2bgra(UINT8* out, const UINT8* in, int xsize) +{ + int x; + unsigned int alpha, tmp; + for (x = 0; x < xsize; x++) { + alpha = in[3]; + *out++ = MULDIV255(in[2], alpha, tmp); + *out++ = MULDIV255(in[1], alpha, tmp); + *out++ = MULDIV255(in[0], alpha, tmp); + *out++ = in[3]; + in += 4; + } +} + /* RGBa -> RGBA conversion to remove premultiplication Needed for correct transforms/resizing on RGBA images */ static void @@ -476,6 +491,26 @@ rgba2rgbA(UINT8* out, const UINT8* in, int xsize) } } +static void +bgra2rgbA(UINT8* out, const UINT8* in, int xsize) +{ + int x; + unsigned int alpha; + for (x = 0; x < xsize; x++, in+=4) { + alpha = in[3]; + if (alpha == 255 || alpha == 0) { + *out++ = in[2]; + *out++ = in[1]; + *out++ = in[0]; + } else { + *out++ = CLIP((255 * in[2]) / alpha); + *out++ = CLIP((255 * in[1]) / alpha); + *out++ = CLIP((255 * in[0]) / alpha); + } + *out++ = in[3]; + } +} + /* * Conversion of RGB + single transparent color to RGBA, * where any pixel that matches the color will have the @@ -834,11 +869,13 @@ static struct { { "RGBA", "F", rgb2f }, { "RGBA", "RGB", rgba2rgb }, { "RGBA", "RGBa", rgbA2rgba }, + { "RGBA", "BGRa", rgbA2bgra }, { "RGBA", "RGBX", rgb2rgba }, { "RGBA", "CMYK", rgb2cmyk }, { "RGBA", "YCbCr", ImagingConvertRGB2YCbCr }, { "RGBa", "RGBA", rgba2rgbA }, + { "BGRa", "RGBA", bgra2rgbA }, { "RGBX", "1", rgb2bit }, { "RGBX", "L", rgb2l }, diff --git a/libImaging/Pack.c b/libImaging/Pack.c index d83cb8284..0d84b65bf 100644 --- a/libImaging/Pack.c +++ b/libImaging/Pack.c @@ -534,6 +534,7 @@ static struct { {"RGBa", "RGBa", 32, copy4}, {"RGBa", "BGRa", 32, ImagingPackBGRA}, {"RGBa", "aBGR", 32, ImagingPackABGR}, + {"BGRa", "BGRa", 32, copy4}, /* true colour w. padding */ {"RGBX", "RGBX", 32, copy4}, diff --git a/libImaging/Storage.c b/libImaging/Storage.c index f40840671..54b6865d0 100644 --- a/libImaging/Storage.c +++ b/libImaging/Storage.c @@ -179,6 +179,11 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, im->bands = im->pixelsize = 4; im->linesize = xsize * 4; + } else if (strcmp(mode, "BGRa") == 0) { + /* 32-bit true colour images with premultiplied alpha */ + im->bands = im->pixelsize = 4; + im->linesize = xsize * 4; + } else if (strcmp(mode, "CMYK") == 0) { /* 32-bit colour separation */ im->bands = im->pixelsize = 4; diff --git a/libImaging/Unpack.c b/libImaging/Unpack.c index 702bc9f1f..c105d517f 100644 --- a/libImaging/Unpack.c +++ b/libImaging/Unpack.c @@ -747,6 +747,30 @@ unpackRGBa(UINT8* out, const UINT8* in, int pixels) } } +static void +unpackBGRa(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* premultiplied BGRA */ + for (i = 0; i < pixels; i++) { + int a = in[3]; + if (!a) + out[R] = out[G] = out[B] = out[A] = 0; + else if (a == 255) { + out[R] = in[2]; + out[G] = in[1]; + out[B] = in[0]; + out[A] = a; + } else { + out[R] = CLIP(in[2] * 255 / a); + out[G] = CLIP(in[1] * 255 / a); + out[B] = CLIP(in[0] * 255 / a); + out[A] = a; + } + out += 4; in += 4; + } +} + static void unpackRGBAI(UINT8* out, const UINT8* in, int pixels) { @@ -1206,6 +1230,7 @@ static struct { {"RGBA", "LA;16B", 32, unpackRGBALA16B}, {"RGBA", "RGBA", 32, copy4}, {"RGBA", "RGBa", 32, unpackRGBa}, + {"RGBA", "BGRa", 32, unpackBGRa}, {"RGBA", "RGBA;I", 32, unpackRGBAI}, {"RGBA", "RGBA;L", 32, unpackRGBAL}, {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15}, @@ -1226,6 +1251,7 @@ static struct { {"RGBa", "BGRa", 32, unpackBGRA}, {"RGBa", "aRGB", 32, unpackARGB}, {"RGBa", "aBGR", 32, unpackABGR}, + {"BGRa", "BGRa", 32, copy4}, /* true colour w. padding */ {"RGBX", "RGB", 24, ImagingUnpackRGB}, From 400f72cffee1085da236a243f89ccfcc3d0ce2e1 Mon Sep 17 00:00:00 2001 From: Arjen Nienhuis Date: Sun, 7 Aug 2016 02:17:16 +0200 Subject: [PATCH 2/5] Improved error message for missing packer It's not that the raw mode does not exist. There is just no direct conversion. --- encode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/encode.c b/encode.c index b08a9aa57..9a0dd2446 100644 --- a/encode.c +++ b/encode.c @@ -365,7 +365,7 @@ get_packer(ImagingEncoderObject* encoder, const char* mode, pack = ImagingFindPacker(mode, rawmode, &bits); if (!pack) { Py_DECREF(encoder); - PyErr_SetString(PyExc_SystemError, "unknown raw mode"); + PyErr_Format(PyExc_ValueError, "No packer found from %s to %s", mode, rawmode); return -1; } From 536342c17cc101a99d465b7b0debdbd5e5a3773e Mon Sep 17 00:00:00 2001 From: Arjen Nienhuis Date: Sun, 7 Aug 2016 02:20:31 +0200 Subject: [PATCH 3/5] Add packing from BGRa to RGBa --- libImaging/Pack.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libImaging/Pack.c b/libImaging/Pack.c index 0d84b65bf..00f9512f2 100644 --- a/libImaging/Pack.c +++ b/libImaging/Pack.c @@ -535,6 +535,7 @@ static struct { {"RGBa", "BGRa", 32, ImagingPackBGRA}, {"RGBa", "aBGR", 32, ImagingPackABGR}, {"BGRa", "BGRa", 32, copy4}, + {"BGRa", "RGBa", 32, ImagingPackBGRA}, /* true colour w. padding */ {"RGBX", "RGBX", 32, copy4}, From 7fb0aaad6aa993ad442720a9d4d92dd68328f157 Mon Sep 17 00:00:00 2001 From: Arjen Nienhuis Date: Sun, 7 Aug 2016 02:21:22 +0200 Subject: [PATCH 4/5] Add pixel access for BGRa --- PIL/PyAccess.py | 1 + Tests/make_hash.py | 2 +- libImaging/Access.c | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/PIL/PyAccess.py b/PIL/PyAccess.py index 8b67a8ea2..2ae881a58 100644 --- a/PIL/PyAccess.py +++ b/PIL/PyAccess.py @@ -289,6 +289,7 @@ mode_map = {'1': _PyAccess8, 'YCbCr': _PyAccess32_3, 'RGBA': _PyAccess32_4, 'RGBa': _PyAccess32_4, + 'BGRa': _PyAccess32_4, 'RGBX': _PyAccess32_4, 'CMYK': _PyAccess32_4, 'F': _PyAccessF, diff --git a/Tests/make_hash.py b/Tests/make_hash.py index 6d700addf..6581e0217 100644 --- a/Tests/make_hash.py +++ b/Tests/make_hash.py @@ -8,7 +8,7 @@ modes = [ "I", "I;16", "I;16L", "I;16B", "I;32L", "I;32B", "F", "P", "PA", - "RGB", "RGBA", "RGBa", "RGBX", + "RGB", "RGBA", "RGBa", "RGBX", "BGRa", "CMYK", "YCbCr", "LAB", "HSV", diff --git a/libImaging/Access.c b/libImaging/Access.c index 059f2aaeb..0a1413358 100644 --- a/libImaging/Access.c +++ b/libImaging/Access.c @@ -14,7 +14,7 @@ /* use Tests/make_hash.py to calculate these values */ #define ACCESS_TABLE_SIZE 27 -#define ACCESS_TABLE_HASH 3078 +#define ACCESS_TABLE_HASH 3154 static struct ImagingAccessInstance access_table[ACCESS_TABLE_SIZE]; @@ -235,6 +235,7 @@ ImagingAccessInit() ADD("RGB", line_32, get_pixel_32, put_pixel_32); ADD("RGBA", line_32, get_pixel_32, put_pixel_32); ADD("RGBa", line_32, get_pixel_32, put_pixel_32); + ADD("BGRa", line_32, get_pixel_32, put_pixel_32); ADD("RGBX", line_32, get_pixel_32, put_pixel_32); ADD("CMYK", line_32, get_pixel_32, put_pixel_32); ADD("YCbCr", line_32, get_pixel_32, put_pixel_32); From a6661a9a460041b57d71e3e2748208ffbc3e3b3b Mon Sep 17 00:00:00 2001 From: Arjen Nienhuis Date: Sun, 7 Aug 2016 02:22:06 +0200 Subject: [PATCH 5/5] Add tests for BGRa --- Tests/test_mode_bgra.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Tests/test_mode_bgra.py diff --git a/Tests/test_mode_bgra.py b/Tests/test_mode_bgra.py new file mode 100644 index 000000000..082bc5d8d --- /dev/null +++ b/Tests/test_mode_bgra.py @@ -0,0 +1,29 @@ +from helper import unittest, PillowTestCase, py3 + +from PIL import Image + + +class TestBGRa(PillowTestCase): + + def test_bgra(self): + RGBA_RED_50 = b'\xff\x00\x00\x80' # 50% red + BGRa_RED_50 = b'\x00\x00\x80\x80' # 50% red + RGBa_RED_50 = b'\x80\x00\x00\x80' # 50% red + + im = Image.frombuffer("BGRa", (1, 1), BGRa_RED_50, 'raw', "BGRa", 0, 1) + self.assertEqual(im.tobytes(), BGRa_RED_50) + self.assertEqual(im.tobytes('raw', 'RGBa'), RGBa_RED_50) + + im = Image.frombuffer("RGBA", (1, 1), BGRa_RED_50, "raw", "BGRa", 4, 1) + self.assertEqual(im.tobytes(), RGBA_RED_50) + + im = im.convert('BGRa') + self.assertEqual(im.tobytes(), BGRa_RED_50) + self.assertEqual(im.load()[0, 0], (0x00, 0x00, 0x80, 0x80)) + + im = im.convert('RGBA') + self.assertEqual(im.tobytes(), RGBA_RED_50) + self.assertEqual(im.load()[0, 0], (0xff, 0x00, 0x00, 0x80)) + +if __name__ == '__main__': + unittest.main()