diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index 132b69091..592de26e0 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -11,7 +11,7 @@ Full text of the CC0 license: """ import struct -from enum import IntFlag, IntEnum +from enum import IntEnum, IntFlag from io import BytesIO from . import Image, ImageFile @@ -63,125 +63,125 @@ class DDPF(IntFlag): # dxgiformat.h class DXGI_FORMAT(IntEnum): - UNKNOWN = 0, - R32G32B32A32_TYPELESS = 1, - R32G32B32A32_FLOAT = 2, - R32G32B32A32_UINT = 3, - R32G32B32A32_SINT = 4, - R32G32B32_TYPELESS = 5, - R32G32B32_FLOAT = 6, - R32G32B32_UINT = 7, - R32G32B32_SINT = 8, - R16G16B16A16_TYPELESS = 9, - R16G16B16A16_FLOAT = 10, - R16G16B16A16_UNORM = 11, - R16G16B16A16_UINT = 12, - R16G16B16A16_SNORM = 13, - R16G16B16A16_SINT = 14, - R32G32_TYPELESS = 15, - R32G32_FLOAT = 16, - R32G32_UINT = 17, - R32G32_SINT = 18, - R32G8X24_TYPELESS = 19, - D32_FLOAT_S8X24_UINT = 20, - R32_FLOAT_X8X24_TYPELESS = 21, - X32_TYPELESS_G8X24_UINT = 22, - R10G10B10A2_TYPELESS = 23, - R10G10B10A2_UNORM = 24, - R10G10B10A2_UINT = 25, - R11G11B10_FLOAT = 26, - R8G8B8A8_TYPELESS = 27, - R8G8B8A8_UNORM = 28, - R8G8B8A8_UNORM_SRGB = 29, - R8G8B8A8_UINT = 30, - R8G8B8A8_SNORM = 31, - R8G8B8A8_SINT = 32, - R16G16_TYPELESS = 33, - R16G16_FLOAT = 34, - R16G16_UNORM = 35, - R16G16_UINT = 36, - R16G16_SNORM = 37, - R16G16_SINT = 38, - R32_TYPELESS = 39, - D32_FLOAT = 40, - R32_FLOAT = 41, - R32_UINT = 42, - R32_SINT = 43, - R24G8_TYPELESS = 44, - D24_UNORM_S8_UINT = 45, - R24_UNORM_X8_TYPELESS = 46, - X24_TYPELESS_G8_UINT = 47, - R8G8_TYPELESS = 48, - R8G8_UNORM = 49, - R8G8_UINT = 50, - R8G8_SNORM = 51, - R8G8_SINT = 52, - R16_TYPELESS = 53, - R16_FLOAT = 54, - D16_UNORM = 55, - R16_UNORM = 56, - R16_UINT = 57, - R16_SNORM = 58, - R16_SINT = 59, - R8_TYPELESS = 60, - R8_UNORM = 61, - R8_UINT = 62, - R8_SNORM = 63, - R8_SINT = 64, - A8_UNORM = 65, - R1_UNORM = 66, - R9G9B9E5_SHAREDEXP = 67, - R8G8_B8G8_UNORM = 68, - G8R8_G8B8_UNORM = 69, - BC1_TYPELESS = 70, - BC1_UNORM = 71, - BC1_UNORM_SRGB = 72, - BC2_TYPELESS = 73, - BC2_UNORM = 74, - BC2_UNORM_SRGB = 75, - BC3_TYPELESS = 76, - BC3_UNORM = 77, - BC3_UNORM_SRGB = 78, - BC4_TYPELESS = 79, - BC4_UNORM = 80, - BC4_SNORM = 81, - BC5_TYPELESS = 82, - BC5_UNORM = 83, - BC5_SNORM = 84, - B5G6R5_UNORM = 85, - B5G5R5A1_UNORM = 86, - B8G8R8A8_UNORM = 87, - B8G8R8X8_UNORM = 88, - R10G10B10_XR_BIAS_A2_UNORM = 89, - B8G8R8A8_TYPELESS = 90, - B8G8R8A8_UNORM_SRGB = 91, - B8G8R8X8_TYPELESS = 92, - B8G8R8X8_UNORM_SRGB = 93, - BC6H_TYPELESS = 94, - BC6H_UF16 = 95, - BC6H_SF16 = 96, - BC7_TYPELESS = 97, - BC7_UNORM = 98, - BC7_UNORM_SRGB = 99, - AYUV = 100, - Y410 = 101, - Y416 = 102, - NV12 = 103, - P010 = 104, - P016 = 105, - _420_OPAQUE = 106, - YUY2 = 107, - Y210 = 108, - Y216 = 109, - NV11 = 110, - AI44 = 111, - IA44 = 112, - P8 = 113, - A8P8 = 114, - B4G4R4A4_UNORM = 115, - P208 = 130, - V208 = 131, - V408 = 132, + UNKNOWN = (0,) + R32G32B32A32_TYPELESS = (1,) + R32G32B32A32_FLOAT = (2,) + R32G32B32A32_UINT = (3,) + R32G32B32A32_SINT = (4,) + R32G32B32_TYPELESS = (5,) + R32G32B32_FLOAT = (6,) + R32G32B32_UINT = (7,) + R32G32B32_SINT = (8,) + R16G16B16A16_TYPELESS = (9,) + R16G16B16A16_FLOAT = (10,) + R16G16B16A16_UNORM = (11,) + R16G16B16A16_UINT = (12,) + R16G16B16A16_SNORM = (13,) + R16G16B16A16_SINT = (14,) + R32G32_TYPELESS = (15,) + R32G32_FLOAT = (16,) + R32G32_UINT = (17,) + R32G32_SINT = (18,) + R32G8X24_TYPELESS = (19,) + D32_FLOAT_S8X24_UINT = (20,) + R32_FLOAT_X8X24_TYPELESS = (21,) + X32_TYPELESS_G8X24_UINT = (22,) + R10G10B10A2_TYPELESS = (23,) + R10G10B10A2_UNORM = (24,) + R10G10B10A2_UINT = (25,) + R11G11B10_FLOAT = (26,) + R8G8B8A8_TYPELESS = (27,) + R8G8B8A8_UNORM = (28,) + R8G8B8A8_UNORM_SRGB = (29,) + R8G8B8A8_UINT = (30,) + R8G8B8A8_SNORM = (31,) + R8G8B8A8_SINT = (32,) + R16G16_TYPELESS = (33,) + R16G16_FLOAT = (34,) + R16G16_UNORM = (35,) + R16G16_UINT = (36,) + R16G16_SNORM = (37,) + R16G16_SINT = (38,) + R32_TYPELESS = (39,) + D32_FLOAT = (40,) + R32_FLOAT = (41,) + R32_UINT = (42,) + R32_SINT = (43,) + R24G8_TYPELESS = (44,) + D24_UNORM_S8_UINT = (45,) + R24_UNORM_X8_TYPELESS = (46,) + X24_TYPELESS_G8_UINT = (47,) + R8G8_TYPELESS = (48,) + R8G8_UNORM = (49,) + R8G8_UINT = (50,) + R8G8_SNORM = (51,) + R8G8_SINT = (52,) + R16_TYPELESS = (53,) + R16_FLOAT = (54,) + D16_UNORM = (55,) + R16_UNORM = (56,) + R16_UINT = (57,) + R16_SNORM = (58,) + R16_SINT = (59,) + R8_TYPELESS = (60,) + R8_UNORM = (61,) + R8_UINT = (62,) + R8_SNORM = (63,) + R8_SINT = (64,) + A8_UNORM = (65,) + R1_UNORM = (66,) + R9G9B9E5_SHAREDEXP = (67,) + R8G8_B8G8_UNORM = (68,) + G8R8_G8B8_UNORM = (69,) + BC1_TYPELESS = (70,) + BC1_UNORM = (71,) + BC1_UNORM_SRGB = (72,) + BC2_TYPELESS = (73,) + BC2_UNORM = (74,) + BC2_UNORM_SRGB = (75,) + BC3_TYPELESS = (76,) + BC3_UNORM = (77,) + BC3_UNORM_SRGB = (78,) + BC4_TYPELESS = (79,) + BC4_UNORM = (80,) + BC4_SNORM = (81,) + BC5_TYPELESS = (82,) + BC5_UNORM = (83,) + BC5_SNORM = (84,) + B5G6R5_UNORM = (85,) + B5G5R5A1_UNORM = (86,) + B8G8R8A8_UNORM = (87,) + B8G8R8X8_UNORM = (88,) + R10G10B10_XR_BIAS_A2_UNORM = (89,) + B8G8R8A8_TYPELESS = (90,) + B8G8R8A8_UNORM_SRGB = (91,) + B8G8R8X8_TYPELESS = (92,) + B8G8R8X8_UNORM_SRGB = (93,) + BC6H_TYPELESS = (94,) + BC6H_UF16 = (95,) + BC6H_SF16 = (96,) + BC7_TYPELESS = (97,) + BC7_UNORM = (98,) + BC7_UNORM_SRGB = (99,) + AYUV = (100,) + Y410 = (101,) + Y416 = (102,) + NV12 = (103,) + P010 = (104,) + P016 = (105,) + _420_OPAQUE = (106,) + YUY2 = (107,) + Y210 = (108,) + Y216 = (109,) + NV11 = (110,) + AI44 = (111,) + IA44 = (112,) + P8 = (113,) + A8P8 = (114,) + B4G4R4A4_UNORM = (115,) + P208 = (130,) + V208 = (131,) + V408 = (132,) SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 133 SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 134 INVALID = -1 @@ -192,7 +192,7 @@ class DXGI_FORMAT(IntEnum): def make_fourcc(name): - return struct.unpack('I', name.encode('ascii'))[0] + return struct.unpack("I", name.encode("ascii"))[0] class D3DFMT(IntEnum): @@ -252,20 +252,20 @@ class D3DFMT(IntEnum): A2B10G10R10_XR_BIAS = 119 BINARYBUFFER = 199 - UYVY = make_fourcc('UYVY') - R8G8_B8G8 = make_fourcc('RGBG') - YUY2 = make_fourcc('YUY2') - G8R8_G8B8 = make_fourcc('GRGB') - DXT1 = make_fourcc('DXT1') - DXT2 = make_fourcc('DXT2') - DXT3 = make_fourcc('DXT3') - DXT4 = make_fourcc('DXT4') - DXT5 = make_fourcc('DXT5') - DX10 = make_fourcc('DX10') - BC5S = make_fourcc('BC5S') - ATI1 = make_fourcc('ATI1') - ATI2 = make_fourcc('ATI2') - MULTI2_ARGB8 = make_fourcc('MET1') + UYVY = make_fourcc("UYVY") + R8G8_B8G8 = make_fourcc("RGBG") + YUY2 = make_fourcc("YUY2") + G8R8_G8B8 = make_fourcc("GRGB") + DXT1 = make_fourcc("DXT1") + DXT2 = make_fourcc("DXT2") + DXT3 = make_fourcc("DXT3") + DXT4 = make_fourcc("DXT4") + DXT5 = make_fourcc("DXT5") + DX10 = make_fourcc("DX10") + BC5S = make_fourcc("BC5S") + ATI1 = make_fourcc("ATI1") + ATI2 = make_fourcc("ATI2") + MULTI2_ARGB8 = make_fourcc("MET1") INVALID = -1 @classmethod @@ -305,9 +305,21 @@ class DdsImageFile(ImageFile.ImageFile): fourcc = D3DFMT(fourcc_) masks = struct.unpack("<4I", header.read(16)) if flags & DDSD.CAPS: - (caps1_, caps2_, caps3, caps4, _,) = struct.unpack("<5I", header.read(20)) + ( + caps1_, + caps2_, + caps3, + caps4, + _, + ) = struct.unpack("<5I", header.read(20)) else: - (caps1_, caps2_, caps3, caps4, _,) = 0, 0, 0, 0, 0 + (caps1_, caps2_, caps3, caps4, _,) = ( + 0, + 0, + 0, + 0, + 0, + ) caps1 = DDSCAPS(caps1_) caps2 = DDSCAPS2(caps2_) if pfflags & DDPF.LUMINANCE: @@ -329,34 +341,47 @@ class DdsImageFile(ImageFile.ImageFile): rawmode = masks[0xFF0000] + masks[0xFF00] + masks[0xFF] elif bitcount == 32: self.mode = "RGBA" - rawmode = masks[0xFF000000] + masks[0xFF0000] + masks[0xFF00] + masks[0xFF] + rawmode = ( + masks[0xFF000000] + masks[0xFF0000] + masks[0xFF00] + masks[0xFF] + ) else: - raise OSError(f'Unsupported bitcount {bitcount} for DDS texture') - + raise OSError(f"Unsupported bitcount {bitcount} for DDS texture") self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))] elif pfflags & DDPF.FOURCC: data_start = header_size + 4 if fourcc == D3DFMT.DXT1: self.pixel_format = "DXT1" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (1, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (1, self.pixel_format) + ) elif fourcc == D3DFMT.DXT3: self.pixel_format = "DXT3" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (2, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (2, self.pixel_format) + ) elif fourcc == D3DFMT.DXT5: self.pixel_format = "DXT5" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (3, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (3, self.pixel_format) + ) elif fourcc == D3DFMT.ATI1: self.pixel_format = "BC4" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (4, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (4, self.pixel_format) + ) self.mode = "L" elif fourcc == D3DFMT.BC5S: self.pixel_format = "BC5S" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (5, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (5, self.pixel_format) + ) self.mode = "RGB" elif fourcc == D3DFMT.ATI2: self.pixel_format = "BC5" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (5, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (5, self.pixel_format) + ) self.mode = "RGB" elif fourcc == D3DFMT.DX10: data_start += 20 @@ -365,27 +390,39 @@ class DdsImageFile(ImageFile.ImageFile): self.fp.read(16) if dxgi_format in (DXGI_FORMAT.BC5_TYPELESS, DXGI_FORMAT.BC5_UNORM): self.pixel_format = "BC5" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (5, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (5, self.pixel_format) + ) self.mode = "RGB" elif dxgi_format == DXGI_FORMAT.BC5_SNORM: self.pixel_format = "BC5S" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (5, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (5, self.pixel_format) + ) self.mode = "RGB" elif dxgi_format == DXGI_FORMAT.BC6H_UF16: self.pixel_format = "BC6H" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (6, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (6, self.pixel_format) + ) self.mode = "RGB" elif dxgi_format == DXGI_FORMAT.BC6H_SF16: self.pixel_format = "BC6HS" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (6, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (6, self.pixel_format) + ) self.mode = "RGB" elif dxgi_format in (DXGI_FORMAT.BC7_TYPELESS, DXGI_FORMAT.BC7_UNORM): self.pixel_format = "BC7" - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (7, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (7, self.pixel_format) + ) elif dxgi_format == DXGI_FORMAT.BC7_UNORM_SRGB: self.pixel_format = "BC7" self.info["gamma"] = 1 / 2.2 - tile = Image.Tile("bcn", (0, 0) + self.size, data_start, (7, self.pixel_format)) + tile = Image.Tile( + "bcn", (0, 0) + self.size, data_start, (7, self.pixel_format) + ) elif dxgi_format in ( DXGI_FORMAT.R8G8B8A8_TYPELESS, DXGI_FORMAT.R8G8B8A8_UNORM, @@ -403,15 +440,14 @@ class DdsImageFile(ImageFile.ImageFile): self.tile = [tile] else: - raise NotImplementedError(f'Unknown pixel format flags {repr(pfflags)}') + msg = f"Unknown pixel format flags {repr(pfflags)}" + raise NotImplementedError(msg) def load_seek(self, pos): pass def _save(im, fp, filename): - if im.mode not in ("RGB", "RGBA", "L"): - raise OSError(f"cannot write mode {im.mode} as DDS") if im.mode not in ("RGB", "RGBA", "L", "LA"): msg = f"cannot write mode {im.mode} as DDS" raise OSError(msg) @@ -434,7 +470,9 @@ def _save(im, fp, filename): fp.write( o32(DDS_MAGIC) + o32(124) # header size - + o32(DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PITCH | DDSD.PIXELFORMAT) # flags + + o32( + DDSD.CAPS | DDSD.HEIGHT | DDSD.WIDTH | DDSD.PITCH | DDSD.PIXELFORMAT + ) # flags + o32(im.height) + o32(im.width) + o32((im.width * bitcount + 7) // 8) # pitch @@ -455,7 +493,9 @@ def _save(im, fp, filename): if im.mode == "RGBA": r, g, b, a = im.split() im = Image.merge("RGBA", (a, r, g, b)) - ImageFile._save(im, fp, [Image.Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))]) + ImageFile._save( + im, fp, [Image.Tile("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))] + ) def _accept(prefix): diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 15d368acf..7919202f7 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -38,7 +38,7 @@ import warnings from collections.abc import Callable, MutableMapping from enum import IntEnum from pathlib import Path -from typing import NamedTuple, Tuple, List +from typing import List, NamedTuple, Tuple try: import defusedxml.ElementTree as ElementTree @@ -207,14 +207,15 @@ if hasattr(core, "DEFAULT_STRATEGY"): RLE = core.RLE FIXED = core.FIXED -Tile = NamedTuple('Tile', - [ - ('encoder_name', str), - ('extents', Tuple[int, int, int, int]), - ('offset', int), - ('tile_args', Tuple) - ] - ) +Tile = NamedTuple( + "Tile", + [ + ("encoder_name", str), + ("extents", Tuple[int, int, int, int]), + ("offset", int), + ("tile_args", Tuple), + ], +) # -------------------------------------------------------------------- # Registries diff --git a/src/PIL/ImageFile.py b/src/PIL/ImageFile.py index d3ab1126c..4194a7c35 100644 --- a/src/PIL/ImageFile.py +++ b/src/PIL/ImageFile.py @@ -536,7 +536,9 @@ def _encode_tile(im, fp, tile: List[Image.Tile], bufsize, fh, exc=None): if exc: # compress to Python file-compatible object while True: - errcode, data = encoder.encode(bufsize)[1:] + errcode, data = encoder.encode( + bufsize + )[1:] fp.write(data) if errcode: break @@ -544,7 +546,8 @@ def _encode_tile(im, fp, tile: List[Image.Tile], bufsize, fh, exc=None): # slight speedup: compress to real file object errcode = encoder.encode_to_file(fh, bufsize) if errcode < 0: - msg = f"encoder error {errcode} when writing image file" + msg = + f"encoder error {errcode} when writing image file" raise OSError(msg) from exc finally: encoder.cleanup()