From 7d5771e56d6e721a751c5413e3f1dfb5f59c10a9 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sat, 27 Apr 2024 17:44:57 -0500 Subject: [PATCH 1/9] parametrize test_lib_pack.py --- Tests/test_lib_pack.py | 1455 ++++++++++++++++++++-------------------- 1 file changed, 737 insertions(+), 718 deletions(-) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index b4a300d0c59..a66bf97087e 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -1,820 +1,839 @@ from __future__ import annotations -import sys +from typing import Union import pytest from PIL import Image -X = 255 +from .helper import is_big_endian +X = 255 -class TestLibPack: - def assert_pack( - self, - mode: str, - rawmode: str, - data: int | bytes, - *pixels: float | tuple[int, ...], - ) -> None: - """ - data - either raw bytes with data or just number of bytes in rawmode. - """ - im = Image.new(mode, (len(pixels), 1)) - for x, pixel in enumerate(pixels): - im.putpixel((x, 0), pixel) - - if isinstance(data, int): - data_len = data * len(pixels) - data = bytes(range(1, data_len + 1)) - - assert data == im.tobytes("raw", rawmode) - - def test_1(self) -> None: - self.assert_pack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X) - self.assert_pack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0) - self.assert_pack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0) - self.assert_pack("1", "1;IR", b"\x01", 0, X, X, X, X, X, X, X) - - self.assert_pack("1", "1", b"\xaa", X, 0, X, 0, X, 0, X, 0) - self.assert_pack("1", "1;I", b"\xaa", 0, X, 0, X, 0, X, 0, X) - self.assert_pack("1", "1;R", b"\xaa", 0, X, 0, X, 0, X, 0, X) - self.assert_pack("1", "1;IR", b"\xaa", X, 0, X, 0, X, 0, X, 0) - - self.assert_pack("1", "L", b"\xff\x00\x00\xff\x00\x00", X, 0, 0, X, 0, 0) - - def test_L(self) -> None: - self.assert_pack("L", "L", 1, 1, 2, 3, 4) - self.assert_pack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175) - self.assert_pack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175) - - def test_LA(self) -> None: - self.assert_pack("LA", "LA", 2, (1, 2), (3, 4), (5, 6)) - self.assert_pack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6)) - - def test_La(self) -> None: - self.assert_pack("La", "La", 2, (1, 2), (3, 4), (5, 6)) - - def test_P(self) -> None: - self.assert_pack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 255, 0, 0) - self.assert_pack("P", "P;2", b"\xe4", 3, 2, 1, 0) - self.assert_pack("P", "P;4", b"\x02\xef", 0, 2, 14, 15) - self.assert_pack("P", "P", 1, 1, 2, 3, 4) - - def test_PA(self) -> None: - self.assert_pack("PA", "PA", 2, (1, 2), (3, 4), (5, 6)) - self.assert_pack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6)) - - def test_RGB(self) -> None: - self.assert_pack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_pack( - "RGB", "RGBX", b"\x01\x02\x03\xff\x05\x06\x07\xff", (1, 2, 3), (5, 6, 7) - ) - self.assert_pack( - "RGB", "XRGB", b"\x00\x02\x03\x04\x00\x06\x07\x08", (2, 3, 4), (6, 7, 8) - ) - self.assert_pack("RGB", "BGR", 3, (3, 2, 1), (6, 5, 4), (9, 8, 7)) - self.assert_pack( - "RGB", "BGRX", b"\x01\x02\x03\x00\x05\x06\x07\x00", (3, 2, 1), (7, 6, 5) - ) - self.assert_pack( - "RGB", "XBGR", b"\x00\x02\x03\x04\x00\x06\x07\x08", (4, 3, 2), (8, 7, 6) - ) - self.assert_pack("RGB", "RGB;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_pack("RGB", "R", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) - self.assert_pack("RGB", "G", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) - self.assert_pack("RGB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) - - def test_RGBA(self) -> None: - self.assert_pack("RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack( - "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_pack("RGBA", "RGB", 3, (1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16)) - self.assert_pack("RGBA", "BGR", 3, (3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16)) - self.assert_pack("RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_pack("RGBA", "ABGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) - self.assert_pack( +UnPackParamTypes = list[ + tuple[str, str, Union[bytes, int], list[Union[float, tuple[int, ...]]]] +] + + +def get_pack_parameters() -> UnPackParamTypes: + params: UnPackParamTypes = [] + + # Mode 1 + params += [ + ("1", "1", b"\x01", [0, 0, 0, 0, 0, 0, 0, X]), + ("1", "1;I", b"\x01", [X, X, X, X, X, X, X, 0]), + ("1", "1;R", b"\x01", [X, 0, 0, 0, 0, 0, 0, 0]), + ("1", "1;IR", b"\x01", [0, X, X, X, X, X, X, X]), + ("1", "1", b"\xaa", [X, 0, X, 0, X, 0, X, 0]), + ("1", "1;I", b"\xaa", [0, X, 0, X, 0, X, 0, X]), + ("1", "1;R", b"\xaa", [0, X, 0, X, 0, X, 0, X]), + ("1", "1;IR", b"\xaa", [X, 0, X, 0, X, 0, X, 0]), + ("1", "L", b"\xff\x00\x00\xff\x00\x00", [X, 0, 0, X, 0, 0]), + ] + + # Mode L + params += [ + ("L", "L", 1, [1, 2, 3, 4]), + ("L", "L;16", b"\x00\xc6\x00\xaf", [198, 175]), + ("L", "L;16B", b"\xc6\x00\xaf\x00", [198, 175]), + ] + + # Mode LA + params += [ + ("LA", "LA", 2, [(1, 2), (3, 4), (5, 6)]), + ("LA", "LA;L", 2, [(1, 4), (2, 5), (3, 6)]), + ] + + # Mode La + params += [("La", "La", 2, [(1, 2), (3, 4), (5, 6)])] + + # Mode P + params += [ + ("P", "P;1", b"\xe4", [1, 1, 1, 0, 0, 255, 0, 0]), + ("P", "P;2", b"\xe4", [3, 2, 1, 0]), + ("P", "P;4", b"\x02\xef", [0, 2, 14, 15]), + ("P", "P", 1, [1, 2, 3, 4]), + ] + + # Mode PA + params += [ + ("PA", "PA", 2, [(1, 2), (3, 4), (5, 6)]), + ("PA", "PA;L", 2, [(1, 4), (2, 5), (3, 6)]), + ] + + # Mode RGB + params += [ + ("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", "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)]), + ("RGB", "RGB;L", 3, [(1, 4, 7), (2, 5, 8), (3, 6, 9)]), + ("RGB", "R", 1, [(1, 9, 9), (2, 9, 9), (3, 9, 9)]), + ("RGB", "G", 1, [(9, 1, 9), (9, 2, 9), (9, 3, 9)]), + ("RGB", "B", 1, [(9, 9, 1), (9, 9, 2), (9, 9, 3)]), + ] + + # Mode RGBA + params += [ + ("RGBA", "RGBA", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("RGBA", "RGBA;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), + ("RGBA", "RGB", 3, [(1, 2, 3, 14), (4, 5, 6, 15), (7, 8, 9, 16)]), + ("RGBA", "BGR", 3, [(3, 2, 1, 14), (6, 5, 4, 15), (9, 8, 7, 16)]), + ("RGBA", "BGRA", 4, [(3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)]), + ("RGBA", "ABGR", 4, [(4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)]), + ( "RGBA", "BGRa", 4, - (191, 127, 63, 4), - (223, 191, 159, 8), - (233, 212, 191, 12), - ) - self.assert_pack("RGBA", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("RGBA", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("RGBA", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) - self.assert_pack("RGBA", "A", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) - - def test_RGBa(self) -> None: - self.assert_pack("RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack("RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)) - self.assert_pack("RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)) - - def test_RGBX(self) -> None: - self.assert_pack("RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack( - "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_pack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) - self.assert_pack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) - self.assert_pack( + [(191, 127, 63, 4), (223, 191, 159, 8), (233, 212, 191, 12)], + ), + ("RGBA", "R", 1, [(1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)]), + ("RGBA", "G", 1, [(6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)]), + ("RGBA", "B", 1, [(6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)]), + ("RGBA", "A", 1, [(6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)]), + ] + + # Mode RGBa + params += [ + ("RGBa", "RGBa", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("RGBa", "BGRa", 4, [(3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)]), + ("RGBa", "aBGR", 4, [(4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)]), + ] + + # Mode RGBX + params += [ + ("RGBX", "RGBX", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("RGBX", "RGBX;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), + ("RGBX", "RGB", 3, [(1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)]), + ("RGBX", "BGR", 3, [(3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)]), + ( "RGBX", "BGRX", b"\x01\x02\x03\x00\x05\x06\x07\x00\t\n\x0b\x00", - (3, 2, 1, X), - (7, 6, 5, X), - (11, 10, 9, X), - ) - self.assert_pack( + [(3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)], + ), + ( "RGBX", "XBGR", b"\x00\x02\x03\x04\x00\x06\x07\x08\x00\n\x0b\x0c", - (4, 3, 2, X), - (8, 7, 6, X), - (12, 11, 10, X), - ) - self.assert_pack("RGBX", "R", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("RGBX", "G", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("RGBX", "B", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) - self.assert_pack("RGBX", "X", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) - - def test_CMYK(self) -> None: - self.assert_pack("CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)) - self.assert_pack( + [(4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)], + ), + ("RGBX", "R", 1, [(1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)]), + ("RGBX", "G", 1, [(6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)]), + ("RGBX", "B", 1, [(6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)]), + ("RGBX", "X", 1, [(6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)]), + ] + + # Mode CMYK + params += [ + ("CMYK", "CMYK", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ( "CMYK", "CMYK;I", 4, - (254, 253, 252, 251), - (250, 249, 248, 247), - (246, 245, 244, 243), - ) - self.assert_pack( - "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_pack("CMYK", "K", 1, (6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)) - - def test_YCbCr(self) -> None: - self.assert_pack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_pack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_pack( + [(254, 253, 252, 251), (250, 249, 248, 247), (246, 245, 244, 243)], + ), + ("CMYK", "CMYK;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), + ("CMYK", "K", 1, [(6, 7, 0, 1), (6, 7, 0, 2), (0, 7, 0, 3)]), + ] + + # Mode YCbCr + params += [ + ("YCbCr", "YCbCr", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ("YCbCr", "YCbCr;L", 3, [(1, 4, 7), (2, 5, 8), (3, 6, 9)]), + ( "YCbCr", "YCbCrX", b"\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff", - (1, 2, 3), - (5, 6, 7), - (9, 10, 11), - ) - self.assert_pack( + [(1, 2, 3), (5, 6, 7), (9, 10, 11)], + ), + ( "YCbCr", "YCbCrK", b"\x01\x02\x03\xff\x05\x06\x07\xff\t\n\x0b\xff", - (1, 2, 3), - (5, 6, 7), - (9, 10, 11), - ) - self.assert_pack("YCbCr", "Y", 1, (1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)) - self.assert_pack("YCbCr", "Cb", 1, (6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)) - self.assert_pack("YCbCr", "Cr", 1, (6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)) - - def test_LAB(self) -> None: - self.assert_pack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) - self.assert_pack("LAB", "L", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) - self.assert_pack("LAB", "A", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) - self.assert_pack("LAB", "B", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) - - def test_HSV(self) -> None: - self.assert_pack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_pack("HSV", "H", 1, (1, 9, 9), (2, 9, 9), (3, 9, 9)) - self.assert_pack("HSV", "S", 1, (9, 1, 9), (9, 2, 9), (9, 3, 9)) - self.assert_pack("HSV", "V", 1, (9, 9, 1), (9, 9, 2), (9, 9, 3)) - - def test_I(self) -> None: - self.assert_pack("I", "I;16B", 2, 0x0102, 0x0304) - self.assert_pack( - "I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", 0x01000083, -2097151999 - ) - - if sys.byteorder == "little": - self.assert_pack("I", "I", 4, 0x04030201, 0x08070605) - self.assert_pack( + [(1, 2, 3), (5, 6, 7), (9, 10, 11)], + ), + ("YCbCr", "Y", 1, [(1, 0, 8, 9), (2, 0, 8, 9), (3, 0, 8, 0)]), + ("YCbCr", "Cb", 1, [(6, 1, 8, 9), (6, 2, 8, 9), (6, 3, 8, 9)]), + ("YCbCr", "Cr", 1, [(6, 7, 1, 9), (6, 7, 2, 0), (6, 7, 3, 9)]), + ] + + # Mode LAB + params += [ + ("LAB", "LAB", 3, [(1, 130, 131), (4, 133, 134), (7, 136, 137)]), + ("LAB", "L", 1, [(1, 9, 9), (2, 9, 9), (3, 9, 9)]), + ("LAB", "A", 1, [(9, 1, 9), (9, 2, 9), (9, 3, 9)]), + ("LAB", "B", 1, [(9, 9, 1), (9, 9, 2), (9, 9, 3)]), + ] + + # Mode HSV + params += [ + ("HSV", "HSV", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ("HSV", "H", 1, [(1, 9, 9), (2, 9, 9), (3, 9, 9)]), + ("HSV", "S", 1, [(9, 1, 9), (9, 2, 9), (9, 3, 9)]), + ("HSV", "V", 1, [(9, 9, 1), (9, 9, 2), (9, 9, 3)]), + ] + + # Mode I + params += [ + ("I", "I;16B", 2, [0x0102, 0x0304]), + ("I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", [0x01000083, -2097151999]), + ] + if is_big_endian(): + params += [ + ("I", "I", 4, [0x01020304, 0x05060708]), + ( "I", "I;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - 0x01000083, - -2097151999, - ) - else: - self.assert_pack("I", "I", 4, 0x01020304, 0x05060708) - self.assert_pack( + [-2097151999, 0x01000083], + ), + ] + else: + params += [ + ("I", "I", 4, [0x04030201, 0x08070605]), + ( "I", "I;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - -2097151999, - 0x01000083, - ) - - def test_I16(self) -> None: - if sys.byteorder == "little": - self.assert_pack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605) - else: - self.assert_pack("I;16N", "I;16N", 2, 0x0102, 0x0304, 0x0506) - - def test_F_float(self) -> None: - self.assert_pack("F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34) - - if sys.byteorder == "little": - self.assert_pack("F", "F", 4, 1.539989614439558e-36, 4.063216068939723e-34) - self.assert_pack( - "F", "F;32NF", 4, 1.539989614439558e-36, 4.063216068939723e-34 - ) - else: - self.assert_pack("F", "F", 4, 2.387939260590663e-38, 6.301941157072183e-36) - self.assert_pack( - "F", "F;32NF", 4, 2.387939260590663e-38, 6.301941157072183e-36 - ) - - -class TestLibUnpack: - def assert_unpack( - self, - mode: str, - rawmode: str, - data: int | bytes, - *pixels: float | tuple[int, ...], - ) -> None: - """ - data - either raw bytes with data or just number of bytes in rawmode. - """ - if isinstance(data, int): - data_len = data * len(pixels) - data = bytes(range(1, data_len + 1)) - - im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1) - - for x, pixel in enumerate(pixels): - assert pixel == im.getpixel((x, 0)) - - def test_1(self) -> None: - self.assert_unpack("1", "1", b"\x01", 0, 0, 0, 0, 0, 0, 0, X) - self.assert_unpack("1", "1;I", b"\x01", X, X, X, X, X, X, X, 0) - self.assert_unpack("1", "1;R", b"\x01", X, 0, 0, 0, 0, 0, 0, 0) - self.assert_unpack("1", "1;IR", b"\x01", 0, X, X, X, X, X, X, X) - - self.assert_unpack("1", "1", b"\xaa", X, 0, X, 0, X, 0, X, 0) - self.assert_unpack("1", "1;I", b"\xaa", 0, X, 0, X, 0, X, 0, X) - self.assert_unpack("1", "1;R", b"\xaa", 0, X, 0, X, 0, X, 0, X) - self.assert_unpack("1", "1;IR", b"\xaa", X, 0, X, 0, X, 0, X, 0) - - self.assert_unpack("1", "1;8", b"\x00\x01\x02\xff", 0, X, X, X) - - def test_L(self) -> None: - self.assert_unpack("L", "L;2", b"\xe4", 255, 170, 85, 0) - self.assert_unpack("L", "L;2I", b"\xe4", 0, 85, 170, 255) - self.assert_unpack("L", "L;2R", b"\xe4", 0, 170, 85, 255) - self.assert_unpack("L", "L;2IR", b"\xe4", 255, 85, 170, 0) - - self.assert_unpack("L", "L;4", b"\x02\xef", 0, 34, 238, 255) - self.assert_unpack("L", "L;4I", b"\x02\xef", 255, 221, 17, 0) - self.assert_unpack("L", "L;4R", b"\x02\xef", 68, 0, 255, 119) - self.assert_unpack("L", "L;4IR", b"\x02\xef", 187, 255, 0, 136) - - self.assert_unpack("L", "L", 1, 1, 2, 3, 4) - self.assert_unpack("L", "L;I", 1, 254, 253, 252, 251) - self.assert_unpack("L", "L;R", 1, 128, 64, 192, 32) - self.assert_unpack("L", "L;16", 2, 2, 4, 6, 8) - self.assert_unpack("L", "L;16B", 2, 1, 3, 5, 7) - self.assert_unpack("L", "L;16", b"\x00\xc6\x00\xaf", 198, 175) - self.assert_unpack("L", "L;16B", b"\xc6\x00\xaf\x00", 198, 175) - - def test_LA(self) -> None: - self.assert_unpack("LA", "LA", 2, (1, 2), (3, 4), (5, 6)) - self.assert_unpack("LA", "LA;L", 2, (1, 4), (2, 5), (3, 6)) - - def test_La(self) -> None: - self.assert_unpack("La", "La", 2, (1, 2), (3, 4), (5, 6)) - - def test_P(self) -> None: - self.assert_unpack("P", "P;1", b"\xe4", 1, 1, 1, 0, 0, 1, 0, 0) - self.assert_unpack("P", "P;2", b"\xe4", 3, 2, 1, 0) + [0x01000083, -2097151999], + ), + ] + + # Mode I;16 + if is_big_endian(): + params += [("I;16N", "I;16N", 2, [0x0102, 0x0304, 0x0506])] + else: + params += [("I;16N", "I;16N", 2, [0x0201, 0x0403, 0x0605])] + + # Mode F float + params += [ + ("F", "F;32F", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ] + if is_big_endian(): + params += [ + ("F", "F", 4, [2.387939260590663e-38, 6.301941157072183e-36]), + ("F", "F;32NF", 4, [2.387939260590663e-38, 6.301941157072183e-36]), + ] + else: + params += [ + ("F", "F", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ("F", "F;32NF", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ] + + return params + + +@pytest.mark.parametrize("mode, rawmode, data, pixels", get_pack_parameters()) +def test_pack( + mode: str, rawmode: str, data: bytes | int, pixels: list[float | tuple[int, ...]] +) -> None: + """ + Test packing from {mode} to {rawmode}. + data - Either the number of bytes in a pixel of the rawmode, or a byte string. + If a number is given, bytes will be generated starting at 1. + The byte string will be compared against the pack result. + pixels - The pixels to populate the starting image with. + """ + im = Image.new(mode, (len(pixels), 1)) + for x, pixel in enumerate(pixels): + im.putpixel((x, 0), pixel) + + if isinstance(data, int): + data_len = data * len(pixels) + data = bytes(range(1, data_len + 1)) + + assert data == im.tobytes("raw", rawmode) + + +def get_unpack_parameters() -> UnPackParamTypes: + params: UnPackParamTypes = [] + + # Mode 1 + params += [ + ("1", "1", b"\x01", [0, 0, 0, 0, 0, 0, 0, X]), + ("1", "1;I", b"\x01", [X, X, X, X, X, X, X, 0]), + ("1", "1;R", b"\x01", [X, 0, 0, 0, 0, 0, 0, 0]), + ("1", "1;IR", b"\x01", [0, X, X, X, X, X, X, X]), + ("1", "1", b"\xaa", [X, 0, X, 0, X, 0, X, 0]), + ("1", "1;I", b"\xaa", [0, X, 0, X, 0, X, 0, X]), + ("1", "1;R", b"\xaa", [0, X, 0, X, 0, X, 0, X]), + ("1", "1;IR", b"\xaa", [X, 0, X, 0, X, 0, X, 0]), + ("1", "1;8", b"\x00\x01\x02\xff", [0, X, X, X]), + ] + + # Mode L + params += [ + ("L", "L;2", b"\xe4", [255, 170, 85, 0]), + ("L", "L;2I", b"\xe4", [0, 85, 170, 255]), + ("L", "L;2R", b"\xe4", [0, 170, 85, 255]), + ("L", "L;2IR", b"\xe4", [255, 85, 170, 0]), + ("L", "L;4", b"\x02\xef", [0, 34, 238, 255]), + ("L", "L;4I", b"\x02\xef", [255, 221, 17, 0]), + ("L", "L;4R", b"\x02\xef", [68, 0, 255, 119]), + ("L", "L;4IR", b"\x02\xef", [187, 255, 0, 136]), + ("L", "L", 1, [1, 2, 3, 4]), + ("L", "L;I", 1, [254, 253, 252, 251]), + ("L", "L;R", 1, [128, 64, 192, 32]), + ("L", "L;16", 2, [2, 4, 6, 8]), + ("L", "L;16B", 2, [1, 3, 5, 7]), + ("L", "L;16", b"\x00\xc6\x00\xaf", [198, 175]), + ("L", "L;16B", b"\xc6\x00\xaf\x00", [198, 175]), + ] + + # Mode LA + params += [ + ("LA", "LA", 2, [(1, 2), (3, 4), (5, 6)]), + ("LA", "LA;L", 2, [(1, 4), (2, 5), (3, 6)]), + ] + + # Mode La + params += [ + ("La", "La", 2, [(1, 2), (3, 4), (5, 6)]), + ] + + # Mode P + params += [ + ("P", "P;1", b"\xe4", [1, 1, 1, 0, 0, 1, 0, 0]), + ("P", "P;2", b"\xe4", [3, 2, 1, 0]), # erroneous? - # self.assert_unpack("P", "P;2L", b'\xe4', 1, 1, 1, 0) - self.assert_unpack("P", "P;4", b"\x02\xef", 0, 2, 14, 15) + # ("P", "P;2L", b"\xe4", [1, 1, 1, 0]), + ("P", "P;4", b"\x02\xef", [0, 2, 14, 15]), # erroneous? - # self.assert_unpack("P", "P;4L", b'\x02\xef', 2, 10, 10, 0) - self.assert_unpack("P", "P", 1, 1, 2, 3, 4) - self.assert_unpack("P", "P;R", 1, 128, 64, 192, 32) - - def test_PA(self) -> None: - self.assert_unpack("PA", "PA", 2, (1, 2), (3, 4), (5, 6)) - self.assert_unpack("PA", "PA;L", 2, (1, 4), (2, 5), (3, 6)) - - def test_RGB(self) -> None: - self.assert_unpack("RGB", "RGB", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_unpack("RGB", "RGB;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_unpack("RGB", "RGB;R", 3, (128, 64, 192), (32, 160, 96)) - self.assert_unpack("RGB", "RGB;16L", 6, (2, 4, 6), (8, 10, 12)) - self.assert_unpack("RGB", "RGB;16B", 6, (1, 3, 5), (7, 9, 11)) - self.assert_unpack("RGB", "BGR", 3, (3, 2, 1), (6, 5, 4), (9, 8, 7)) - self.assert_unpack("RGB", "RGB;15", 2, (8, 131, 0), (24, 0, 8)) - self.assert_unpack("RGB", "BGR;15", 2, (0, 131, 8), (8, 0, 24)) - self.assert_unpack("RGB", "RGB;16", 2, (8, 64, 0), (24, 129, 0)) - self.assert_unpack("RGB", "BGR;16", 2, (0, 64, 8), (0, 129, 24)) - self.assert_unpack("RGB", "RGB;4B", 2, (17, 0, 34), (51, 0, 68)) - self.assert_unpack("RGB", "RGBX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_unpack("RGB", "RGBX;L", 4, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_unpack("RGB", "BGRX", 4, (3, 2, 1), (7, 6, 5), (11, 10, 9)) - self.assert_unpack("RGB", "XRGB", 4, (2, 3, 4), (6, 7, 8), (10, 11, 12)) - self.assert_unpack("RGB", "XBGR", 4, (4, 3, 2), (8, 7, 6), (12, 11, 10)) - self.assert_unpack( + # ("P", "P;4L", b"\x02\xef", [2, 10, 10, 0]), + ("P", "P", 1, [1, 2, 3, 4]), + ("P", "P;R", 1, [128, 64, 192, 32]), + ] + + # Mode PA + params += [ + ("PA", "PA", 2, [(1, 2), (3, 4), (5, 6)]), + ("PA", "PA;L", 2, [(1, 4), (2, 5), (3, 6)]), + ] + + # Mode RGB + params += [ + ("RGB", "RGB", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ("RGB", "RGB;L", 3, [(1, 4, 7), (2, 5, 8), (3, 6, 9)]), + ("RGB", "RGB;R", 3, [(128, 64, 192), (32, 160, 96)]), + ("RGB", "RGB;16L", 6, [(2, 4, 6), (8, 10, 12)]), + ("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", "BGR;15", 2, [(0, 131, 8), (8, 0, 24)]), + ("RGB", "RGB;16", 2, [(8, 64, 0), (24, 129, 0)]), + ("RGB", "BGR;16", 2, [(0, 64, 8), (0, 129, 24)]), + ("RGB", "RGB;4B", 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)]), + ("RGB", "XRGB", 4, [(2, 3, 4), (6, 7, 8), (10, 11, 12)]), + ("RGB", "XBGR", 4, [(4, 3, 2), (8, 7, 6), (12, 11, 10)]), + ( "RGB", "YCC;P", b"D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12", # random data - (127, 102, 0), - (192, 227, 0), - (213, 255, 170), - (98, 255, 133), - ) - self.assert_unpack("RGB", "R", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) - self.assert_unpack("RGB", "G", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) - self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) - - self.assert_unpack("RGB", "R;16B", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) - self.assert_unpack("RGB", "G;16B", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) - self.assert_unpack("RGB", "B;16B", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) - - self.assert_unpack("RGB", "R;16L", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) - self.assert_unpack("RGB", "G;16L", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) - self.assert_unpack("RGB", "B;16L", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) - - if sys.byteorder == "little": - self.assert_unpack("RGB", "R;16N", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) - self.assert_unpack("RGB", "G;16N", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) - self.assert_unpack("RGB", "B;16N", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) - else: - self.assert_unpack("RGB", "R;16N", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) - self.assert_unpack("RGB", "G;16N", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) - self.assert_unpack("RGB", "B;16N", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) - - self.assert_unpack( - "RGB", "CMYK", 4, (250, 249, 248), (242, 241, 240), (234, 233, 233) - ) - - def test_BGR(self) -> None: - with pytest.warns(DeprecationWarning): - 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) -> None: - self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) - self.assert_unpack( - "RGBA", "LA;16B", 4, (1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11) - ) - self.assert_unpack( - "RGBA", "RGBA", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) - ) - self.assert_unpack( - "RGBA", "RGBAX", 5, (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14) - ) - self.assert_unpack( - "RGBA", "RGBAXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16) - ) - self.assert_unpack( + [(127, 102, 0), (192, 227, 0), (213, 255, 170), (98, 255, 133)], + ), + ("RGB", "R", 1, [(1, 0, 0), (2, 0, 0), (3, 0, 0)]), + ("RGB", "G", 1, [(0, 1, 0), (0, 2, 0), (0, 3, 0)]), + ("RGB", "B", 1, [(0, 0, 1), (0, 0, 2), (0, 0, 3)]), + ("RGB", "R;16B", 2, [(1, 0, 0), (3, 0, 0), (5, 0, 0)]), + ("RGB", "G;16B", 2, [(0, 1, 0), (0, 3, 0), (0, 5, 0)]), + ("RGB", "B;16B", 2, [(0, 0, 1), (0, 0, 3), (0, 0, 5)]), + ("RGB", "R;16L", 2, [(2, 0, 0), (4, 0, 0), (6, 0, 0)]), + ("RGB", "G;16L", 2, [(0, 2, 0), (0, 4, 0), (0, 6, 0)]), + ("RGB", "B;16L", 2, [(0, 0, 2), (0, 0, 4), (0, 0, 6)]), + ] + + if is_big_endian(): + params += [ + ("RGB", "R;16N", 2, [(1, 0, 0), (3, 0, 0), (5, 0, 0)]), + ("RGB", "G;16N", 2, [(0, 1, 0), (0, 3, 0), (0, 5, 0)]), + ("RGB", "B;16N", 2, [(0, 0, 1), (0, 0, 3), (0, 0, 5)]), + ] + else: + params += [ + ("RGB", "R;16N", 2, [(2, 0, 0), (4, 0, 0), (6, 0, 0)]), + ("RGB", "G;16N", 2, [(0, 2, 0), (0, 4, 0), (0, 6, 0)]), + ("RGB", "B;16N", 2, [(0, 0, 2), (0, 0, 4), (0, 0, 6)]), + ] + + params += [ + ("RGB", "CMYK", 4, [(250, 249, 248), (242, 241, 240), (234, 233, 233)]), + ] + + # Mode RGBA + params += [ + ("RGBA", "LA", 2, [(1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)]), + ("RGBA", "LA;16B", 4, [(1, 1, 1, 3), (5, 5, 5, 7), (9, 9, 9, 11)]), + ("RGBA", "RGBA", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("RGBA", "RGBAX", 5, [(1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)]), + ("RGBA", "RGBAXX", 6, [(1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)]), + ( "RGBA", "RGBa", 4, - (63, 127, 191, 4), - (159, 191, 223, 8), - (191, 212, 233, 12), - ) - self.assert_unpack( + [ + (63, 127, 191, 4), + (159, 191, 223, 8), + (191, 212, 233, 12), + ], + ), + ( "RGBA", "RGBa", b"\x01\x02\x03\x00\x10\x20\x30\x7f\x10\x20\x30\xff", - (0, 0, 0, 0), - (32, 64, 96, 127), - (16, 32, 48, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (32, 64, 96, 127), + (16, 32, 48, 255), + ], + ), + ( "RGBA", "RGBaX", b"\x01\x02\x03\x00-\x10\x20\x30\x7f-\x10\x20\x30\xff-", - (0, 0, 0, 0), - (32, 64, 96, 127), - (16, 32, 48, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (32, 64, 96, 127), + (16, 32, 48, 255), + ], + ), + ( "RGBA", "RGBaXX", b"\x01\x02\x03\x00==\x10\x20\x30\x7f!!\x10\x20\x30\xff??", - (0, 0, 0, 0), - (32, 64, 96, 127), - (16, 32, 48, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (32, 64, 96, 127), + (16, 32, 48, 255), + ], + ), + ( "RGBA", "RGBa;16L", 8, - (63, 127, 191, 8), - (159, 191, 223, 16), - (191, 212, 233, 24), - ) - self.assert_unpack( + [ + (63, 127, 191, 8), + (159, 191, 223, 16), + (191, 212, 233, 24), + ], + ), + ( "RGBA", "RGBa;16L", b"\x88\x01\x88\x02\x88\x03\x88\x00\x88\x10\x88\x20\x88\x30\x88\xff", - (0, 0, 0, 0), - (16, 32, 48, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (16, 32, 48, 255), + ], + ), + ( "RGBA", "RGBa;16B", 8, - (36, 109, 182, 7), - (153, 187, 221, 15), - (188, 210, 232, 23), - ) - self.assert_unpack( + [ + (36, 109, 182, 7), + (153, 187, 221, 15), + (188, 210, 232, 23), + ], + ), + ( "RGBA", "RGBa;16B", b"\x01\x88\x02\x88\x03\x88\x00\x88\x10\x88\x20\x88\x30\x88\xff\x88", - (0, 0, 0, 0), - (16, 32, 48, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (16, 32, 48, 255), + ], + ), + ( "RGBA", "BGRa", 4, - (191, 127, 63, 4), - (223, 191, 159, 8), - (233, 212, 191, 12), - ) - self.assert_unpack( + [ + (191, 127, 63, 4), + (223, 191, 159, 8), + (233, 212, 191, 12), + ], + ), + ( "RGBA", "BGRa", b"\x01\x02\x03\x00\x10\x20\x30\xff", - (0, 0, 0, 0), - (48, 32, 16, 255), - ) - self.assert_unpack( + [ + (0, 0, 0, 0), + (48, 32, 16, 255), + ], + ), + ( "RGBA", "RGBA;I", 4, - (254, 253, 252, 4), - (250, 249, 248, 8), - (246, 245, 244, 12), - ) - self.assert_unpack( - "RGBA", "RGBA;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_unpack("RGBA", "RGBA;15", 2, (8, 131, 0, 0), (24, 0, 8, 0)) - self.assert_unpack("RGBA", "BGRA;15", 2, (0, 131, 8, 0), (8, 0, 24, 0)) - self.assert_unpack("RGBA", "RGBA;4B", 2, (17, 0, 34, 0), (51, 0, 68, 0)) - self.assert_unpack("RGBA", "RGBA;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - self.assert_unpack("RGBA", "RGBA;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - self.assert_unpack("RGBA", "BGRA;16L", 8, (6, 4, 2, 8), (14, 12, 10, 16)) - self.assert_unpack("RGBA", "BGRA;16B", 8, (5, 3, 1, 7), (13, 11, 9, 15)) - self.assert_unpack( - "RGBA", "BGRA", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12) - ) - self.assert_unpack( - "RGBA", "ARGB", 4, (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9) - ) - self.assert_unpack( - "RGBA", "ABGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9) - ) - self.assert_unpack( + [ + (254, 253, 252, 4), + (250, 249, 248, 8), + (246, 245, 244, 12), + ], + ), + ("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", "BGRA;15", 2, [(0, 131, 8, 0), (8, 0, 24, 0)]), + ("RGBA", "RGBA;4B", 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)]), + ("RGBA", "BGRA;16B", 8, [(5, 3, 1, 7), (13, 11, 9, 15)]), + ("RGBA", "BGRA", 4, [(3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)]), + ("RGBA", "ARGB", 4, [(2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)]), + ("RGBA", "ABGR", 4, [(4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)]), + ( "RGBA", "YCCA;P", b"]bE\x04\xdd\xbej\xed57T\xce\xac\xce:\x11", # random data - (0, 161, 0, 4), - (255, 255, 255, 237), - (27, 158, 0, 206), - (0, 118, 0, 17), - ) - self.assert_unpack("RGBA", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("RGBA", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) - - self.assert_unpack("RGBA", "R;16B", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)) - self.assert_unpack("RGBA", "G;16B", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)) - self.assert_unpack("RGBA", "B;16B", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)) - self.assert_unpack("RGBA", "A;16B", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)) - - self.assert_unpack("RGBA", "R;16L", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)) - self.assert_unpack("RGBA", "G;16L", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)) - self.assert_unpack("RGBA", "B;16L", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)) - self.assert_unpack("RGBA", "A;16L", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)) - - if sys.byteorder == "little": - self.assert_unpack( - "RGBA", "R;16N", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0) - ) - self.assert_unpack( - "RGBA", "G;16N", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0) - ) - self.assert_unpack( - "RGBA", "B;16N", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0) - ) - self.assert_unpack( - "RGBA", "A;16N", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6) - ) - else: - self.assert_unpack( - "RGBA", "R;16N", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0) - ) - self.assert_unpack( - "RGBA", "G;16N", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0) - ) - self.assert_unpack( - "RGBA", "B;16N", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0) - ) - self.assert_unpack( - "RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5) - ) - - def test_RGBa(self) -> None: - self.assert_unpack( - "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) - ) - self.assert_unpack( - "RGBa", "BGRa", 4, (3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12) - ) - self.assert_unpack( - "RGBa", "aRGB", 4, (2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9) - ) - self.assert_unpack( - "RGBa", "aBGR", 4, (4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9) - ) - - def test_RGBX(self) -> None: - self.assert_unpack("RGBX", "RGB", 3, (1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)) - self.assert_unpack("RGBX", "RGB;L", 3, (1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)) - self.assert_unpack("RGBX", "RGB;16B", 6, (1, 3, 5, X), (7, 9, 11, X)) - self.assert_unpack("RGBX", "BGR", 3, (3, 2, 1, X), (6, 5, 4, X), (9, 8, 7, X)) - self.assert_unpack("RGBX", "RGB;15", 2, (8, 131, 0, X), (24, 0, 8, X)) - self.assert_unpack("RGBX", "BGR;15", 2, (0, 131, 8, X), (8, 0, 24, X)) - self.assert_unpack("RGBX", "RGB;4B", 2, (17, 0, 34, X), (51, 0, 68, X)) - self.assert_unpack( - "RGBX", "RGBX", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) - ) - self.assert_unpack( - "RGBX", "RGBXX", 5, (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14) - ) - self.assert_unpack( - "RGBX", "RGBXXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16) - ) - self.assert_unpack( - "RGBX", "RGBX;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_unpack("RGBX", "RGBX;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - self.assert_unpack("RGBX", "RGBX;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - self.assert_unpack( - "RGBX", "BGRX", 4, (3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X) - ) - self.assert_unpack( - "RGBX", "XRGB", 4, (2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X) - ) - self.assert_unpack( - "RGBX", "XBGR", 4, (4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X) - ) - self.assert_unpack( + [ + (0, 161, 0, 4), + (255, 255, 255, 237), + (27, 158, 0, 206), + (0, 118, 0, 17), + ], + ), + ("RGBA", "R", 1, [(1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)]), + ("RGBA", "G", 1, [(0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)]), + ("RGBA", "B", 1, [(0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)]), + ("RGBA", "A", 1, [(0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)]), + ("RGBA", "R;16B", 2, [(1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)]), + ("RGBA", "G;16B", 2, [(0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)]), + ("RGBA", "B;16B", 2, [(0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)]), + ("RGBA", "A;16B", 2, [(0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)]), + ("RGBA", "R;16L", 2, [(2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)]), + ("RGBA", "G;16L", 2, [(0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)]), + ("RGBA", "B;16L", 2, [(0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)]), + ("RGBA", "A;16L", 2, [(0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)]), + ] + + if is_big_endian(): + params += [ + ("RGBA", "R;16N", 2, [(1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)]), + ("RGBA", "G;16N", 2, [(0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)]), + ("RGBA", "B;16N", 2, [(0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)]), + ("RGBA", "A;16N", 2, [(0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)]), + ] + else: + params += [ + ("RGBA", "R;16N", 2, [(2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)]), + ("RGBA", "G;16N", 2, [(0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)]), + ("RGBA", "B;16N", 2, [(0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)]), + ("RGBA", "A;16N", 2, [(0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)]), + ] + + # Mode RGBa + params += [ + ("RGBa", "RGBa", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("RGBa", "BGRa", 4, [(3, 2, 1, 4), (7, 6, 5, 8), (11, 10, 9, 12)]), + ("RGBa", "aRGB", 4, [(2, 3, 4, 1), (6, 7, 8, 5), (10, 11, 12, 9)]), + ("RGBa", "aBGR", 4, [(4, 3, 2, 1), (8, 7, 6, 5), (12, 11, 10, 9)]), + ] + + # Mode RGBX + params += [ + ("RGBX", "RGB", 3, [(1, 2, 3, X), (4, 5, 6, X), (7, 8, 9, X)]), + ("RGBX", "RGB;L", 3, [(1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)]), + ("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", "BGR;15", 2, [(0, 131, 8, X), (8, 0, 24, X)]), + ("RGBX", "RGB;4B", 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)]), + ("RGBX", "RGBX;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), + ("RGBX", "RGBX;16L", 8, [(2, 4, 6, 8), (10, 12, 14, 16)]), + ("RGBX", "RGBX;16B", 8, [(1, 3, 5, 7), (9, 11, 13, 15)]), + ("RGBX", "BGRX", 4, [(3, 2, 1, X), (7, 6, 5, X), (11, 10, 9, X)]), + ("RGBX", "XRGB", 4, [(2, 3, 4, X), (6, 7, 8, X), (10, 11, 12, X)]), + ("RGBX", "XBGR", 4, [(4, 3, 2, X), (8, 7, 6, X), (12, 11, 10, X)]), + ( "RGBX", "YCC;P", b"D]\x9c\x82\x1a\x91\xfaOC\xe7J\x12", # random data - (127, 102, 0, X), - (192, 227, 0, X), - (213, 255, 170, X), - (98, 255, 133, X), - ) - self.assert_unpack("RGBX", "R", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("RGBX", "G", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("RGBX", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("RGBX", "X", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) - - def test_CMYK(self) -> None: - self.assert_unpack( - "CMYK", "CMYK", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) - ) - self.assert_unpack( - "CMYK", "CMYKX", 5, (1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14) - ) - self.assert_unpack( - "CMYK", "CMYKXX", 6, (1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16) - ) - self.assert_unpack( + [ + (127, 102, 0, X), + (192, 227, 0, X), + (213, 255, 170, X), + (98, 255, 133, X), + ], + ), + ("RGBX", "R", 1, [(1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)]), + ("RGBX", "G", 1, [(0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)]), + ("RGBX", "B", 1, [(0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)]), + ("RGBX", "X", 1, [(0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)]), + ] + + # Mode CMYK + params += [ + ("CMYK", "CMYK", 4, [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)]), + ("CMYK", "CMYKX", 5, [(1, 2, 3, 4), (6, 7, 8, 9), (11, 12, 13, 14)]), + ("CMYK", "CMYKXX", 6, [(1, 2, 3, 4), (7, 8, 9, 10), (13, 14, 15, 16)]), + ( "CMYK", "CMYK;I", 4, - (254, 253, 252, 251), - (250, 249, 248, 247), - (246, 245, 244, 243), - ) - self.assert_unpack( - "CMYK", "CMYK;L", 4, (1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12) - ) - self.assert_unpack("CMYK", "C", 1, (1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)) - self.assert_unpack("CMYK", "M", 1, (0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)) - self.assert_unpack("CMYK", "Y", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) - self.assert_unpack("CMYK", "K", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) - self.assert_unpack( - "CMYK", "C;I", 1, (254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0) - ) - self.assert_unpack( - "CMYK", "M;I", 1, (0, 254, 0, 0), (0, 253, 0, 0), (0, 252, 0, 0) - ) - self.assert_unpack( - "CMYK", "Y;I", 1, (0, 0, 254, 0), (0, 0, 253, 0), (0, 0, 252, 0) - ) - self.assert_unpack( - "CMYK", "K;I", 1, (0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252) - ) - - def test_YCbCr(self) -> None: - self.assert_unpack("YCbCr", "YCbCr", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_unpack("YCbCr", "YCbCr;L", 3, (1, 4, 7), (2, 5, 8), (3, 6, 9)) - self.assert_unpack("YCbCr", "YCbCrK", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) - self.assert_unpack("YCbCr", "YCbCrX", 4, (1, 2, 3), (5, 6, 7), (9, 10, 11)) - - def test_LAB(self) -> None: - self.assert_unpack("LAB", "LAB", 3, (1, 130, 131), (4, 133, 134), (7, 136, 137)) - self.assert_unpack("LAB", "L", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) - self.assert_unpack("LAB", "A", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) - self.assert_unpack("LAB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) - - def test_HSV(self) -> None: - self.assert_unpack("HSV", "HSV", 3, (1, 2, 3), (4, 5, 6), (7, 8, 9)) - self.assert_unpack("HSV", "H", 1, (1, 0, 0), (2, 0, 0), (3, 0, 0)) - self.assert_unpack("HSV", "S", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) - self.assert_unpack("HSV", "V", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) - - def test_I(self) -> None: - self.assert_unpack("I", "I;8", 1, 0x01, 0x02, 0x03, 0x04) - self.assert_unpack("I", "I;8S", b"\x01\x83", 1, -125) - self.assert_unpack("I", "I;16", 2, 0x0201, 0x0403) - self.assert_unpack("I", "I;16S", b"\x83\x01\x01\x83", 0x0183, -31999) - self.assert_unpack("I", "I;16B", 2, 0x0102, 0x0304) - self.assert_unpack("I", "I;16BS", b"\x83\x01\x01\x83", -31999, 0x0183) - self.assert_unpack("I", "I;32", 4, 0x04030201, 0x08070605) - self.assert_unpack( - "I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", 0x01000083, -2097151999 - ) - self.assert_unpack("I", "I;32B", 4, 0x01020304, 0x05060708) - self.assert_unpack( - "I", "I;32BS", b"\x83\x00\x00\x01\x01\x00\x00\x83", -2097151999, 0x01000083 - ) - - if sys.byteorder == "little": - self.assert_unpack("I", "I", 4, 0x04030201, 0x08070605) - self.assert_unpack("I", "I;16N", 2, 0x0201, 0x0403) - self.assert_unpack("I", "I;16NS", b"\x83\x01\x01\x83", 0x0183, -31999) - self.assert_unpack("I", "I;32N", 4, 0x04030201, 0x08070605) - self.assert_unpack( + [ + (254, 253, 252, 251), + (250, 249, 248, 247), + (246, 245, 244, 243), + ], + ), + ("CMYK", "CMYK;L", 4, [(1, 4, 7, 10), (2, 5, 8, 11), (3, 6, 9, 12)]), + ("CMYK", "C", 1, [(1, 0, 0, 0), (2, 0, 0, 0), (3, 0, 0, 0)]), + ("CMYK", "M", 1, [(0, 1, 0, 0), (0, 2, 0, 0), (0, 3, 0, 0)]), + ("CMYK", "Y", 1, [(0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)]), + ("CMYK", "K", 1, [(0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)]), + ("CMYK", "C;I", 1, [(254, 0, 0, 0), (253, 0, 0, 0), (252, 0, 0, 0)]), + ("CMYK", "M;I", 1, [(0, 254, 0, 0), (0, 253, 0, 0), (0, 252, 0, 0)]), + ("CMYK", "Y;I", 1, [(0, 0, 254, 0), (0, 0, 253, 0), (0, 0, 252, 0)]), + ("CMYK", "K;I", 1, [(0, 0, 0, 254), (0, 0, 0, 253), (0, 0, 0, 252)]), + ] + + # Mode YCbCr + params += [ + ("YCbCr", "YCbCr", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ("YCbCr", "YCbCr;L", 3, [(1, 4, 7), (2, 5, 8), (3, 6, 9)]), + ("YCbCr", "YCbCrK", 4, [(1, 2, 3), (5, 6, 7), (9, 10, 11)]), + ("YCbCr", "YCbCrX", 4, [(1, 2, 3), (5, 6, 7), (9, 10, 11)]), + ] + + # Mode LAB + params += [ + ("LAB", "LAB", 3, [(1, 130, 131), (4, 133, 134), (7, 136, 137)]), + ("LAB", "L", 1, [(1, 0, 0), (2, 0, 0), (3, 0, 0)]), + ("LAB", "A", 1, [(0, 1, 0), (0, 2, 0), (0, 3, 0)]), + ("LAB", "B", 1, [(0, 0, 1), (0, 0, 2), (0, 0, 3)]), + ] + + # Mode HSV + params += [ + ("HSV", "HSV", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ("HSV", "H", 1, [(1, 0, 0), (2, 0, 0), (3, 0, 0)]), + ("HSV", "S", 1, [(0, 1, 0), (0, 2, 0), (0, 3, 0)]), + ("HSV", "V", 1, [(0, 0, 1), (0, 0, 2), (0, 0, 3)]), + ] + + # Mode I + params += [ + ("I", "I;8", 1, [0x01, 0x02, 0x03, 0x04]), + ("I", "I;8S", b"\x01\x83", [1, -125]), + ("I", "I;16", 2, [0x0201, 0x0403]), + ("I", "I;16S", b"\x83\x01\x01\x83", [0x0183, -31999]), + ("I", "I;16B", 2, [0x0102, 0x0304]), + ("I", "I;16BS", b"\x83\x01\x01\x83", [-31999, 0x0183]), + ("I", "I;32", 4, [0x04030201, 0x08070605]), + ("I", "I;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", [0x01000083, -2097151999]), + ("I", "I;32B", 4, [0x01020304, 0x05060708]), + ("I", "I;32BS", b"\x83\x00\x00\x01\x01\x00\x00\x83", [-2097151999, 0x01000083]), + ] + if is_big_endian(): + params += [ + ("I", "I", 4, [0x01020304, 0x05060708]), + ("I", "I;16N", 2, [0x0102, 0x0304]), + ("I", "I;16NS", b"\x83\x01\x01\x83", [-31999, 0x0183]), + ("I", "I;32N", 4, [0x01020304, 0x05060708]), + ( "I", "I;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - 0x01000083, - -2097151999, - ) - else: - self.assert_unpack("I", "I", 4, 0x01020304, 0x05060708) - self.assert_unpack("I", "I;16N", 2, 0x0102, 0x0304) - self.assert_unpack("I", "I;16NS", b"\x83\x01\x01\x83", -31999, 0x0183) - self.assert_unpack("I", "I;32N", 4, 0x01020304, 0x05060708) - self.assert_unpack( + [ + -2097151999, + 0x01000083, + ], + ), + ] + else: + params += [ + ("I", "I", 4, [0x04030201, 0x08070605]), + ("I", "I;16N", 2, [0x0201, 0x0403]), + ("I", "I;16NS", b"\x83\x01\x01\x83", [0x0183, -31999]), + ("I", "I;32N", 4, [0x04030201, 0x08070605]), + ( "I", "I;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - -2097151999, - 0x01000083, - ) - - def test_F_int(self) -> None: - self.assert_unpack("F", "F;8", 1, 0x01, 0x02, 0x03, 0x04) - self.assert_unpack("F", "F;8S", b"\x01\x83", 1, -125) - self.assert_unpack("F", "F;16", 2, 0x0201, 0x0403) - self.assert_unpack("F", "F;16S", b"\x83\x01\x01\x83", 0x0183, -31999) - self.assert_unpack("F", "F;16B", 2, 0x0102, 0x0304) - self.assert_unpack("F", "F;16BS", b"\x83\x01\x01\x83", -31999, 0x0183) - self.assert_unpack("F", "F;32", 4, 67305984, 134678016) - self.assert_unpack( - "F", "F;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", 16777348, -2097152000 - ) - self.assert_unpack("F", "F;32B", 4, 0x01020304, 0x05060708) - self.assert_unpack( - "F", "F;32BS", b"\x83\x00\x00\x01\x01\x00\x00\x83", -2097152000, 16777348 - ) - - if sys.byteorder == "little": - self.assert_unpack("F", "F;16N", 2, 0x0201, 0x0403) - self.assert_unpack("F", "F;16NS", b"\x83\x01\x01\x83", 0x0183, -31999) - self.assert_unpack("F", "F;32N", 4, 67305984, 134678016) - self.assert_unpack( + [ + 0x01000083, + -2097151999, + ], + ), + ] + + # Mode F int + params += [ + ("F", "F;8", 1, [0x01, 0x02, 0x03, 0x04]), + ("F", "F;8S", b"\x01\x83", [1, -125]), + ("F", "F;16", 2, [0x0201, 0x0403]), + ("F", "F;16S", b"\x83\x01\x01\x83", [0x0183, -31999]), + ("F", "F;16B", 2, [0x0102, 0x0304]), + ("F", "F;16BS", b"\x83\x01\x01\x83", [-31999, 0x0183]), + ("F", "F;32", 4, [67305984, 134678016]), + ("F", "F;32S", b"\x83\x00\x00\x01\x01\x00\x00\x83", [16777348, -2097152000]), + ("F", "F;32B", 4, [0x01020304, 0x05060708]), + ("F", "F;32BS", b"\x83\x00\x00\x01\x01\x00\x00\x83", [-2097152000, 16777348]), + ] + if is_big_endian(): + params += [ + ("F", "F;16N", 2, [0x0102, 0x0304]), + ("F", "F;16NS", b"\x83\x01\x01\x83", [-31999, 0x0183]), + ("F", "F;32N", 4, [0x01020304, 0x05060708]), + ( "F", "F;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - 16777348, - -2097152000, - ) - else: - self.assert_unpack("F", "F;16N", 2, 0x0102, 0x0304) - self.assert_unpack("F", "F;16NS", b"\x83\x01\x01\x83", -31999, 0x0183) - self.assert_unpack("F", "F;32N", 4, 0x01020304, 0x05060708) - self.assert_unpack( + [-2097152000, 16777348], + ), + ] + else: + params += [ + ("F", "F;16N", 2, [0x0201, 0x0403]), + ("F", "F;16NS", b"\x83\x01\x01\x83", [0x0183, -31999]), + ("F", "F;32N", 4, [67305984, 134678016]), + ( "F", "F;32NS", b"\x83\x00\x00\x01\x01\x00\x00\x83", - -2097152000, - 16777348, - ) - - def test_F_float(self) -> None: - self.assert_unpack( - "F", "F;32F", 4, 1.539989614439558e-36, 4.063216068939723e-34 - ) - self.assert_unpack( - "F", "F;32BF", 4, 2.387939260590663e-38, 6.301941157072183e-36 - ) - self.assert_unpack( + [16777348, -2097152000], + ), + ] + + # Mode F float + params += [ + ("F", "F;32F", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ("F", "F;32BF", 4, [2.387939260590663e-38, 6.301941157072183e-36]), + ( "F", "F;64F", b"333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0", # by struct.pack - 0.15000000596046448, - -1234.5, - ) - self.assert_unpack( + [0.15000000596046448, -1234.5], + ), + ( "F", "F;64BF", b"?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00", # by struct.pack - 0.15000000596046448, - -1234.5, - ) - - if sys.byteorder == "little": - self.assert_unpack( - "F", "F", 4, 1.539989614439558e-36, 4.063216068939723e-34 - ) - self.assert_unpack( - "F", "F;32NF", 4, 1.539989614439558e-36, 4.063216068939723e-34 - ) - self.assert_unpack( + [0.15000000596046448, -1234.5], + ), + ] + if is_big_endian(): + params += [ + ("F", "F", 4, [2.387939260590663e-38, 6.301941157072183e-36]), + ("F", "F;32NF", 4, [2.387939260590663e-38, 6.301941157072183e-36]), + ( "F", "F;64NF", - b"333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0", - 0.15000000596046448, - -1234.5, - ) - else: - self.assert_unpack( - "F", "F", 4, 2.387939260590663e-38, 6.301941157072183e-36 - ) - self.assert_unpack( - "F", "F;32NF", 4, 2.387939260590663e-38, 6.301941157072183e-36 - ) - self.assert_unpack( + b"?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00", + [0.15000000596046448, -1234.5], + ), + ] + else: + params += [ + ("F", "F", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ("F", "F;32NF", 4, [1.539989614439558e-36, 4.063216068939723e-34]), + ( "F", "F;64NF", - b"?\xc3333333\xc0\x93J\x00\x00\x00\x00\x00", - 0.15000000596046448, - -1234.5, - ) - - def test_I16(self) -> None: - self.assert_unpack("I;16", "I;16", 2, 0x0201, 0x0403, 0x0605) - self.assert_unpack("I;16", "I;16B", 2, 0x0102, 0x0304, 0x0506) - self.assert_unpack("I;16B", "I;16B", 2, 0x0102, 0x0304, 0x0506) - self.assert_unpack("I;16L", "I;16L", 2, 0x0201, 0x0403, 0x0605) - self.assert_unpack("I;16", "I;12", 2, 0x0010, 0x0203, 0x0040) - if sys.byteorder == "little": - self.assert_unpack("I;16", "I;16N", 2, 0x0201, 0x0403, 0x0605) - self.assert_unpack("I;16B", "I;16N", 2, 0x0201, 0x0403, 0x0605) - self.assert_unpack("I;16L", "I;16N", 2, 0x0201, 0x0403, 0x0605) - self.assert_unpack("I;16N", "I;16N", 2, 0x0201, 0x0403, 0x0605) - else: - self.assert_unpack("I;16", "I;16N", 2, 0x0102, 0x0304, 0x0506) - self.assert_unpack("I;16B", "I;16N", 2, 0x0102, 0x0304, 0x0506) - self.assert_unpack("I;16L", "I;16N", 2, 0x0102, 0x0304, 0x0506) - self.assert_unpack("I;16N", "I;16N", 2, 0x0102, 0x0304, 0x0506) - - def test_CMYK16(self) -> None: - self.assert_unpack("CMYK", "CMYK;16L", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - self.assert_unpack("CMYK", "CMYK;16B", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - if sys.byteorder == "little": - self.assert_unpack("CMYK", "CMYK;16N", 8, (2, 4, 6, 8), (10, 12, 14, 16)) - else: - self.assert_unpack("CMYK", "CMYK;16N", 8, (1, 3, 5, 7), (9, 11, 13, 15)) - - def test_value_error(self) -> None: - with pytest.raises(ValueError): - self.assert_unpack("L", "L", 0, 0) - with pytest.raises(ValueError): - self.assert_unpack("RGB", "RGB", 2, 0) - with pytest.raises(ValueError): - self.assert_unpack("CMYK", "CMYK", 2, 0) + b"333333\xc3?\x00\x00\x00\x00\x00J\x93\xc0", + [0.15000000596046448, -1234.5], + ), + ] + + # Mode I;16 + params += [ + ("I;16", "I;16", 2, [0x0201, 0x0403, 0x0605]), + ("I;16", "I;16B", 2, [0x0102, 0x0304, 0x0506]), + ("I;16B", "I;16B", 2, [0x0102, 0x0304, 0x0506]), + ("I;16L", "I;16L", 2, [0x0201, 0x0403, 0x0605]), + ("I;16", "I;12", 2, [0x0010, 0x0203, 0x0040]), + ] + if is_big_endian(): + params += [ + ("I;16", "I;16N", 2, [0x0102, 0x0304, 0x0506]), + ("I;16B", "I;16N", 2, [0x0102, 0x0304, 0x0506]), + ("I;16L", "I;16N", 2, [0x0102, 0x0304, 0x0506]), + ("I;16N", "I;16N", 2, [0x0102, 0x0304, 0x0506]), + ] + else: + params += [ + ("I;16", "I;16N", 2, [0x0201, 0x0403, 0x0605]), + ("I;16B", "I;16N", 2, [0x0201, 0x0403, 0x0605]), + ("I;16L", "I;16N", 2, [0x0201, 0x0403, 0x0605]), + ("I;16N", "I;16N", 2, [0x0201, 0x0403, 0x0605]), + ] + + # Mode CMYK + params += [ + ("CMYK", "CMYK;16L", 8, [(2, 4, 6, 8), (10, 12, 14, 16)]), + ("CMYK", "CMYK;16B", 8, [(1, 3, 5, 7), (9, 11, 13, 15)]), + ] + if is_big_endian(): + params += [ + ("CMYK", "CMYK;16N", 8, [(1, 3, 5, 7), (9, 11, 13, 15)]), + ] + else: + params += [ + ("CMYK", "CMYK;16N", 8, [(2, 4, 6, 8), (10, 12, 14, 16)]), + ] + + return params + + +@pytest.mark.parametrize("mode, rawmode, data, pixels", get_unpack_parameters()) +def test_unpack( + mode: str, rawmode: str, data: bytes | int, pixels: list[float | tuple[int, ...]] +) -> None: + """ + Test unpacking from {rawmode} to {mode}. + data - Either the number of bytes in a pixel of the rawmode, or a byte string. + If a number is given, bytes will be generated starting at 1. + The byte string will be used to populate the starting image. + pixels - The pixels to be compared against the image pixels after unpacking. + """ + if isinstance(data, int): + data_len = data * len(pixels) + data = bytes(range(1, data_len + 1)) + + im = Image.frombytes(mode, (len(pixels), 1), data, "raw", rawmode, 0, 1) + + for x, pixel in enumerate(pixels): + assert pixel == im.getpixel((x, 0)) + + +@pytest.mark.parametrize( + "mode, rawmode, data, pixels", + ( + # Mode BGR + ("BGR;15", "BGR;15", 3, [(8, 131, 0), (24, 0, 8), (41, 131, 8)]), + ("BGR;16", "BGR;16", 3, [(8, 64, 0), (24, 129, 0), (41, 194, 0)]), + ("BGR;24", "BGR;24", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + ), +) +def test_unpack_deprecated( + mode: str, rawmode: str, data: int | bytes, pixels: list[float | tuple[int, ...]] +) -> None: + with pytest.warns(DeprecationWarning): + test_unpack(mode, rawmode, data, pixels) + + +@pytest.mark.parametrize( + "mode, rawmode, data, pixels", + ( + ("L", "L", 0, [0]), + ("RGB", "RGB", 2, [0]), + ("CMYK", "CMYK", 2, [0]), + ), +) +def test_unpack_valueerror( + mode: str, rawmode: str, data: int | bytes, pixels: list[float | tuple[int, ...]] +) -> None: + with pytest.raises(ValueError): + test_unpack(mode, rawmode, data, pixels) From 3af0e2d9cf69b10b51924f27e58407dbce042903 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Thu, 25 Apr 2024 21:20:41 -0500 Subject: [PATCH 2/9] 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 a66bf97087e..09c6214ccec 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 c29473d90db..79076c2e8db 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 c23d5d889f6..fbd01b62f23 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", "RGBX;16L", 64, unpackRGBA16L}, - {"RGB", "RGBX;16B", 64, unpackRGBA16B}, + {"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", "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}, From 5ffaf3f37834ec1044da0dfdc556832d723427d3 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 1 May 2024 15:45:34 -0500 Subject: [PATCH 3/9] clean up rawmode syntax comments --- src/libImaging/Unpack.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index fbd01b62f23..a094d7c6851 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -1706,16 +1706,25 @@ static struct { ImagingShuffler unpack; } unpackers[] = { - /* raw mode syntax is ";" where "bits" defaults - depending on mode (1 for "1", 8 for "P" and "L", etc), and - "flags" should be given in alphabetical order. if both bits - and flags have their default values, the ; should be left out */ - - /* flags: "I" inverted data; "R" reversed bit order; "B" big - endian byte order (default is little endian); "L" line - interleave, "S" signed, "F" floating point, "Z" inverted alpha */ - - /* exception: rawmodes "I" and "F" are always native endian byte order */ + // The rawmode syntax is ";". + // "bits" defaults depending on mode (1 for "1", 8 for "P" and "L", etc.). + // "flags" should be given in alphabetical order. + // If both bits and flags have their default values, the ; should be left out. + + // Flags: + // "B" big endian byte order (default is little endian) + // "F" floating point + // "I" inverted data + // "L" line interleaved + // "N" native endian byte order + // "R" reversed bit order + // "S" signed + // "Z" inverted alpha + + // Exceptions: + // Some RGB/BGR rawmodes have different sized bands, + // so the size of each band is listed consecutively. + // Rawmodes "I" and "F" default to native endian byte order. /* bilevel */ {"1", "1", 1, unpack1}, From f281063941eb73639e0f7ef66d97964c6939131d Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 1 May 2024 14:05:11 -0500 Subject: [PATCH 4/9] use new rawmodes in BMP and TGA image plugins --- Tests/test_file_tga.py | 2 +- src/PIL/BmpImagePlugin.py | 6 +++--- src/PIL/TgaImagePlugin.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/test_file_tga.py b/Tests/test_file_tga.py index a03a6a6e10a..26837fcf8b0 100644 --- a/Tests/test_file_tga.py +++ b/Tests/test_file_tga.py @@ -85,7 +85,7 @@ def test_rgba_16() -> None: with Image.open("Tests/images/rgba16.tga") as im: assert im.mode == "RGBA" - assert im.getpixel((0, 0)) == (172, 0, 255, 255) + assert im.getpixel((0, 0)) == (173, 0, 255, 255) assert im.getpixel((1, 0)) == (0, 255, 82, 0) diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index bf8f29577ae..a1942d954db 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -43,7 +43,7 @@ 1: ("P", "P;1"), 4: ("P", "P;4"), 8: ("P", "P"), - 16: ("RGB", "BGR;15"), + 16: ("RGB", "XRGB;1555"), 24: ("RGB", "BGR"), 32: ("RGB", "BGRX"), } @@ -218,8 +218,8 @@ def _bitmap(self, header: int = 0, offset: int = 0) -> None: (32, (0xFF000000, 0xFF00, 0xFF, 0xFF0000)): "BGAR", (32, (0x0, 0x0, 0x0, 0x0)): "BGRA", (24, (0xFF0000, 0xFF00, 0xFF)): "BGR", - (16, (0xF800, 0x7E0, 0x1F)): "BGR;16", - (16, (0x7C00, 0x3E0, 0x1F)): "BGR;15", + (16, (0xF800, 0x7E0, 0x1F)): "RGB;565", + (16, (0x7C00, 0x3E0, 0x1F)): "XRGB;1555", } if file_info["bits"] in SUPPORTED: if ( diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 90d5b5cf4ee..daf98f353eb 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -36,7 +36,7 @@ (3, 1): "1", (3, 8): "L", (3, 16): "LA", - (2, 16): "BGRA;15Z", + (2, 16): "ARGB;1555Z", (2, 24): "BGR", (2, 32): "BGRA", } @@ -116,7 +116,7 @@ def _open(self) -> None: start, size, mapdepth = i16(s, 3), i16(s, 5), s[7] if mapdepth == 16: self.palette = ImagePalette.raw( - "BGRA;15Z", bytes(2 * start) + self.fp.read(2 * size) + "ARGB;1555Z", bytes(2 * start) + self.fp.read(2 * size) ) self.palette.mode = "RGBA" elif mapdepth == 24: From adcd54111004d239b1813f4682479e31b2f74e77 Mon Sep 17 00:00:00 2001 From: Yay295 Date: Tue, 7 May 2024 19:51:16 -0500 Subject: [PATCH 5/9] deprecate old rawmodes for 16-bit RGB data --- docs/deprecations.rst | 25 +++++++++++++++++++++++++ docs/releasenotes/11.0.0.rst | 23 +++++++++++++++++++++++ src/PIL/Image.py | 27 +++++++++++++++++++++++++++ 3 files changed, 75 insertions(+) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 25607e27c3b..c0361fc29df 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -175,6 +175,31 @@ deprecated and will be removed in Pillow 12 (2025-10-15). They were used for obt raw pointers to ``ImagingCore`` internals. To interact with C code, you can use ``Image.Image.getim()``, which returns a ``Capsule`` object. +16-Bit RGB/BGR Rawmodes +^^^^^^^^^^^^^^^^^^^^^^^ + +.. deprecated:: 11.0.0 + +The following rawmodes have been deprecated and replaced with better-named rawmodes. +Additionally, the 5 and 6 bit conversions are slightly more accurate, so there will be +some differences in the output. The difference is only ever by 1, so you are unlikely +to notice the difference visually. + +============ ============== +Deprecated Use instead +============ ============== +``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`` +============ ============== + Removed features ---------------- diff --git a/docs/releasenotes/11.0.0.rst b/docs/releasenotes/11.0.0.rst index c3f18140f42..349e5130e8f 100644 --- a/docs/releasenotes/11.0.0.rst +++ b/docs/releasenotes/11.0.0.rst @@ -113,6 +113,29 @@ Specific WebP Feature Checks ``True`` if the WebP module is installed, until they are removed in Pillow 12.0.0 (2025-10-15). +16-Bit RGB/BGR Rawmodes +^^^^^^^^^^^^^^^^^^^^^^^ + +The following rawmodes have been deprecated and replaced with better-named rawmodes. +Additionally, the 5 and 6 bit conversions are slightly more accurate, so there will be +some differences in the output. The difference is only ever by 1, so you are unlikely +to notice the difference visually. + +============ ============== +Deprecated Use instead +============ ============== +``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`` +============ ============== + API Changes =========== diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 44270392c4d..a656aa5bfcc 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -283,6 +283,20 @@ def _conv_type_shape(im: Image) -> tuple[tuple[int, ...], str]: # may have to modify the stride calculation in map.c too! _MAPMODES = ("L", "P", "RGBX", "RGBA", "CMYK", "I;16", "I;16L", "I;16B") +# map of old deprecated rawmode to new replacement rawmode +_DEPRECATED_RAWMODES = { + "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", +} + def getmodebase(mode: str) -> str: """ @@ -426,6 +440,13 @@ def _getdecoder( elif not isinstance(args, tuple): args = (args,) + if decoder_name == "raw" and args[0] in _DEPRECATED_RAWMODES: + deprecate( + f"rawmode {args[0]}", + 12, + replacement=f"rawmode {_DEPRECATED_RAWMODES[args[0]]}", + ) + try: decoder = DECODERS[decoder_name] except KeyError: @@ -1636,6 +1657,12 @@ def getpalette(self, rawmode: str | None = "RGB") -> list[int] | None: mode = self.im.getpalettemode() except ValueError: return None # no palette + if rawmode in _DEPRECATED_RAWMODES: + deprecate( + f"rawmode {rawmode}", + 12, + replacement=f"rawmode {_DEPRECATED_RAWMODES[rawmode]}", + ) if rawmode is None: rawmode = mode return list(self.im.getpalette(mode, rawmode)) From d330a136cd07023b83aed5cdb098389a477a7f5f Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sat, 22 Jun 2024 09:24:26 -0500 Subject: [PATCH 6/9] move deprecated rawmode unpack tests to test_unpack_deprecated() --- Tests/test_lib_pack.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 09c6214ccec..f88140b3180 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -325,18 +325,13 @@ def get_unpack_parameters() -> UnPackParamTypes: ("RGB", "RGB;16L", 6, [(2, 4, 6), (8, 10, 12)]), ("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)]), @@ -493,12 +488,9 @@ 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)]), @@ -561,13 +553,10 @@ def get_unpack_parameters() -> UnPackParamTypes: ("RGBX", "RGB;L", 3, [(1, 4, 7, X), (2, 5, 8, X), (3, 6, 9, X)]), ("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)]), @@ -837,6 +826,19 @@ def test_unpack( ("BGR;15", "BGR;15", 3, [(8, 131, 0), (24, 0, 8), (41, 131, 8)]), ("BGR;16", "BGR;16", 3, [(8, 64, 0), (24, 129, 0), (41, 194, 0)]), ("BGR;24", "BGR;24", 3, [(1, 2, 3), (4, 5, 6), (7, 8, 9)]), + # Rawmode RGB/BGR/RGBA/BGRA 15/16/4B + ("RGB", "RGB;15", 2, [(8, 131, 0), (24, 0, 8)]), + ("RGB", "BGR;15", 2, [(0, 131, 8), (8, 0, 24)]), + ("RGB", "RGB;16", 2, [(8, 64, 0), (24, 129, 0)]), + ("RGB", "BGR;16", 2, [(0, 64, 8), (0, 129, 24)]), + ("RGB", "RGB;4B", 2, [(17, 0, 34), (51, 0, 68)]), + ("RGBA", "RGBA;15", 2, [(8, 131, 0, 0), (24, 0, 8, 0)]), + ("RGBA", "BGRA;15", 2, [(0, 131, 8, 0), (8, 0, 24, 0)]), + ("RGBA", "BGRA;15Z", 2, [(0, 131, 8, X), (8, 0, 24, X)]), + ("RGBA", "RGBA;4B", 2, [(17, 0, 34, 0), (51, 0, 68, 0)]), + ("RGBX", "RGB;15", 2, [(8, 131, 0, X), (24, 0, 8, X)]), + ("RGBX", "BGR;15", 2, [(0, 131, 8, X), (8, 0, 24, X)]), + ("RGBX", "RGB;4B", 2, [(17, 0, 34, X), (51, 0, 68, X)]), ), ) def test_unpack_deprecated( From 976f30709a6ef0a04ec6fcfd28a78c9926e4346e Mon Sep 17 00:00:00 2001 From: Yay295 Date: Sat, 22 Jun 2024 10:23:25 -0500 Subject: [PATCH 7/9] don't show rawmode deprecation warning if mode is same as rawmode The "BGR;15" and "BGR;16" modes being deprecated is separate from the "BGR;15" and "BGR;16" rawmodes being deprecated. --- src/PIL/Image.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index a656aa5bfcc..f7598bcc7c9 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -440,12 +440,14 @@ def _getdecoder( elif not isinstance(args, tuple): args = (args,) - if decoder_name == "raw" and args[0] in _DEPRECATED_RAWMODES: - deprecate( - f"rawmode {args[0]}", - 12, - replacement=f"rawmode {_DEPRECATED_RAWMODES[args[0]]}", - ) + if decoder_name == "raw": + rawmode = args[0] + if mode != rawmode and rawmode in _DEPRECATED_RAWMODES: + deprecate( + f"rawmode {rawmode}", + 12, + replacement=f"rawmode {_DEPRECATED_RAWMODES[rawmode]}", + ) try: decoder = DECODERS[decoder_name] From 75e54c23acf695aa0eb568143f4cb6d89eb825cb Mon Sep 17 00:00:00 2001 From: Yay295 Date: Wed, 26 Jun 2024 09:51:16 -0500 Subject: [PATCH 8/9] add check for deprecated rawmodes when creating an ImagePalette --- Tests/test_imagepalette.py | 6 ++++++ src/PIL/ImagePalette.py | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/Tests/test_imagepalette.py b/Tests/test_imagepalette.py index 6cf0079dda7..0317f77de7a 100644 --- a/Tests/test_imagepalette.py +++ b/Tests/test_imagepalette.py @@ -158,6 +158,12 @@ def test_rawmode_valueerrors(tmp_path: Path) -> None: palette.save(f) +@pytest.mark.parametrize("rawmode", Image._DEPRECATED_RAWMODES) +def test_rawmode_deprecated(rawmode: str) -> None: + with pytest.warns(DeprecationWarning): + ImagePalette.raw(rawmode, b"") + + def test_getdata() -> None: # Arrange data_in = list(range(256)) * 3 diff --git a/src/PIL/ImagePalette.py b/src/PIL/ImagePalette.py index 183f85526d2..2b709c91a25 100644 --- a/src/PIL/ImagePalette.py +++ b/src/PIL/ImagePalette.py @@ -209,6 +209,16 @@ def save(self, fp: str | IO[str]) -> None: def raw(rawmode: str, data: Sequence[int] | bytes | bytearray) -> ImagePalette: + from . import Image + from ._deprecate import deprecate + + if rawmode in Image._DEPRECATED_RAWMODES: + deprecate( + f"rawmode {rawmode}", + 12, + replacement=f"rawmode {Image._DEPRECATED_RAWMODES[rawmode]}", + ) + palette = ImagePalette() palette.rawmode = rawmode palette.palette = data From 89bafd30986e600c202f85bde833c99407db0be3 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sat, 29 Jun 2024 14:23:41 +1000 Subject: [PATCH 9/9] remove unpackers with identical output --- src/libImaging/Unpack.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index a094d7c6851..46a30a48407 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -883,36 +883,6 @@ ImagingUnpackBGR565(UINT8 *out, const UINT8 *in, const int pixels) { } } -void -ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) { - int i, 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; - out[G] = ((pixel >> 4) & 15) * 17; - out[B] = ((pixel >> 8) & 15) * 17; - out[A] = 255; - out += 4; - in += 2; - } -} - -void -ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) { - int i, 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; - out[G] = ((pixel >> 4) & 15) * 17; - out[B] = ((pixel >> 8) & 15) * 17; - out[A] = ((pixel >> 12) & 15) * 17; - out += 4; - in += 2; - } -} - static void ImagingUnpackXBGR4(UINT8 *out, const UINT8 *in, const int pixels) { /* XBGR, 4 bits per pixel, little-endian */ @@ -1791,7 +1761,7 @@ static struct { {"RGB", "RGB;565", 16, ImagingUnpackRGB565}, {"RGB", "BGR;16", 16, ImagingUnpackBGR16}, {"RGB", "BGR;565", 16, ImagingUnpackBGR565}, - {"RGB", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGB", "RGB;4B", 16, ImagingUnpackXBGR4}, {"RGB", "XBGR;4", 16, ImagingUnpackXBGR4}, {"RGB", "ABGR;4", 16, ImagingUnpackABGR4}, {"RGB", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ @@ -1843,7 +1813,7 @@ static struct { {"RGBA", "RGBA;15", 16, ImagingUnpackRGBA15}, {"RGBA", "BGRA;15", 16, ImagingUnpackBGRA15}, {"RGBA", "BGRA;15Z", 16, ImagingUnpackBGRA15Z}, - {"RGBA", "RGBA;4B", 16, ImagingUnpackRGBA4B}, + {"RGBA", "RGBA;4B", 16, ImagingUnpackABGR4}, {"RGBA", "ABGR;4", 16, ImagingUnpackABGR4}, {"RGBA", "RGBA;16L", 64, unpackRGBA16L}, {"RGBA", "RGBA;16B", 64, unpackRGBA16B}, @@ -1912,7 +1882,7 @@ static struct { {"RGBX", "BGR;15", 16, ImagingUnpackBGR15}, {"RGBX", "XBGR;1555", 16, ImagingUnpackXBGR1555}, {"RGBX", "BGR;565", 16, ImagingUnpackBGR565}, - {"RGBX", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGBX", "RGB;4B", 16, ImagingUnpackXBGR4}, {"RGBX", "XBGR;4", 16, ImagingUnpackXBGR4}, {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ {"RGBX", "RGBX", 32, copy4},