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/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/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index b4a300d0c59..f88140b3180 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -1,820 +1,863 @@ 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", "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)]), + ("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", "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", "XBGR;1555", 2, [(8, 132, 0), (24, 0, 8)]), + ("RGB", "ABGR;1555", 2, [(8, 132, 0), (24, 0, 8)]), + ("RGB", "RGB;565", 2, [(0, 65, 8), (0, 130, 24)]), + ("RGB", "BGR;565", 2, [(8, 65, 0), (24, 130, 0)]), + ("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)]), + ("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", "ARGB;1555", 2, [(0, 132, 8, 0), (8, 0, 24, 0)]), + ("RGBA", "ARGB;1555Z", 2, [(0, 132, 8, X), (8, 0, 24, X)]), + ("RGBA", "ABGR;1555", 2, [(8, 132, 0, 0), (24, 0, 8, 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)]), + ("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", "XRGB;1555", 2, [(0, 132, 8, X), (8, 0, 24, X)]), + ("RGBX", "RGB;565", 2, [(0, 65, 8, X), (0, 130, 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", "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)]), + ("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)]), + # 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( + 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) diff --git a/docs/deprecations.rst b/docs/deprecations.rst index 80966ca362a..498247f81bc 100644 --- a/docs/deprecations.rst +++ b/docs/deprecations.rst @@ -183,6 +183,31 @@ ExifTags.IFD.Makernote ``ExifTags.IFD.Makernote`` has been deprecated. Instead, use ``ExifTags.IFD.MakerNote``. +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/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/Image.py b/src/PIL/Image.py index dff3d063b13..1e6cdc34749 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,15 @@ def _getdecoder( elif not isinstance(args, tuple): args = (args,) + 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] except KeyError: @@ -1627,6 +1650,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)) 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 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: 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 e9203fe4d74..9d86d299fa8 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -764,31 +764,153 @@ ImagingUnpackBGR16(UINT8 *out, const UINT8 *in, int pixels) { } } -void -ImagingUnpackRGB4B(UINT8 *out, const UINT8 *in, int pixels) { - int i, pixel; - /* RGB, 4 bits per pixel */ - 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; +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; } } -void -ImagingUnpackRGBA4B(UINT8 *out, const UINT8 *in, int pixels) { - int i, pixel; - /* RGBA, 4 bits per pixel */ - 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; +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; + } +} + +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; } @@ -1554,16 +1676,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}, @@ -1620,13 +1751,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, ImagingUnpackXBGR4}, + {"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 +1796,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}, @@ -1670,7 +1813,8 @@ 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}, {"RGBA", "BGRA", 32, unpackBGRA}, @@ -1735,8 +1879,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", "RGB;4B", 16, ImagingUnpackRGB4B}, + {"RGBX", "XBGR;1555", 16, ImagingUnpackXBGR1555}, + {"RGBX", "BGR;565", 16, ImagingUnpackBGR565}, + {"RGBX", "RGB;4B", 16, ImagingUnpackXBGR4}, + {"RGBX", "XBGR;4", 16, ImagingUnpackXBGR4}, {"RGBX", "BGR;5", 16, ImagingUnpackBGR15}, /* compat */ {"RGBX", "RGBX", 32, copy4}, {"RGBX", "RGBXX", 40, copy4skip1},