Changed Image mode property to be read-only by default

This commit is contained in:
Andrew Murray 2023-07-29 09:28:18 +10:00
parent 07623d1a7c
commit 9979a822c7
48 changed files with 125 additions and 115 deletions

View File

@ -135,6 +135,12 @@ class TestImage:
with pytest.raises(AttributeError): with pytest.raises(AttributeError):
im.size = (3, 4) im.size = (3, 4)
def test_set_mode(self):
im = Image.new("RGB", (1, 1))
with pytest.raises(AttributeError):
im.mode = "P"
def test_invalid_image(self): def test_invalid_image(self):
im = io.BytesIO(b"") im = io.BytesIO(b"")
with pytest.raises(UnidentifiedImageError): with pytest.raises(UnidentifiedImageError):

View File

@ -136,7 +136,7 @@ class TestImageFile:
class DummyImageFile(ImageFile.ImageFile): class DummyImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
self.mode = "RGB" self._mode = "RGB"
self._size = (1, 1) self._size = (1, 1)
im = DummyImageFile(buf) im = DummyImageFile(buf)
@ -217,7 +217,7 @@ xoff, yoff, xsize, ysize = 10, 20, 100, 100
class MockImageFile(ImageFile.ImageFile): class MockImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
self.rawmode = "RGBA" self.rawmode = "RGBA"
self.mode = "RGBA" self._mode = "RGBA"
self._size = (200, 200) self._size = (200, 200)
self.tile = [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 32, None)] self.tile = [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 32, None)]

View File

@ -75,13 +75,13 @@ def test_pickle_la_mode_with_palette(tmp_path):
# Act / Assert # Act / Assert
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1): for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
im.mode = "LA" im._mode = "LA"
with open(filename, "wb") as f: with open(filename, "wb") as f:
pickle.dump(im, f, protocol) pickle.dump(im, f, protocol)
with open(filename, "rb") as f: with open(filename, "rb") as f:
loaded_im = pickle.load(f) loaded_im = pickle.load(f)
im.mode = "PA" im._mode = "PA"
assert im == loaded_im assert im == loaded_im

View File

@ -225,7 +225,7 @@ class DdsImageFile(ImageFile.ImageFile):
flags, height, width = struct.unpack("<3I", header.read(12)) flags, height, width = struct.unpack("<3I", header.read(12))
self._size = (width, height) self._size = (width, height)
self.mode = "RGBA" self._mode = "RGBA"
pitch, depth, mipmaps = struct.unpack("<3I", header.read(12)) pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
struct.unpack("<11I", header.read(44)) # reserved struct.unpack("<11I", header.read(44)) # reserved

View File

@ -72,11 +72,11 @@ true color.
# mode setting # mode setting
bits = int(header[3]) bits = int(header[3])
if bits == 1: if bits == 1:
self.mode = "1" self._mode = "1"
elif bits == 8: elif bits == 8:
self.mode = "L" self._mode = "L"
elif bits == 24: elif bits == 24:
self.mode = "RGB" self._mode = "RGB"
else: else:
msg = "unknown number of bits" msg = "unknown number of bits"
raise SyntaxError(msg) raise SyntaxError(msg)

View File

@ -266,7 +266,7 @@ class BlpImageFile(ImageFile.ImageFile):
msg = f"Bad BLP magic {repr(self.magic)}" msg = f"Bad BLP magic {repr(self.magic)}"
raise BLPFormatError(msg) raise BLPFormatError(msg)
self.mode = "RGBA" if self._blp_alpha_depth else "RGB" self._mode = "RGBA" if self._blp_alpha_depth else "RGB"
self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))] self.tile = [(decoder, (0, 0) + self.size, 0, (self.mode, 0, 1))]

View File

@ -163,7 +163,7 @@ class BmpImageFile(ImageFile.ImageFile):
offset += 4 * file_info["colors"] offset += 4 * file_info["colors"]
# ---------------------- Check bit depth for unusual unsupported values # ---------------------- Check bit depth for unusual unsupported values
self.mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None)) self._mode, raw_mode = BIT2MODE.get(file_info["bits"], (None, None))
if self.mode is None: if self.mode is None:
msg = f"Unsupported BMP pixel depth ({file_info['bits']})" msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
raise OSError(msg) raise OSError(msg)
@ -200,7 +200,7 @@ class BmpImageFile(ImageFile.ImageFile):
and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]] and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
): ):
raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])] raw_mode = MASK_MODES[(file_info["bits"], file_info["rgba_mask"])]
self.mode = "RGBA" if "A" in raw_mode else self.mode self._mode = "RGBA" if "A" in raw_mode else self.mode
elif ( elif (
file_info["bits"] in (24, 16) file_info["bits"] in (24, 16)
and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]] and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
@ -214,7 +214,7 @@ class BmpImageFile(ImageFile.ImageFile):
raise OSError(msg) raise OSError(msg)
elif file_info["compression"] == self.RAW: elif file_info["compression"] == self.RAW:
if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset if file_info["bits"] == 32 and header == 22: # 32-bit .cur offset
raw_mode, self.mode = "BGRA", "RGBA" raw_mode, self._mode = "BGRA", "RGBA"
elif file_info["compression"] in (self.RLE8, self.RLE4): elif file_info["compression"] in (self.RLE8, self.RLE4):
decoder_name = "bmp_rle" decoder_name = "bmp_rle"
else: else:
@ -245,10 +245,10 @@ class BmpImageFile(ImageFile.ImageFile):
# ------- If all colors are grey, white or black, ditch palette # ------- If all colors are grey, white or black, ditch palette
if greyscale: if greyscale:
self.mode = "1" if file_info["colors"] == 2 else "L" self._mode = "1" if file_info["colors"] == 2 else "L"
raw_mode = self.mode raw_mode = self.mode
else: else:
self.mode = "P" self._mode = "P"
self.palette = ImagePalette.raw( self.palette = ImagePalette.raw(
"BGRX" if padding == 4 else "BGR", palette "BGRX" if padding == 4 else "BGR", palette
) )

View File

@ -46,7 +46,7 @@ class BufrStubImageFile(ImageFile.StubImageFile):
self.fp.seek(offset) self.fp.seek(offset)
# make something up # make something up
self.mode = "F" self._mode = "F"
self._size = 1, 1 self._size = 1, 1
loader = self._load() loader = self._load()

View File

@ -128,7 +128,7 @@ class DdsImageFile(ImageFile.ImageFile):
flags, height, width = struct.unpack("<3I", header.read(12)) flags, height, width = struct.unpack("<3I", header.read(12))
self._size = (width, height) self._size = (width, height)
self.mode = "RGBA" self._mode = "RGBA"
pitch, depth, mipmaps = struct.unpack("<3I", header.read(12)) pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
struct.unpack("<11I", header.read(44)) # reserved struct.unpack("<11I", header.read(44)) # reserved
@ -141,9 +141,9 @@ class DdsImageFile(ImageFile.ImageFile):
if pfflags & DDPF_LUMINANCE: if pfflags & DDPF_LUMINANCE:
# Texture contains uncompressed L or LA data # Texture contains uncompressed L or LA data
if pfflags & DDPF_ALPHAPIXELS: if pfflags & DDPF_ALPHAPIXELS:
self.mode = "LA" self._mode = "LA"
else: else:
self.mode = "L" self._mode = "L"
self.tile = [("raw", (0, 0) + self.size, 0, (self.mode, 0, 1))] self.tile = [("raw", (0, 0) + self.size, 0, (self.mode, 0, 1))]
elif pfflags & DDPF_RGB: elif pfflags & DDPF_RGB:
@ -153,7 +153,7 @@ class DdsImageFile(ImageFile.ImageFile):
if pfflags & DDPF_ALPHAPIXELS: if pfflags & DDPF_ALPHAPIXELS:
rawmode += masks[0xFF000000] rawmode += masks[0xFF000000]
else: else:
self.mode = "RGB" self._mode = "RGB"
rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF] rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]
self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))] self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]
@ -172,15 +172,15 @@ class DdsImageFile(ImageFile.ImageFile):
elif fourcc == b"ATI1": elif fourcc == b"ATI1":
self.pixel_format = "BC4" self.pixel_format = "BC4"
n = 4 n = 4
self.mode = "L" self._mode = "L"
elif fourcc == b"ATI2": elif fourcc == b"ATI2":
self.pixel_format = "BC5" self.pixel_format = "BC5"
n = 5 n = 5
self.mode = "RGB" self._mode = "RGB"
elif fourcc == b"BC5S": elif fourcc == b"BC5S":
self.pixel_format = "BC5S" self.pixel_format = "BC5S"
n = 5 n = 5
self.mode = "RGB" self._mode = "RGB"
elif fourcc == b"DX10": elif fourcc == b"DX10":
data_start += 20 data_start += 20
# ignoring flags which pertain to volume textures and cubemaps # ignoring flags which pertain to volume textures and cubemaps
@ -189,19 +189,19 @@ class DdsImageFile(ImageFile.ImageFile):
if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM): if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):
self.pixel_format = "BC5" self.pixel_format = "BC5"
n = 5 n = 5
self.mode = "RGB" self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC5_SNORM: elif dxgi_format == DXGI_FORMAT_BC5_SNORM:
self.pixel_format = "BC5S" self.pixel_format = "BC5S"
n = 5 n = 5
self.mode = "RGB" self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_UF16: elif dxgi_format == DXGI_FORMAT_BC6H_UF16:
self.pixel_format = "BC6H" self.pixel_format = "BC6H"
n = 6 n = 6
self.mode = "RGB" self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_SF16: elif dxgi_format == DXGI_FORMAT_BC6H_SF16:
self.pixel_format = "BC6HS" self.pixel_format = "BC6HS"
n = 6 n = 6
self.mode = "RGB" self._mode = "RGB"
elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM): elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
self.pixel_format = "BC7" self.pixel_format = "BC7"
n = 7 n = 7

View File

@ -227,7 +227,7 @@ class EpsImageFile(ImageFile.ImageFile):
# go to offset - start of "%!PS" # go to offset - start of "%!PS"
self.fp.seek(offset) self.fp.seek(offset)
self.mode = "RGB" self._mode = "RGB"
self._size = None self._size = None
byte_arr = bytearray(255) byte_arr = bytearray(255)
@ -344,10 +344,10 @@ class EpsImageFile(ImageFile.ImageFile):
] ]
if bit_depth == 1: if bit_depth == 1:
self.mode = "1" self._mode = "1"
elif bit_depth == 8: elif bit_depth == 8:
try: try:
self.mode = self.mode_map[mode_id] self._mode = self.mode_map[mode_id]
except ValueError: except ValueError:
break break
else: else:
@ -391,7 +391,7 @@ class EpsImageFile(ImageFile.ImageFile):
# Load EPS via Ghostscript # Load EPS via Ghostscript
if self.tile: if self.tile:
self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency) self.im = Ghostscript(self.tile, self.size, self.fp, scale, transparency)
self.mode = self.im.mode self._mode = self.im.mode
self._size = self.im.size self._size = self.im.size
self.tile = [] self.tile = []
return Image.Image.load(self) return Image.Image.load(self)

View File

@ -51,14 +51,14 @@ class FitsImageFile(ImageFile.ImageFile):
number_of_bits = int(headers[b"BITPIX"]) number_of_bits = int(headers[b"BITPIX"])
if number_of_bits == 8: if number_of_bits == 8:
self.mode = "L" self._mode = "L"
elif number_of_bits == 16: elif number_of_bits == 16:
self.mode = "I" self._mode = "I"
# rawmode = "I;16S" # rawmode = "I;16S"
elif number_of_bits == 32: elif number_of_bits == 32:
self.mode = "I" self._mode = "I"
elif number_of_bits in (-32, -64): elif number_of_bits in (-32, -64):
self.mode = "F" self._mode = "F"
# rawmode = "F" if number_of_bits == -32 else "F;64F" # rawmode = "F" if number_of_bits == -32 else "F;64F"
offset = math.ceil(self.fp.tell() / 2880) * 2880 offset = math.ceil(self.fp.tell() / 2880) * 2880

View File

@ -56,7 +56,7 @@ class FliImageFile(ImageFile.ImageFile):
self.is_animated = self.n_frames > 1 self.is_animated = self.n_frames > 1
# image characteristics # image characteristics
self.mode = "P" self._mode = "P"
self._size = i16(s, 8), i16(s, 10) self._size = i16(s, 8), i16(s, 10)
# animation speed # animation speed

View File

@ -106,7 +106,7 @@ class FpxImageFile(ImageFile.ImageFile):
# note: for now, we ignore the "uncalibrated" flag # note: for now, we ignore the "uncalibrated" flag
colors.append(i32(s, 8 + i * 4) & 0x7FFFFFFF) colors.append(i32(s, 8 + i * 4) & 0x7FFFFFFF)
self.mode, self.rawmode = MODES[tuple(colors)] self._mode, self.rawmode = MODES[tuple(colors)]
# load JPEG tables, if any # load JPEG tables, if any
self.jpeg = {} self.jpeg = {}

View File

@ -77,7 +77,7 @@ class FtexImageFile(ImageFile.ImageFile):
self._size = struct.unpack("<2i", self.fp.read(8)) self._size = struct.unpack("<2i", self.fp.read(8))
mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8)) mipmap_count, format_count = struct.unpack("<2i", self.fp.read(8))
self.mode = "RGB" self._mode = "RGB"
# Only support single-format files. # Only support single-format files.
# I don't know of any multi-format file. # I don't know of any multi-format file.
@ -90,7 +90,7 @@ class FtexImageFile(ImageFile.ImageFile):
data = self.fp.read(mipmap_size) data = self.fp.read(mipmap_size)
if format == Format.DXT1: if format == Format.DXT1:
self.mode = "RGBA" self._mode = "RGBA"
self.tile = [("bcn", (0, 0) + self.size, 0, 1)] self.tile = [("bcn", (0, 0) + self.size, 0, 1)]
elif format == Format.UNCOMPRESSED: elif format == Format.UNCOMPRESSED:
self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))] self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]

View File

@ -73,9 +73,9 @@ class GbrImageFile(ImageFile.ImageFile):
comment = self.fp.read(comment_length)[:-1] comment = self.fp.read(comment_length)[:-1]
if color_depth == 1: if color_depth == 1:
self.mode = "L" self._mode = "L"
else: else:
self.mode = "RGBA" self._mode = "RGBA"
self._size = width, height self._size = width, height

View File

@ -51,7 +51,7 @@ class GdImageFile(ImageFile.ImageFile):
msg = "Not a valid GD 2.x .gd file" msg = "Not a valid GD 2.x .gd file"
raise SyntaxError(msg) raise SyntaxError(msg)
self.mode = "L" # FIXME: "P" self._mode = "L" # FIXME: "P"
self._size = i16(s, 2), i16(s, 4) self._size = i16(s, 2), i16(s, 4)
true_color = s[6] true_color = s[6]

View File

@ -304,11 +304,11 @@ class GifImageFile(ImageFile.ImageFile):
if frame == 0: if frame == 0:
if self._frame_palette: if self._frame_palette:
if LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS: if LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS:
self.mode = "RGBA" if frame_transparency is not None else "RGB" self._mode = "RGBA" if frame_transparency is not None else "RGB"
else: else:
self.mode = "P" self._mode = "P"
else: else:
self.mode = "L" self._mode = "L"
if not palette and self.global_palette: if not palette and self.global_palette:
from copy import copy from copy import copy
@ -325,10 +325,10 @@ class GifImageFile(ImageFile.ImageFile):
if "transparency" in self.info: if "transparency" in self.info:
self.im.putpalettealpha(self.info["transparency"], 0) self.im.putpalettealpha(self.info["transparency"], 0)
self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG) self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG)
self.mode = "RGBA" self._mode = "RGBA"
del self.info["transparency"] del self.info["transparency"]
else: else:
self.mode = "RGB" self._mode = "RGB"
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG) self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)
def _rgb(color): def _rgb(color):
@ -424,7 +424,7 @@ class GifImageFile(ImageFile.ImageFile):
self.im.putpalette(*self._frame_palette.getdata()) self.im.putpalette(*self._frame_palette.getdata())
else: else:
self.im = None self.im = None
self.mode = temp_mode self._mode = temp_mode
self._frame_palette = None self._frame_palette = None
super().load_prepare() super().load_prepare()
@ -434,9 +434,9 @@ class GifImageFile(ImageFile.ImageFile):
if self.mode == "P" and LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS: if self.mode == "P" and LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS:
if self._frame_transparency is not None: if self._frame_transparency is not None:
self.im.putpalettealpha(self._frame_transparency, 0) self.im.putpalettealpha(self._frame_transparency, 0)
self.mode = "RGBA" self._mode = "RGBA"
else: else:
self.mode = "RGB" self._mode = "RGB"
self.im = self.im.convert(self.mode, Image.Dither.FLOYDSTEINBERG) self.im = self.im.convert(self.mode, Image.Dither.FLOYDSTEINBERG)
return return
if not self._prev_im: if not self._prev_im:
@ -449,7 +449,7 @@ class GifImageFile(ImageFile.ImageFile):
frame_im = self._crop(frame_im, self.dispose_extent) frame_im = self._crop(frame_im, self.dispose_extent)
self.im = self._prev_im self.im = self._prev_im
self.mode = self.im.mode self._mode = self.im.mode
if frame_im.mode == "RGBA": if frame_im.mode == "RGBA":
self.im.paste(frame_im, self.dispose_extent, frame_im) self.im.paste(frame_im, self.dispose_extent, frame_im)
else: else:

View File

@ -46,7 +46,7 @@ class GribStubImageFile(ImageFile.StubImageFile):
self.fp.seek(offset) self.fp.seek(offset)
# make something up # make something up
self.mode = "F" self._mode = "F"
self._size = 1, 1 self._size = 1, 1
loader = self._load() loader = self._load()

View File

@ -46,7 +46,7 @@ class HDF5StubImageFile(ImageFile.StubImageFile):
self.fp.seek(offset) self.fp.seek(offset)
# make something up # make something up
self.mode = "F" self._mode = "F"
self._size = 1, 1 self._size = 1, 1
loader = self._load() loader = self._load()

View File

@ -253,7 +253,7 @@ class IcnsImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
self.icns = IcnsFile(self.fp) self.icns = IcnsFile(self.fp)
self.mode = "RGBA" self._mode = "RGBA"
self.info["sizes"] = self.icns.itersizes() self.info["sizes"] = self.icns.itersizes()
self.best_size = self.icns.bestsize() self.best_size = self.icns.bestsize()
self.size = ( self.size = (
@ -305,7 +305,7 @@ class IcnsImageFile(ImageFile.ImageFile):
px = im.load() px = im.load()
self.im = im.im self.im = im.im
self.mode = im.mode self._mode = im.mode
self.size = im.size self.size = im.size
return px return px

View File

@ -330,7 +330,7 @@ class IcoImageFile(ImageFile.ImageFile):
im.load() im.load()
self.im = im.im self.im = im.im
self.pyaccess = None self.pyaccess = None
self.mode = im.mode self._mode = im.mode
if im.size != self.size: if im.size != self.size:
warnings.warn("Image was not the expected size") warnings.warn("Image was not the expected size")

View File

@ -205,7 +205,7 @@ class ImImageFile(ImageFile.ImageFile):
# Basic attributes # Basic attributes
self._size = self.info[SIZE] self._size = self.info[SIZE]
self.mode = self.info[MODE] self._mode = self.info[MODE]
# Skip forward to start of image data # Skip forward to start of image data
while s and s[:1] != b"\x1A": while s and s[:1] != b"\x1A":
@ -231,9 +231,9 @@ class ImImageFile(ImageFile.ImageFile):
self.lut = list(palette[:256]) self.lut = list(palette[:256])
else: else:
if self.mode in ["L", "P"]: if self.mode in ["L", "P"]:
self.mode = self.rawmode = "P" self._mode = self.rawmode = "P"
elif self.mode in ["LA", "PA"]: elif self.mode in ["LA", "PA"]:
self.mode = "PA" self._mode = "PA"
self.rawmode = "PA;L" self.rawmode = "PA;L"
self.palette = ImagePalette.raw("RGB;L", palette) self.palette = ImagePalette.raw("RGB;L", palette)
elif self.mode == "RGB": elif self.mode == "RGB":

View File

@ -482,7 +482,7 @@ class Image:
# FIXME: take "new" parameters / other image? # FIXME: take "new" parameters / other image?
# FIXME: turn mode and size into delegating properties? # FIXME: turn mode and size into delegating properties?
self.im = None self.im = None
self.mode = "" self._mode = ""
self._size = (0, 0) self._size = (0, 0)
self.palette = None self.palette = None
self.info = {} self.info = {}
@ -502,10 +502,14 @@ class Image:
def size(self): def size(self):
return self._size return self._size
@property
def mode(self):
return self._mode
def _new(self, im): def _new(self, im):
new = Image() new = Image()
new.im = im new.im = im
new.mode = im.mode new._mode = im.mode
new._size = im.size new._size = im.size
if im.mode in ("P", "PA"): if im.mode in ("P", "PA"):
if self.palette: if self.palette:
@ -693,7 +697,7 @@ class Image:
Image.__init__(self) Image.__init__(self)
info, mode, size, palette, data = state info, mode, size, palette, data = state
self.info = info self.info = info
self.mode = mode self._mode = mode
self._size = size self._size = size
self.im = core.new(mode, size) self.im = core.new(mode, size)
if mode in ("L", "LA", "P", "PA") and palette: if mode in ("L", "LA", "P", "PA") and palette:
@ -1840,7 +1844,7 @@ class Image:
raise ValueError from e # sanity check raise ValueError from e # sanity check
self.im = im self.im = im
self.pyaccess = None self.pyaccess = None
self.mode = self.im.mode self._mode = self.im.mode
except KeyError as e: except KeyError as e:
msg = "illegal image mode" msg = "illegal image mode"
raise ValueError(msg) from e raise ValueError(msg) from e
@ -1918,7 +1922,7 @@ class Image:
if not isinstance(data, bytes): if not isinstance(data, bytes):
data = bytes(data) data = bytes(data)
palette = ImagePalette.raw(rawmode, data) palette = ImagePalette.raw(rawmode, data)
self.mode = "PA" if "A" in self.mode else "P" self._mode = "PA" if "A" in self.mode else "P"
self.palette = palette self.palette = palette
self.palette.mode = "RGB" self.palette.mode = "RGB"
self.load() # install new palette self.load() # install new palette
@ -2026,7 +2030,7 @@ class Image:
mapping_palette = bytearray(new_positions) mapping_palette = bytearray(new_positions)
m_im = self.copy() m_im = self.copy()
m_im.mode = "P" m_im._mode = "P"
m_im.palette = ImagePalette.ImagePalette( m_im.palette = ImagePalette.ImagePalette(
palette_mode, palette=mapping_palette * bands palette_mode, palette=mapping_palette * bands
@ -2601,7 +2605,7 @@ class Image:
self.im = im.im self.im = im.im
self._size = size self._size = size
self.mode = self.im.mode self._mode = self.im.mode
self.readonly = 0 self.readonly = 0
self.pyaccess = None self.pyaccess = None

View File

@ -89,7 +89,7 @@ class ImtImageFile(ImageFile.ImageFile):
ysize = int(v) ysize = int(v)
self._size = xsize, ysize self._size = xsize, ysize
elif k == b"pixel" and v == b"n8": elif k == b"pixel" and v == b"n8":
self.mode = "L" self._mode = "L"
# #

View File

@ -109,11 +109,11 @@ class IptcImageFile(ImageFile.ImageFile):
else: else:
id = 0 id = 0
if layers == 1 and not component: if layers == 1 and not component:
self.mode = "L" self._mode = "L"
elif layers == 3 and component: elif layers == 3 and component:
self.mode = "RGB"[id] self._mode = "RGB"[id]
elif layers == 4 and component: elif layers == 4 and component:
self.mode = "CMYK"[id] self._mode = "CMYK"[id]
# size # size
self._size = self.getint((3, 20)), self.getint((3, 30)) self._size = self.getint((3, 20)), self.getint((3, 30))

View File

@ -208,14 +208,14 @@ class Jpeg2KImageFile(ImageFile.ImageFile):
sig = self.fp.read(4) sig = self.fp.read(4)
if sig == b"\xff\x4f\xff\x51": if sig == b"\xff\x4f\xff\x51":
self.codec = "j2k" self.codec = "j2k"
self._size, self.mode = _parse_codestream(self.fp) self._size, self._mode = _parse_codestream(self.fp)
else: else:
sig = sig + self.fp.read(8) sig = sig + self.fp.read(8)
if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a": if sig == b"\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a":
self.codec = "jp2" self.codec = "jp2"
header = _parse_jp2_header(self.fp) header = _parse_jp2_header(self.fp)
self._size, self.mode, self.custom_mimetype, dpi = header self._size, self._mode, self.custom_mimetype, dpi = header
if dpi is not None: if dpi is not None:
self.info["dpi"] = dpi self.info["dpi"] = dpi
if self.fp.read(12).endswith(b"jp2c\xff\x4f\xff\x51"): if self.fp.read(12).endswith(b"jp2c\xff\x4f\xff\x51"):

View File

@ -208,11 +208,11 @@ def SOF(self, marker):
self.layers = s[5] self.layers = s[5]
if self.layers == 1: if self.layers == 1:
self.mode = "L" self._mode = "L"
elif self.layers == 3: elif self.layers == 3:
self.mode = "RGB" self._mode = "RGB"
elif self.layers == 4: elif self.layers == 4:
self.mode = "CMYK" self._mode = "CMYK"
else: else:
msg = f"cannot handle {self.layers}-layer images" msg = f"cannot handle {self.layers}-layer images"
raise SyntaxError(msg) raise SyntaxError(msg)
@ -426,7 +426,7 @@ class JpegImageFile(ImageFile.ImageFile):
original_size = self.size original_size = self.size
if a[0] == "RGB" and mode in ["L", "YCbCr"]: if a[0] == "RGB" and mode in ["L", "YCbCr"]:
self.mode = mode self._mode = mode
a = mode, "" a = mode, ""
if size: if size:
@ -475,7 +475,7 @@ class JpegImageFile(ImageFile.ImageFile):
except OSError: except OSError:
pass pass
self.mode = self.im.mode self._mode = self.im.mode
self._size = self.im.size self._size = self.im.size
self.tile = [] self.tile = []

View File

@ -58,7 +58,7 @@ class McIdasImageFile(ImageFile.ImageFile):
msg = "unsupported McIdas format" msg = "unsupported McIdas format"
raise SyntaxError(msg) raise SyntaxError(msg)
self.mode = mode self._mode = mode
self._size = w[10], w[9] self._size = w[10], w[9]
offset = w[34] + w[15] offset = w[34] + w[15]

View File

@ -68,7 +68,7 @@ class MpegImageFile(ImageFile.ImageFile):
msg = "not an MPEG file" msg = "not an MPEG file"
raise SyntaxError(msg) raise SyntaxError(msg)
self.mode = "RGB" self._mode = "RGB"
self._size = s.read(12), s.read(12) self._size = s.read(12), s.read(12)

View File

@ -62,7 +62,7 @@ class MspImageFile(ImageFile.ImageFile):
msg = "bad MSP checksum" msg = "bad MSP checksum"
raise SyntaxError(msg) raise SyntaxError(msg)
self.mode = "1" self._mode = "1"
self._size = i16(s, 4), i16(s, 6) self._size = i16(s, 4), i16(s, 6)
if s[:4] == b"DanM": if s[:4] == b"DanM":

View File

@ -43,7 +43,7 @@ class PcdImageFile(ImageFile.ImageFile):
elif orientation == 3: elif orientation == 3:
self.tile_post_rotate = -90 self.tile_post_rotate = -90
self.mode = "RGB" self._mode = "RGB"
self._size = 768, 512 # FIXME: not correct for rotated images! self._size = 768, 512 # FIXME: not correct for rotated images!
self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)] self.tile = [("pcd", (0, 0) + self.size, 96 * 2048, None)]

View File

@ -108,7 +108,7 @@ class PcxImageFile(ImageFile.ImageFile):
msg = "unknown PCX mode" msg = "unknown PCX mode"
raise OSError(msg) raise OSError(msg)
self.mode = mode self._mode = mode
self._size = bbox[2] - bbox[0], bbox[3] - bbox[1] self._size = bbox[2] - bbox[0], bbox[3] - bbox[1]
# Don't trust the passed in stride. # Don't trust the passed in stride.

View File

@ -54,7 +54,7 @@ class PixarImageFile(ImageFile.ImageFile):
mode = i16(s, 424), i16(s, 426) mode = i16(s, 424), i16(s, 426)
if mode == (14, 2): if mode == (14, 2):
self.mode = "RGB" self._mode = "RGB"
# FIXME: to be continued... # FIXME: to be continued...
# create tile descriptor (assuming "dumped") # create tile descriptor (assuming "dumped")

View File

@ -737,7 +737,7 @@ class PngImageFile(ImageFile.ImageFile):
# difficult to break if things go wrong in the decoder... # difficult to break if things go wrong in the decoder...
# (believe me, I've tried ;-) # (believe me, I've tried ;-)
self.mode = self.png.im_mode self._mode = self.png.im_mode
self._size = self.png.im_size self._size = self.png.im_size
self.info = self.png.im_info self.info = self.png.im_info
self._text = None self._text = None

View File

@ -116,18 +116,18 @@ class PpmImageFile(ImageFile.ImageFile):
elif ix == 1: # token is the y size elif ix == 1: # token is the y size
ysize = token ysize = token
if mode == "1": if mode == "1":
self.mode = "1" self._mode = "1"
rawmode = "1;I" rawmode = "1;I"
break break
else: else:
self.mode = rawmode = mode self._mode = rawmode = mode
elif ix == 2: # token is maxval elif ix == 2: # token is maxval
maxval = token maxval = token
if not 0 < maxval < 65536: if not 0 < maxval < 65536:
msg = "maxval must be greater than 0 and less than 65536" msg = "maxval must be greater than 0 and less than 65536"
raise ValueError(msg) raise ValueError(msg)
if maxval > 255 and mode == "L": if maxval > 255 and mode == "L":
self.mode = "I" self._mode = "I"
if decoder_name != "ppm_plain": if decoder_name != "ppm_plain":
# If maxval matches a bit depth, use the raw decoder directly # If maxval matches a bit depth, use the raw decoder directly

View File

@ -79,7 +79,7 @@ class PsdImageFile(ImageFile.ImageFile):
mode = "RGBA" mode = "RGBA"
channels = 4 channels = 4
self.mode = mode self._mode = mode
self._size = i32(s, 18), i32(s, 14) self._size = i32(s, 18), i32(s, 14)
# #
@ -146,7 +146,7 @@ class PsdImageFile(ImageFile.ImageFile):
# seek to given layer (1..max) # seek to given layer (1..max)
try: try:
name, mode, bbox, tile = self.layers[layer - 1] name, mode, bbox, tile = self.layers[layer - 1]
self.mode = mode self._mode = mode
self.tile = tile self.tile = tile
self.frame = layer self.frame = layer
self.fp = self._fp self.fp = self._fp

View File

@ -29,7 +29,7 @@ class QoiImageFile(ImageFile.ImageFile):
self._size = tuple(i32(self.fp.read(4)) for i in range(2)) self._size = tuple(i32(self.fp.read(4)) for i in range(2))
channels = self.fp.read(1)[0] channels = self.fp.read(1)[0]
self.mode = "RGB" if channels == 3 else "RGBA" self._mode = "RGB" if channels == 3 else "RGBA"
self.fp.seek(1, os.SEEK_CUR) # colorspace self.fp.seek(1, os.SEEK_CUR) # colorspace
self.tile = [("qoi", (0, 0) + self._size, self.fp.tell(), None)] self.tile = [("qoi", (0, 0) + self._size, self.fp.tell(), None)]

View File

@ -94,7 +94,7 @@ class SgiImageFile(ImageFile.ImageFile):
raise ValueError(msg) raise ValueError(msg)
self._size = xsize, ysize self._size = xsize, ysize
self.mode = rawmode.split(";")[0] self._mode = rawmode.split(";")[0]
if self.mode == "RGB": if self.mode == "RGB":
self.custom_mimetype = "image/rgb" self.custom_mimetype = "image/rgb"

View File

@ -149,7 +149,7 @@ class SpiderImageFile(ImageFile.ImageFile):
self.rawmode = "F;32BF" self.rawmode = "F;32BF"
else: else:
self.rawmode = "F;32F" self.rawmode = "F;32F"
self.mode = "F" self._mode = "F"
self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))] self.tile = [("raw", (0, 0) + self.size, offset, (self.rawmode, 0, 1))]
self._fp = self.fp # FIXME: hack self._fp = self.fp # FIXME: hack

View File

@ -66,21 +66,21 @@ class SunImageFile(ImageFile.ImageFile):
palette_length = i32(s, 28) palette_length = i32(s, 28)
if depth == 1: if depth == 1:
self.mode, rawmode = "1", "1;I" self._mode, rawmode = "1", "1;I"
elif depth == 4: elif depth == 4:
self.mode, rawmode = "L", "L;4" self._mode, rawmode = "L", "L;4"
elif depth == 8: elif depth == 8:
self.mode = rawmode = "L" self._mode = rawmode = "L"
elif depth == 24: elif depth == 24:
if file_type == 3: if file_type == 3:
self.mode, rawmode = "RGB", "RGB" self._mode, rawmode = "RGB", "RGB"
else: else:
self.mode, rawmode = "RGB", "BGR" self._mode, rawmode = "RGB", "BGR"
elif depth == 32: elif depth == 32:
if file_type == 3: if file_type == 3:
self.mode, rawmode = "RGB", "RGBX" self._mode, rawmode = "RGB", "RGBX"
else: else:
self.mode, rawmode = "RGB", "BGRX" self._mode, rawmode = "RGB", "BGRX"
else: else:
msg = "Unsupported Mode/Bit Depth" msg = "Unsupported Mode/Bit Depth"
raise SyntaxError(msg) raise SyntaxError(msg)
@ -97,7 +97,7 @@ class SunImageFile(ImageFile.ImageFile):
offset = offset + palette_length offset = offset + palette_length
self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length)) self.palette = ImagePalette.raw("RGB;L", self.fp.read(palette_length))
if self.mode == "L": if self.mode == "L":
self.mode = "P" self._mode = "P"
rawmode = rawmode.replace("L", "P") rawmode = rawmode.replace("L", "P")
# 16 bit boundaries on stride # 16 bit boundaries on stride

View File

@ -76,17 +76,17 @@ class TgaImageFile(ImageFile.ImageFile):
# image mode # image mode
if imagetype in (3, 11): if imagetype in (3, 11):
self.mode = "L" self._mode = "L"
if depth == 1: if depth == 1:
self.mode = "1" # ??? self._mode = "1" # ???
elif depth == 16: elif depth == 16:
self.mode = "LA" self._mode = "LA"
elif imagetype in (1, 9): elif imagetype in (1, 9):
self.mode = "P" self._mode = "P"
elif imagetype in (2, 10): elif imagetype in (2, 10):
self.mode = "RGB" self._mode = "RGB"
if depth == 32: if depth == 32:
self.mode = "RGBA" self._mode = "RGBA"
else: else:
msg = "unknown TGA mode" msg = "unknown TGA mode"
raise SyntaxError(msg) raise SyntaxError(msg)

View File

@ -1409,7 +1409,7 @@ class TiffImageFile(ImageFile.ImageFile):
) )
logger.debug(f"format key: {key}") logger.debug(f"format key: {key}")
try: try:
self.mode, rawmode = OPEN_INFO[key] self._mode, rawmode = OPEN_INFO[key]
except KeyError as e: except KeyError as e:
logger.debug("- unsupported format") logger.debug("- unsupported format")
msg = "unknown pixel mode" msg = "unknown pixel mode"
@ -1461,7 +1461,7 @@ class TiffImageFile(ImageFile.ImageFile):
# this should always work, since all the # this should always work, since all the
# fillorder==2 modes have a corresponding # fillorder==2 modes have a corresponding
# fillorder=1 mode # fillorder=1 mode
self.mode, rawmode = OPEN_INFO[key] self._mode, rawmode = OPEN_INFO[key]
# libtiff always returns the bytes in native order. # libtiff always returns the bytes in native order.
# we're expecting image byte order. So, if the rawmode # we're expecting image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image # contains I;16, we need to convert from native to image

View File

@ -32,7 +32,7 @@ class WalImageFile(ImageFile.ImageFile):
format_description = "Quake2 Texture" format_description = "Quake2 Texture"
def _open(self): def _open(self):
self.mode = "P" self._mode = "P"
# read header fields # read header fields
header = self.fp.read(32 + 24 + 32 + 12) header = self.fp.read(32 + 24 + 32 + 12)

View File

@ -43,7 +43,7 @@ class WebPImageFile(ImageFile.ImageFile):
def _open(self): def _open(self):
if not _webp.HAVE_WEBPANIM: if not _webp.HAVE_WEBPANIM:
# Legacy mode # Legacy mode
data, width, height, self.mode, icc_profile, exif = _webp.WebPDecode( data, width, height, self._mode, icc_profile, exif = _webp.WebPDecode(
self.fp.read() self.fp.read()
) )
if icc_profile: if icc_profile:
@ -74,7 +74,7 @@ class WebPImageFile(ImageFile.ImageFile):
self.info["background"] = (bg_r, bg_g, bg_b, bg_a) self.info["background"] = (bg_r, bg_g, bg_b, bg_a)
self.n_frames = frame_count self.n_frames = frame_count
self.is_animated = self.n_frames > 1 self.is_animated = self.n_frames > 1
self.mode = "RGB" if mode == "RGBX" else mode self._mode = "RGB" if mode == "RGBX" else mode
self.rawmode = mode self.rawmode = mode
self.tile = [] self.tile = []

View File

@ -42,7 +42,7 @@ if hasattr(Image.core, "drawwmf"):
class WmfHandler: class WmfHandler:
def open(self, im): def open(self, im):
im.mode = "RGB" im._mode = "RGB"
self.bbox = im.info["wmf_bbox"] self.bbox = im.info["wmf_bbox"]
def load(self, im): def load(self, im):
@ -139,7 +139,7 @@ class WmfStubImageFile(ImageFile.StubImageFile):
msg = "Unsupported file format" msg = "Unsupported file format"
raise SyntaxError(msg) raise SyntaxError(msg)
self.mode = "RGB" self._mode = "RGB"
self._size = size self._size = size
loader = self._load() loader = self._load()

View File

@ -65,7 +65,7 @@ class XVThumbImageFile(ImageFile.ImageFile):
# parse header line (already read) # parse header line (already read)
s = s.strip().split() s = s.strip().split()
self.mode = "P" self._mode = "P"
self._size = int(s[0]), int(s[1]) self._size = int(s[0]), int(s[1])
self.palette = ImagePalette.raw("RGB", PALETTE) self.palette = ImagePalette.raw("RGB", PALETTE)

View File

@ -60,7 +60,7 @@ class XbmImageFile(ImageFile.ImageFile):
if m.group("hotspot"): if m.group("hotspot"):
self.info["hotspot"] = (int(m.group("xhot")), int(m.group("yhot"))) self.info["hotspot"] = (int(m.group("xhot")), int(m.group("yhot")))
self.mode = "1" self._mode = "1"
self._size = xsize, ysize self._size = xsize, ysize
self.tile = [("xbm", (0, 0) + self.size, m.end(), None)] self.tile = [("xbm", (0, 0) + self.size, m.end(), None)]

View File

@ -98,7 +98,7 @@ class XpmImageFile(ImageFile.ImageFile):
msg = "cannot read this XPM file" msg = "cannot read this XPM file"
raise ValueError(msg) raise ValueError(msg)
self.mode = "P" self._mode = "P"
self.palette = ImagePalette.raw("RGB", b"".join(palette)) self.palette = ImagePalette.raw("RGB", b"".join(palette))
self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))] self.tile = [("raw", (0, 0) + self.size, self.fp.tell(), ("P", 0, 1))]