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 size property to be read-only by default #3203

Merged
merged 6 commits into from Sep 30, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions Tests/test_file_icns.py
Expand Up @@ -64,6 +64,10 @@ def test_sizes(self):
self.assertEqual(im2.mode, 'RGBA')
self.assertEqual(im2.size, (wr, hr))

# Check that we cannot load an incorrect size
with self.assertRaises(ValueError):
im.size = (1, 1)

def test_older_icon(self):
# This icon was made with Icon Composer rather than iconutil; it still
# uses PNG rather than JP2, however (since it was made on 10.9).
Expand Down
5 changes: 5 additions & 0 deletions Tests/test_file_ico.py
Expand Up @@ -47,6 +47,11 @@ def test_save_to_bytes(self):
self.assert_image_equal(reloaded,
hopper().resize((32, 32), Image.LANCZOS))

def test_incorrect_size(self):
im = Image.open(TEST_ICO_FILE)
with self.assertRaises(ValueError):
im.size = (1, 1)

def test_save_256x256(self):
"""Issue #2264 https://github.com/python-pillow/Pillow/issues/2264"""
# Arrange
Expand Down
8 changes: 8 additions & 0 deletions Tests/test_file_tiff.py
Expand Up @@ -69,6 +69,14 @@ def test_set_legacy_api(self):
self.assertEqual(str(e.exception),
"Not allowing setting of legacy api")

def test_size(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)

def set_size():
im.size = (256, 256)
self.assert_warning(DeprecationWarning, set_size)

def test_xyres_tiff(self):
filename = "Tests/images/pil168.tif"
im = Image.open(filename)
Expand Down
5 changes: 2 additions & 3 deletions Tests/test_image.py
Expand Up @@ -56,9 +56,8 @@ def test_width_height(self):
self.assertEqual(im.width, 1)
self.assertEqual(im.height, 2)

im.size = (3, 4)
self.assertEqual(im.width, 3)
self.assertEqual(im.height, 4)
with self.assertRaises(AttributeError) as e:
im.size = (3, 4)

def test_invalid_image(self):
if py3:
Expand Down
2 changes: 1 addition & 1 deletion Tests/test_imagefile.py
Expand Up @@ -154,7 +154,7 @@ class MockImageFile(ImageFile.ImageFile):
def _open(self):
self.rawmode = 'RGBA'
self.mode = 'RGBA'
self.size = (200, 200)
self._size = (200, 200)
self.tile = [("MOCK", (xoff, yoff, xoff+xsize, yoff+ysize), 32, None)]


Expand Down
2 changes: 1 addition & 1 deletion docs/example/DdsImagePlugin.py
Expand Up @@ -221,7 +221,7 @@ def _open(self):
header = BytesIO(header_bytes)

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

pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
Expand Down
2 changes: 1 addition & 1 deletion docs/handbook/writing-your-own-file-decoder.rst
Expand Up @@ -69,7 +69,7 @@ true color.
header = string.split(header)

# size in pixels (width, height)
self.size = int(header[1]), int(header[2])
self._size = int(header[1]), int(header[2])

# mode setting
bits = int(header[3])
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BlpImagePlugin.py
Expand Up @@ -270,7 +270,7 @@ def _read_blp_header(self):
self._blp_alpha_encoding, = struct.unpack("<b", self.fp.read(1))
self._blp_mips, = struct.unpack("<b", self.fp.read(1))

self.size = struct.unpack("<II", self.fp.read(8))
self._size = struct.unpack("<II", self.fp.read(8))

if self.magic == b"BLP1":
# Only present for BLP1
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BmpImagePlugin.py
Expand Up @@ -143,7 +143,7 @@ def _bitmap(self, header=0, offset=0):
file_info['header_size'])
# ------------------ Special case : header is reported 40, which
# ---------------------- is shorter than real size for bpp >= 16
self.size = file_info['width'], file_info['height']
self._size = file_info['width'], file_info['height']
# -------- If color count was not found in the header, compute from bits
file_info['colors'] = file_info['colors'] if file_info.get('colors', 0) else (1 << file_info['bits'])
# -------------------------------- Check abnormal values for DOS attacks
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/BufrStubImagePlugin.py
Expand Up @@ -47,7 +47,7 @@ def _open(self):

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

loader = self._load()
if loader:
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/CurImagePlugin.py
Expand Up @@ -63,7 +63,7 @@ def _open(self):
self._bitmap(i32(m[12:]) + offset)

# patch up the bitmap height
self.size = self.size[0], self.size[1]//2
self._size = self.size[0], self.size[1]//2
d, e, o, a = self.tile[0]
self.tile[0] = d, (0, 0)+self.size, o, a

Expand Down
2 changes: 1 addition & 1 deletion src/PIL/DdsImagePlugin.py
Expand Up @@ -114,7 +114,7 @@ def _open(self):
header = BytesIO(header_bytes)

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

pitch, depth, mipmaps = struct.unpack("<3I", header.read(12))
Expand Down
8 changes: 4 additions & 4 deletions src/PIL/EpsImagePlugin.py
Expand Up @@ -217,7 +217,7 @@ def _open(self):
box = None

self.mode = "RGB"
self.size = 1, 1 # FIXME: huh?
self._size = 1, 1 # FIXME: huh?

#
# Load EPS header
Expand All @@ -244,7 +244,7 @@ def _open(self):
# fields should be integers, but some drivers
# put floating point values there anyway.
box = [int(float(i)) for i in v.split()]
self.size = box[2] - box[0], box[3] - box[1]
self._size = box[2] - box[0], box[3] - box[1]
self.tile = [("eps", (0, 0) + self.size, offset,
(length, box))]
except Exception:
Expand Down Expand Up @@ -293,7 +293,7 @@ def _open(self):
except ValueError:
break

self.size = int(x), int(y)
self._size = int(x), int(y)
return

s = fp.readline().strip('\r\n')
Expand Down Expand Up @@ -331,7 +331,7 @@ def load(self, scale=1):
return
self.im = Ghostscript(self.tile, self.size, self.fp, scale)
self.mode = self.im.mode
self.size = self.im.size
self._size = self.im.size
self.tile = []

def load_seek(self, *args, **kwargs):
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FitsStubImagePlugin.py
Expand Up @@ -50,7 +50,7 @@ def _open(self):

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

loader = self._load()
if loader:
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FliImagePlugin.py
Expand Up @@ -54,7 +54,7 @@ def _open(self):

# image characteristics
self.mode = "P"
self.size = i16(s[8:10]), i16(s[10:12])
self._size = i16(s[8:10]), i16(s[10:12])

# animation speed
duration = i32(s[16:20])
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FpxImagePlugin.py
Expand Up @@ -81,7 +81,7 @@ def _open_index(self, index=1):

# size (highest resolution)

self.size = prop[0x1000002], prop[0x1000003]
self._size = prop[0x1000002], prop[0x1000003]

size = max(self.size)
i = 1
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/FtexImagePlugin.py
Expand Up @@ -61,7 +61,7 @@ class FtexImageFile(ImageFile.ImageFile):
def _open(self):
magic = struct.unpack("<I", self.fp.read(4))
version = struct.unpack("<i", self.fp.read(4))
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))

self.mode = "RGB"
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GbrImagePlugin.py
Expand Up @@ -74,7 +74,7 @@ def _open(self):
else:
self.mode = 'RGBA'

self.size = width, height
self._size = width, height

self.info["comment"] = comment

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

self.mode = "L" # FIXME: "P"
self.size = i16(s[2:4]), i16(s[4:6])
self._size = i16(s[2:4]), i16(s[4:6])

trueColor = i8(s[6])
trueColorOffset = 2 if trueColor else 0
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GifImagePlugin.py
Expand Up @@ -65,7 +65,7 @@ def _open(self):
raise SyntaxError("not a GIF file")

self.info["version"] = s[:6]
self.size = i16(s[6:]), i16(s[8:])
self._size = i16(s[6:]), i16(s[8:])
self.tile = []
flags = i8(s[10])
bits = (flags & 7) + 1
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/GribStubImagePlugin.py
Expand Up @@ -48,7 +48,7 @@ def _open(self):

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

loader = self._load()
if loader:
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/Hdf5StubImagePlugin.py
Expand Up @@ -47,7 +47,7 @@ def _open(self):

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

loader = self._load()
if loader:
Expand Down
22 changes: 21 additions & 1 deletion src/PIL/IcnsImagePlugin.py
Expand Up @@ -265,13 +265,33 @@ class IcnsImageFile(ImageFile.ImageFile):
def _open(self):
self.icns = IcnsFile(self.fp)
self.mode = 'RGBA'
self.info['sizes'] = self.icns.itersizes()
self.best_size = self.icns.bestsize()
self.size = (self.best_size[0] * self.best_size[2],
self.best_size[1] * self.best_size[2])
self.info['sizes'] = self.icns.itersizes()
# Just use this to see if it's loaded or not yet.
self.tile = ('',)

@property
def size(self):
return self._size

@size.setter
def size(self, value):
info_size = value
if info_size not in self.info['sizes'] and len(info_size) == 2:
info_size = (info_size[0], info_size[1], 1)
if info_size not in self.info['sizes'] and len(info_size) == 3 and \
info_size[2] == 1:
simple_sizes = [(size[0] * size[2], size[1] * size[2])
for size in self.info['sizes']]
if value in simple_sizes:
info_size = self.info['sizes'][simple_sizes.index(value)]
if info_size not in self.info['sizes']:
raise ValueError(
"This is not one of the allowed sizes of this image")
self._size = value

def load(self):
if len(self.size) == 3:
self.best_size = self.size
Expand Down
13 changes: 12 additions & 1 deletion src/PIL/IcoImagePlugin.py
Expand Up @@ -169,7 +169,7 @@ def frame(self, idx):
im = BmpImagePlugin.DibImageFile(self.buf)

# change tile dimension to only encompass XOR image
im.size = (im.size[0], int(im.size[1] / 2))
im._size = (im.size[0], int(im.size[1] / 2))
d, e, o, a = im.tile[0]
im.tile[0] = d, (0, 0) + im.size, o, a

Expand Down Expand Up @@ -263,6 +263,17 @@ def _open(self):
self.size = self.ico.entry[0]['dim']
self.load()

@property
def size(self):
return self._size

@size.setter
def size(self, value):
if value not in self.info['sizes']:
raise ValueError(
"This is not one of the allowed sizes of this image")
self._size = value

def load(self):
im = self.ico.getimage(self.size)
# if tile is PNG, it won't really be loaded yet
Expand Down
2 changes: 1 addition & 1 deletion src/PIL/ImImagePlugin.py
Expand Up @@ -196,7 +196,7 @@ def _open(self):
raise SyntaxError("Not an IM file")

# Basic attributes
self.size = self.info[SIZE]
self._size = self.info[SIZE]
self.mode = self.info[MODE]

# Skip forward to start of image data
Expand Down
12 changes: 8 additions & 4 deletions src/PIL/Image.py
Expand Up @@ -531,7 +531,7 @@ def __init__(self):
# FIXME: turn mode and size into delegating properties?
self.im = None
self.mode = ""
self.size = (0, 0)
self._size = (0, 0)
self.palette = None
self.info = {}
self.category = NORMAL
Expand All @@ -546,11 +546,15 @@ def width(self):
def height(self):
return self.size[1]

@property
def size(self):
return self._size

def _new(self, im):
new = Image()
new.im = im
new.mode = im.mode
new.size = im.size
new._size = im.size
if im.mode in ('P', 'PA'):
if self.palette:
new.palette = self.palette.copy()
Expand Down Expand Up @@ -698,7 +702,7 @@ def __setstate__(self, state):
info, mode, size, palette, data = state
self.info = info
self.mode = mode
self.size = size
self._size = size
self.im = core.new(mode, size)
if mode in ("L", "P") and palette:
self.putpalette(palette)
Expand Down Expand Up @@ -2104,7 +2108,7 @@ def thumbnail(self, size, resample=BICUBIC):

self.im = im.im
self.mode = im.mode
self.size = size
self._size = size

self.readonly = 0
self.pyaccess = None
Expand Down
4 changes: 2 additions & 2 deletions src/PIL/ImtImagePlugin.py
Expand Up @@ -78,10 +78,10 @@ def _open(self):
k, v = m.group(1, 2)
if k == "width":
xsize = int(v)
self.size = xsize, ysize
self._size = xsize, ysize
elif k == "height":
ysize = int(v)
self.size = xsize, ysize
self._size = xsize, ysize
elif k == "pixel" and v == "n8":
self.mode = "L"

Expand Down
2 changes: 1 addition & 1 deletion src/PIL/IptcImagePlugin.py
Expand Up @@ -118,7 +118,7 @@ def _open(self):
self.mode = "CMYK"[id]

# size
self.size = self.getint((3, 20)), self.getint((3, 30))
self._size = self.getint((3, 20)), self.getint((3, 30))

# compression
try:
Expand Down