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/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/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() 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); diff --git a/libImaging/Convert.c b/libImaging/Convert.c index 0ec5ef864..bd136dede 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 8a0fcc004..4bde9c0d7 100644 --- a/libImaging/Pack.c +++ b/libImaging/Pack.c @@ -554,6 +554,8 @@ static struct { {"RGBa", "RGBa", 32, copy4}, {"RGBa", "BGRa", 32, ImagingPackBGRA}, {"RGBa", "aBGR", 32, ImagingPackABGR}, + {"BGRa", "BGRa", 32, copy4}, + {"BGRa", "RGBa", 32, ImagingPackBGRA}, /* true colour w. padding */ {"RGBX", "RGBX", 32, copy4}, diff --git a/libImaging/Storage.c b/libImaging/Storage.c index 27661bfdb..92f251cfa 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 dfc8a4d7e..54d7facbb 100644 --- a/libImaging/Unpack.c +++ b/libImaging/Unpack.c @@ -1251,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},