From 3af0e2d9cf69b10b51924f27e58407dbce042903 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Thu, 25 Apr 2024 21:20:41 -0500 Subject: [PATCH] add "new" rawmodes for 16-bit RGB data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing 16-bit RGB rawmodes do not follow the naming convention given in Unpack.c. These new modes do follow that convention, except since these modes do not all use the same number of bits for each band, the sizes of each band are listed. Old → New RGB;15 → XBGR;1555 RGB;16 → BGR;565 BGR;5 → XRGB;1555 BGR;15 → XRGB;1555 BGR;16 → RGB;565 RGB;4B → XBGR;4 RGBA;4B → ABGR;4 RGBA;15 → ABGR;1555 BGRA;15 → ARGB;1555 BGRA;15Z → ARGB;1555Z These new rawmodes also use a slightly different conversion method. The most accurate conversion from 5 to 8 bits is "round(x * 255 / 31.0)". However, that involves floating point numbers and rounding, so it's not as fast. The current method doesn't include the rounding, allowing us to also use integer instead of floating point division. This is faster, but unfortunately not roundtrippable - when converting from 5 to 8 to 5 bits not every value stays the same. The new method is roundtrippable, even faster than the current method since it uses basic bitwise operations instead of multiplication and division, and if you compare the result to what you get with rounding and floating point numbers, it is actually more accurate. --- Tests/test_lib_pack.py | 22 +++++ src/libImaging/Pack.c | 52 ++++++++++++ src/libImaging/Unpack.c | 178 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 248 insertions(+), 4 deletions(-) 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},