Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changed Image mode property to be read-only by default #7307

Merged
merged 2 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ def test_width_height(self):
with pytest.raises(AttributeError):
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):
im = io.BytesIO(b"")
with pytest.raises(UnidentifiedImageError):
Expand Down
4 changes: 2 additions & 2 deletions Tests/test_imagefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def test_no_format(self):

class DummyImageFile(ImageFile.ImageFile):
def _open(self):
self.mode = "RGB"
self._mode = "RGB"
self._size = (1, 1)

im = DummyImageFile(buf)
Expand Down Expand Up @@ -217,7 +217,7 @@ def cleanup(self):
class MockImageFile(ImageFile.ImageFile):
def _open(self):
self.rawmode = "RGBA"
self.mode = "RGBA"
self._mode = "RGBA"
self._size = (200, 200)
self.tile = [("MOCK", (xoff, yoff, xoff + xsize, yoff + ysize), 32, None)]

Expand Down
4 changes: 2 additions & 2 deletions Tests/test_pickle.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ def test_pickle_la_mode_with_palette(tmp_path):

# Act / Assert
for protocol in range(0, pickle.HIGHEST_PROTOCOL + 1):
im.mode = "LA"
im._mode = "LA"
with open(filename, "wb") as f:
pickle.dump(im, f, protocol)
with open(filename, "rb") as f:
loaded_im = pickle.load(f)

im.mode = "PA"
im._mode = "PA"
assert im == loaded_im


Expand Down
2 changes: 1 addition & 1 deletion docs/example/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ def _open(self):

flags, height, width = struct.unpack("<3I", header.read(12))
self._size = (width, height)
self.mode = "RGBA"
self._mode = "RGBA"

pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
struct.unpack("<11I", header.read(44)) # reserved
Expand Down
6 changes: 3 additions & 3 deletions docs/handbook/writing-your-own-image-plugin.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ true color.
# mode setting
bits = int(header[3])
if bits == 1:
self.mode = "1"
self._mode = "1"
elif bits == 8:
self.mode = "L"
self._mode = "L"
elif bits == 24:
self.mode = "RGB"
self._mode = "RGB"
else:
msg = "unknown number of bits"
raise SyntaxError(msg)
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BlpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ def _open(self):
msg = f"Bad BLP magic {repr(self.magic)}"
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))]


Expand Down
10 changes: 5 additions & 5 deletions src/PIL/BmpImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def _bitmap(self, header=0, offset=0):
offset += 4 * file_info["colors"]

# ---------------------- 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:
msg = f"Unsupported BMP pixel depth ({file_info['bits']})"
raise OSError(msg)
Expand Down Expand Up @@ -200,7 +200,7 @@ def _bitmap(self, header=0, offset=0):
and file_info["rgba_mask"] in SUPPORTED[file_info["bits"]]
):
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 (
file_info["bits"] in (24, 16)
and file_info["rgb_mask"] in SUPPORTED[file_info["bits"]]
Expand All @@ -214,7 +214,7 @@ def _bitmap(self, header=0, offset=0):
raise OSError(msg)
elif file_info["compression"] == self.RAW:
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):
decoder_name = "bmp_rle"
else:
Expand Down Expand Up @@ -245,10 +245,10 @@ def _bitmap(self, header=0, offset=0):

# ------- If all colors are grey, white or black, ditch palette
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
else:
self.mode = "P"
self._mode = "P"
self.palette = ImagePalette.raw(
"BGRX" if padding == 4 else "BGR", palette
)
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BufrStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _open(self):
self.fp.seek(offset)

# make something up
self.mode = "F"
self._mode = "F"
self._size = 1, 1

loader = self._load()
Expand Down
22 changes: 11 additions & 11 deletions src/PIL/DdsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def _open(self):

flags, height, width = struct.unpack("<3I", header.read(12))
self._size = (width, height)
self.mode = "RGBA"
self._mode = "RGBA"

pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
struct.unpack("<11I", header.read(44)) # reserved
Expand All @@ -141,9 +141,9 @@ def _open(self):
if pfflags & DDPF_LUMINANCE:
# Texture contains uncompressed L or LA data
if pfflags & DDPF_ALPHAPIXELS:
self.mode = "LA"
self._mode = "LA"
else:
self.mode = "L"
self._mode = "L"

self.tile = [("raw", (0, 0) + self.size, 0, (self.mode, 0, 1))]
elif pfflags & DDPF_RGB:
Expand All @@ -153,7 +153,7 @@ def _open(self):
if pfflags & DDPF_ALPHAPIXELS:
rawmode += masks[0xFF000000]
else:
self.mode = "RGB"
self._mode = "RGB"
rawmode += masks[0xFF0000] + masks[0xFF00] + masks[0xFF]

self.tile = [("raw", (0, 0) + self.size, 0, (rawmode[::-1], 0, 1))]
Expand All @@ -172,15 +172,15 @@ def _open(self):
elif fourcc == b"ATI1":
self.pixel_format = "BC4"
n = 4
self.mode = "L"
self._mode = "L"
elif fourcc == b"ATI2":
self.pixel_format = "BC5"
n = 5
self.mode = "RGB"
self._mode = "RGB"
elif fourcc == b"BC5S":
self.pixel_format = "BC5S"
n = 5
self.mode = "RGB"
self._mode = "RGB"
elif fourcc == b"DX10":
data_start += 20
# ignoring flags which pertain to volume textures and cubemaps
Expand All @@ -189,19 +189,19 @@ def _open(self):
if dxgi_format in (DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM):
self.pixel_format = "BC5"
n = 5
self.mode = "RGB"
self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC5_SNORM:
self.pixel_format = "BC5S"
n = 5
self.mode = "RGB"
self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_UF16:
self.pixel_format = "BC6H"
n = 6
self.mode = "RGB"
self._mode = "RGB"
elif dxgi_format == DXGI_FORMAT_BC6H_SF16:
self.pixel_format = "BC6HS"
n = 6
self.mode = "RGB"
self._mode = "RGB"
elif dxgi_format in (DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM):
self.pixel_format = "BC7"
n = 7
Expand Down
8 changes: 4 additions & 4 deletions src/PIL/EpsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def _open(self):
# go to offset - start of "%!PS"
self.fp.seek(offset)

self.mode = "RGB"
self._mode = "RGB"
self._size = None

byte_arr = bytearray(255)
Expand Down Expand Up @@ -344,10 +344,10 @@ def check_required_header_comments():
]

if bit_depth == 1:
self.mode = "1"
self._mode = "1"
elif bit_depth == 8:
try:
self.mode = self.mode_map[mode_id]
self._mode = self.mode_map[mode_id]
except ValueError:
break
else:
Expand Down Expand Up @@ -391,7 +391,7 @@ def load(self, scale=1, transparency=False):
# Load EPS via Ghostscript
if self.tile:
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.tile = []
return Image.Image.load(self)
Expand Down
8 changes: 4 additions & 4 deletions src/PIL/FitsImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@

number_of_bits = int(headers[b"BITPIX"])
if number_of_bits == 8:
self.mode = "L"
self._mode = "L"
elif number_of_bits == 16:
self.mode = "I"
self._mode = "I"

Check warning on line 56 in src/PIL/FitsImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/FitsImagePlugin.py#L56

Added line #L56 was not covered by tests
# rawmode = "I;16S"
elif number_of_bits == 32:
self.mode = "I"
self._mode = "I"

Check warning on line 59 in src/PIL/FitsImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/FitsImagePlugin.py#L59

Added line #L59 was not covered by tests
elif number_of_bits in (-32, -64):
self.mode = "F"
self._mode = "F"

Check warning on line 61 in src/PIL/FitsImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/FitsImagePlugin.py#L61

Added line #L61 was not covered by tests
# rawmode = "F" if number_of_bits == -32 else "F;64F"

offset = math.ceil(self.fp.tell() / 2880) * 2880
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FliImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def _open(self):
self.is_animated = self.n_frames > 1

# image characteristics
self.mode = "P"
self._mode = "P"
self._size = i16(s, 8), i16(s, 10)

# animation speed
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FpxImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def _open_index(self, index=1):
# note: for now, we ignore the "uncalibrated" flag
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
self.jpeg = {}
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/FtexImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def _open(self):
self._size = 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.
# I don't know of any multi-format file.
Expand All @@ -90,7 +90,7 @@ def _open(self):
data = self.fp.read(mipmap_size)

if format == Format.DXT1:
self.mode = "RGBA"
self._mode = "RGBA"
self.tile = [("bcn", (0, 0) + self.size, 0, 1)]
elif format == Format.UNCOMPRESSED:
self.tile = [("raw", (0, 0) + self.size, 0, ("RGB", 0, 1))]
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/GbrImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@
comment = self.fp.read(comment_length)[:-1]

if color_depth == 1:
self.mode = "L"
self._mode = "L"

Check warning on line 76 in src/PIL/GbrImagePlugin.py

View check run for this annotation

Codecov / codecov/patch

src/PIL/GbrImagePlugin.py#L76

Added line #L76 was not covered by tests
else:
self.mode = "RGBA"
self._mode = "RGBA"

self._size = width, height

Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GdImageFile.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _open(self):
msg = "Not a valid GD 2.x .gd file"
raise SyntaxError(msg)

self.mode = "L" # FIXME: "P"
self._mode = "L" # FIXME: "P"
self._size = i16(s, 2), i16(s, 4)

true_color = s[6]
Expand Down
18 changes: 9 additions & 9 deletions src/PIL/GifImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,11 @@ def _seek(self, frame, update_image=True):
if frame == 0:
if self._frame_palette:
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:
self.mode = "P"
self._mode = "P"
else:
self.mode = "L"
self._mode = "L"

if not palette and self.global_palette:
from copy import copy
Expand All @@ -325,10 +325,10 @@ def _seek(self, frame, update_image=True):
if "transparency" in self.info:
self.im.putpalettealpha(self.info["transparency"], 0)
self.im = self.im.convert("RGBA", Image.Dither.FLOYDSTEINBERG)
self.mode = "RGBA"
self._mode = "RGBA"
del self.info["transparency"]
else:
self.mode = "RGB"
self._mode = "RGB"
self.im = self.im.convert("RGB", Image.Dither.FLOYDSTEINBERG)

def _rgb(color):
Expand Down Expand Up @@ -424,7 +424,7 @@ def load_prepare(self):
self.im.putpalette(*self._frame_palette.getdata())
else:
self.im = None
self.mode = temp_mode
self._mode = temp_mode
self._frame_palette = None

super().load_prepare()
Expand All @@ -434,9 +434,9 @@ def load_end(self):
if self.mode == "P" and LOADING_STRATEGY == LoadingStrategy.RGB_ALWAYS:
if self._frame_transparency is not None:
self.im.putpalettealpha(self._frame_transparency, 0)
self.mode = "RGBA"
self._mode = "RGBA"
else:
self.mode = "RGB"
self._mode = "RGB"
self.im = self.im.convert(self.mode, Image.Dither.FLOYDSTEINBERG)
return
if not self._prev_im:
Expand All @@ -449,7 +449,7 @@ def load_end(self):
frame_im = self._crop(frame_im, self.dispose_extent)

self.im = self._prev_im
self.mode = self.im.mode
self._mode = self.im.mode
if frame_im.mode == "RGBA":
self.im.paste(frame_im, self.dispose_extent, frame_im)
else:
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GribStubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _open(self):
self.fp.seek(offset)

# make something up
self.mode = "F"
self._mode = "F"
self._size = 1, 1

loader = self._load()
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/Hdf5StubImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def _open(self):
self.fp.seek(offset)

# make something up
self.mode = "F"
self._mode = "F"
self._size = 1, 1

loader = self._load()
Expand Down
Loading
Loading