diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index a66bf9708..09c6214cc 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -63,9 +63,13 @@ def get_pack_parameters() -> UnPackParamTypes: # Mode RGB params += [ + ("RGB", "XRGB;1555", b"\x00\x86\x01\x8c", [(8, 131, 0), (24, 0, 8)]), + ("RGB", "RGB;565", b"\x00\n\x00\x1c", [(8, 64, 0), (24, 129, 0)]), ("RGB", "RGB", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), ("RGB", "RGBX", b"\x01\x02\x03\xff\x05\x06\x07\xff", [(1, 2, 3), (5, 6, 7)]), ("RGB", "XRGB", b"\x00\x02\x03\x04\x00\x06\x07\x08", [(2, 3, 4), (6, 7, 8)]), + ("RGB", "XBGR;1555", b"\x00\x86\x01\x8c", [(0, 131, 8), (8, 0, 24)]), + ("RGB", "BGR;565", b"\x00\n\x00\x1c", [(0, 64, 8), (0, 129, 24)]), ("RGB", "BGR", 3, [(3, 2, 1), (6, 5, 4), (9, 8, 7)]), ("RGB", "BGRX", b"\x01\x02\x03\x00\x05\x06\x07\x00", [(3, 2, 1), (7, 6, 5)]), ("RGB", "XBGR", b"\x00\x02\x03\x04\x00\x06\x07\x08", [(4, 3, 2), (8, 7, 6)]), @@ -322,10 +326,19 @@ def get_unpack_parameters() -> UnPackParamTypes: ("RGB", "RGB;16B", 6, [(1, 3, 5), (7, 9, 11)]), ("RGB", "BGR", 3, [(3, 2, 1), (6, 5, 4), (9, 8, 7)]), ("RGB", "RGB;15", 2, [(8, 131, 0), (24, 0, 8)]), + ("RGB", "XRGB;1555", 2, [(0, 132, 8), (8, 0, 24)]), + ("RGB", "ARGB;1555", 2, [(0, 132, 8), (8, 0, 24)]), + ("RGB", "ARGB;1555Z", 2, [(0, 132, 8), (8, 0, 24)]), ("RGB", "BGR;15", 2, [(0, 131, 8), (8, 0, 24)]), + ("RGB", "XBGR;1555", 2, [(8, 132, 0), (24, 0, 8)]), + ("RGB", "ABGR;1555", 2, [(8, 132, 0), (24, 0, 8)]), ("RGB", "RGB;16", 2, [(8, 64, 0), (24, 129, 0)]), + ("RGB", "RGB;565", 2, [(0, 65, 8), (0, 130, 24)]), ("RGB", "BGR;16", 2, [(0, 64, 8), (0, 129, 24)]), + ("RGB", "BGR;565", 2, [(8, 65, 0), (24, 130, 0)]), ("RGB", "RGB;4B", 2, [(17, 0, 34), (51, 0, 68)]), + ("RGB", "XBGR;4", 2, [(17, 0, 34), (51, 0, 68)]), + ("RGB", "ABGR;4", 2, [(17, 0, 34), (51, 0, 68)]), ("RGB", "RGBX", 4, [(1, 2, 3), (5, 6, 7), (9, 10, 11)]), ("RGB", "RGBX;L", 4, [(1, 4, 7), (2, 5, 8), (3, 6, 9)]), ("RGB", "BGRX", 4, [(3, 2, 1), (7, 6, 5), (11, 10, 9)]), @@ -481,8 +494,12 @@ def get_unpack_parameters() -> UnPackParamTypes: ), ("RGBA", "RGBA;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), ("RGBA", "RGBA;15", 2, [(8, 131, 0, 0), (24, 0, 8, 0)]), + ("RGBA", "ARGB;1555", 2, [(0, 132, 8, 0), (8, 0, 24, 0)]), + ("RGBA", "ARGB;1555Z", 2, [(0, 132, 8, X), (8, 0, 24, X)]), ("RGBA", "BGRA;15", 2, [(0, 131, 8, 0), (8, 0, 24, 0)]), + ("RGBA", "ABGR;1555", 2, [(8, 132, 0, 0), (24, 0, 8, 0)]), ("RGBA", "RGBA;4B", 2, [(17, 0, 34, 0), (51, 0, 68, 0)]), + ("RGBA", "ABGR;4", 2, [(17, 0, 34, 0), (51, 0, 68, 0)]), ("RGBA", "RGBA;16L", 8, [(2, 4, 6, 8), (10, 12, 14, 16)]), ("RGBA", "RGBA;16B", 8, [(1, 3, 5, 7), (9, 11, 13, 15)]), ("RGBA", "BGRA;16L", 8, [(6, 4, 2, 8), (14, 12, 10, 16)]), @@ -545,8 +562,13 @@ def get_unpack_parameters() -> UnPackParamTypes: ("RGBX", "RGB;16B", 6, [(1, 3, 5, X), (7, 9, 11, X)]), ("RGBX", "BGR", 3, [(3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)]), ("RGBX", "RGB;15", 2, [(8, 131, 0, X), (24, 0, 8, X)]), + ("RGBX", "XRGB;1555", 2, [(0, 132, 8, X), (8, 0, 24, X)]), + ("RGBX", "RGB;565", 2, [(0, 65, 8, X), (0, 130, 24, X)]), ("RGBX", "BGR;15", 2, [(0, 131, 8, X), (8, 0, 24, X)]), + ("RGBX", "XBGR;1555", 2, [(8, 132, 0, X), (24, 0, 8, X)]), + ("RGBX", "BGR;565", 2, [(8, 65, 0, X), (24, 130, 0, X)]), ("RGBX", "RGB;4B", 2, [(17, 0, 34, X), (51, 0, 68, X)]), + ("RGBX", "XBGR;4", 2, [(17, 0, 34, X), (51, 0, 68, X)]), ("RGBX", "RGBX", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), ("RGBX", "RGBXX", 5, [(1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)]), ("RGBX", "RGBXXX", 6, [(1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)]), diff --git a/src/libImaging/Pack.c b/src/libImaging/Pack.c index c29473d90..79076c2e8 100644 --- a/src/libImaging/Pack.c +++ b/src/libImaging/Pack.c @@ -254,6 +254,30 @@ packLAL(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +ImagingPackXRGB1555(UINT8 *out, const UINT8 *in, int pixels) { + for (int i = 0; i < pixels; out += 2, in += 4, i++) { + /* XRGB, 1/5/5/5 bits per pixel, little-endian */ + const UINT8 r = in[0] >> 3; + const UINT8 g = in[1] >> 3; + const UINT8 b = in[2] >> 3; + out[1] = 0x80 | (r << 2) | (g >> 3); + out[0] = (g << 5) | b; + } +} + +static void +ImagingPackRGB565(UINT8 *out, const UINT8 *in, int pixels) { + for (int i = 0; i < pixels; out += 2, in += 4, i++) { + /* RGB, 5/6/5 bits per pixel, little-endian */ + const UINT8 r = in[0] >> 3; + const UINT8 g = in[1] >> 2; + const UINT8 b = in[2] >> 3; + out[1] = (r << 3) | (g >> 3); + out[0] = (g << 5) | b; + } +} + void ImagingPackRGB(UINT8 *out, const UINT8 *in, int pixels) { int i = 0; @@ -284,6 +308,30 @@ ImagingPackXRGB(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +ImagingPackXBGR1555(UINT8 *out, const UINT8 *in, int pixels) { + for (int i = 0; i < pixels; out += 2, in += 4, i++) { + /* XBGR, 1/5/5/5 bits per pixel, little-endian */ + const UINT8 r = in[0] >> 3; + const UINT8 g = in[1] >> 3; + const UINT8 b = in[2] >> 3; + out[1] = 0x80 | (b << 2) | (g >> 3); + out[0] = (g << 5) | r; + } +} + +static void +ImagingPackBGR565(UINT8 *out, const UINT8 *in, int pixels) { + for (int i = 0; i < pixels; out += 2, in += 4, i++) { + /* BGR, 5/6/5 bits per pixel, little-endian */ + const UINT8 r = in[0] >> 3; + const UINT8 g = in[1] >> 2; + const UINT8 b = in[2] >> 3; + out[1] = (b << 3) | (g >> 3); + out[0] = (g << 5) | r; + } +} + void ImagingPackBGR(UINT8 *out, const UINT8 *in, int pixels) { int i; @@ -561,10 +609,14 @@ static struct { {"PA", "PA;L", 16, packLAL}, /* true colour */ + {"RGB", "XRGB;1555", 16, ImagingPackXRGB1555}, + {"RGB", "RGB;565", 16, ImagingPackRGB565}, {"RGB", "RGB", 24, ImagingPackRGB}, {"RGB", "RGBX", 32, copy4}, {"RGB", "RGBA", 32, copy4}, {"RGB", "XRGB", 32, ImagingPackXRGB}, + {"RGB", "XBGR;1555", 16, ImagingPackXBGR1555}, + {"RGB", "BGR;565", 16, ImagingPackBGR565}, {"RGB", "BGR", 24, ImagingPackBGR}, {"RGB", "BGRX", 32, ImagingPackBGRX}, {"RGB", "XBGR", 32, ImagingPackXBGR}, diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index c23d5d889..fbd01b62f 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -764,10 +764,129 @@ ImagingUnpackBGR16(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +ImagingUnpackXRGB1555(UINT8 *out, const UINT8 *in, const int pixels) { + /* XRGB, 1/5/5/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 r = (pixel >> 10) & 31; + const UINT8 g = (pixel >> 5) & 31; + const UINT8 b = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 3) | (g >> 2); + out[B] = (b << 3) | (b >> 2); + out[A] = 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackARGB1555(UINT8 *out, const UINT8 *in, const int pixels) { + /* ARGB, 1/5/5/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 r = (pixel >> 10) & 31; + const UINT8 g = (pixel >> 5) & 31; + const UINT8 b = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 3) | (g >> 2); + out[B] = (b << 3) | (b >> 2); + out[A] = (pixel >> 15) * 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackARGB1555Z(UINT8 *out, const UINT8 *in, const int pixels) { + /* ARGB, 1/5/5/5 bits per pixel, little-endian, inverted alpha */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 r = (pixel >> 10) & 31; + const UINT8 g = (pixel >> 5) & 31; + const UINT8 b = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 3) | (g >> 2); + out[B] = (b << 3) | (b >> 2); + out[A] = ~((pixel >> 15) * 255); + out += 4; + in += 2; + } +} + +static void +ImagingUnpackXBGR1555(UINT8 *out, const UINT8 *in, const int pixels) { + /* XBGR, 1/5/5/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 b = (pixel >> 10) & 31; + const UINT8 g = (pixel >> 5) & 31; + const UINT8 r = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 3) | (g >> 2); + out[B] = (b << 3) | (b >> 2); + out[A] = 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackABGR1555(UINT8 *out, const UINT8 *in, const int pixels) { + /* ABGR, 1/5/5/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 b = (pixel >> 10) & 31; + const UINT8 g = (pixel >> 5) & 31; + const UINT8 r = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 3) | (g >> 2); + out[B] = (b << 3) | (b >> 2); + out[A] = (pixel >> 15) * 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackRGB565(UINT8 *out, const UINT8 *in, const int pixels) { + /* RGB, 5/6/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 r = (pixel >> 11) & 31; + const UINT8 g = (pixel >> 5) & 63; + const UINT8 b = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 2) | (g >> 4); + out[B] = (b << 3) | (b >> 2); + out[A] = 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackBGR565(UINT8 *out, const UINT8 *in, const int pixels) { + /* BGR, 5/6/5 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT16 pixel = ((UINT16)in[1] << 8) | in[0]; + const UINT8 b = (pixel >> 11) & 31; + const UINT8 g = (pixel >> 5) & 63; + const UINT8 r = pixel & 31; + out[R] = (r << 3) | (r >> 2); + out[G] = (g << 2) | (g >> 4); + out[B] = (b << 3) | (b >> 2); + out[A] = 255; + out += 4; + in += 2; + } +} + void ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; - /* RGB, 4 bits per pixel */ + /* RGB, 4 bits per pixel, little-endian */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 15) * 17; @@ -782,7 +901,7 @@ ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) { void ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) { int i, pixel; - /* RGBA, 4 bits per pixel */ + /* RGBA, 4 bits per pixel, little-endian */ for (i = 0; i < pixels; i++) { pixel = in[0] + (in[1] << 8); out[R] = (pixel & 15) * 17; @@ -794,6 +913,39 @@ ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) { } } +static void +ImagingUnpackXBGR4(UINT8 *out, const UINT8 *in, const int pixels) { + /* XBGR, 4 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT8 b = in[1] & 0x0F; + const UINT8 g = in[0] & 0xF0; + const UINT8 r = in[0] & 0x0F; + out[R] = (r << 4) | r; + out[G] = g | (g >> 4); + out[B] = (b << 4) | b; + out[A] = 255; + out += 4; + in += 2; + } +} + +static void +ImagingUnpackABGR4(UINT8 *out, const UINT8 *in, const int pixels) { + /* ABGR, 4 bits per pixel, little-endian */ + for (int i = 0; i < pixels; i++) { + const UINT8 a = in[1] & 0xF0; + const UINT8 b = in[1] & 0x0F; + const UINT8 g = in[0] & 0xF0; + const UINT8 r = in[0] & 0x0F; + out[R] = (r << 4) | r; + out[G] = g | (g >> 4); + out[B] = (b << 4) | b; + out[A] = a | (a >> 4); + out += 4; + in += 2; + } +} + static void ImagingUnpackBGRX(UINT8 *_out, const UINT8 *in, int pixels) { int i; @@ -1620,13 +1772,22 @@ static struct { {"RGB", "RGB;16B", 48, unpackRGB16B}, {"RGB", "BGR", 24, ImagingUnpackBGR}, {"RGB", "RGB;15", 16, ImagingUnpackRGB15}, + {"RGB", "XRGB;1555", 16, ImagingUnpackXRGB1555}, + {"RGB", "ARGB;1555", 16, ImagingUnpackARGB1555}, + {"RGB", "ARGB;1555Z", 16, ImagingUnpackARGB1555Z}, {"RGB", "BGR;15", 16, ImagingUnpackBGR15}, + {"RGB", "XBGR;1555", 16, ImagingUnpackXBGR1555}, + {"RGB", "ABGR;1555", 16, ImagingUnpackABGR1555}, {"RGB", "RGB;16", 16, ImagingUnpackRGB16}, + {"RGB", "RGB;565", 16, ImagingUnpackRGB565}, {"RGB", "BGR;16", 16, ImagingUnpackBGR16}, + {"RGB", "BGR;565", 16, ImagingUnpackBGR565}, + {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGB", "XBGR;4", 16, ImagingUnpackXBGR4}, + {"RGB", "ABGR;4", 16, ImagingUnpackABGR4}, + {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ {"RGB", "RGBX;16L", 64, unpackRGBA16L}, {"RGB", "RGBX;16B", 64, unpackRGBA16B}, - {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B}, - {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ {"RGB", "RGBX", 32, copy4}, {"RGB", "RGBX;L", 32, unpackRGBAL}, {"RGB", "RGBXX", 40, copy4skip1}, @@ -1656,6 +1817,9 @@ static struct { /* true colour w. alpha */ {"RGBA", "LA", 16, unpackRGBALA}, {"RGBA", "LA;16B", 32, unpackRGBALA16B}, + {"RGBA", "ARGB;1555", 16, ImagingUnpackARGB1555}, + {"RGBA", "ARGB;1555Z", 16, ImagingUnpackARGB1555Z}, + {"RGBA", "ABGR;1555", 16, ImagingUnpackABGR1555}, {"RGBA", "RGBA", 32, copy4}, {"RGBA", "RGBAX", 40, copy4skip1}, {"RGBA", "RGBAXX", 48, copy4skip2}, @@ -1671,6 +1835,7 @@ static struct { {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15}, {"RGBA", "BGRA;15Z", 16, ImagingUnpackBGRA15Z}, {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B}, + {"RGBA", "ABGR;4", 16, ImagingUnpackABGR4}, {"RGBA", "RGBA;16L", 64, unpackRGBA16L}, {"RGBA", "RGBA;16B", 64, unpackRGBA16B}, {"RGBA", "BGRA", 32, unpackBGRA}, @@ -1733,8 +1898,13 @@ static struct { {"RGBX", "RGB;16B", 48, unpackRGB16B}, {"RGBX", "BGR", 24, ImagingUnpackBGR}, {"RGBX", "RGB;15", 16, ImagingUnpackRGB15}, + {"RGBX", "XRGB;1555", 16, ImagingUnpackXRGB1555}, + {"RGBX", "RGB;565", 16, ImagingUnpackRGB565}, {"RGBX", "BGR;15", 16, ImagingUnpackBGR15}, + {"RGBX", "XBGR;1555", 16, ImagingUnpackXBGR1555}, + {"RGBX", "BGR;565", 16, ImagingUnpackBGR565}, {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGBX", "XBGR;4", 16, ImagingUnpackXBGR4}, {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ {"RGBX", "RGBX", 32, copy4}, {"RGBX", "RGBXX", 40, copy4skip1},