From 0adeb82e9886cdedb3917e8ddfaf46f69556a991 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 12:58:02 +1000 Subject: [PATCH 1/6] Changed Image size property to be read-only by default --- Tests/test_image.py | 5 ++--- Tests/test_imagefile.py | 2 +- src/PIL/BlpImagePlugin.py | 2 +- src/PIL/BmpImagePlugin.py | 2 +- src/PIL/BufrStubImagePlugin.py | 2 +- src/PIL/CurImagePlugin.py | 2 +- src/PIL/DdsImagePlugin.py | 2 +- src/PIL/EpsImagePlugin.py | 8 ++++---- src/PIL/FitsStubImagePlugin.py | 2 +- src/PIL/FliImagePlugin.py | 2 +- src/PIL/FpxImagePlugin.py | 2 +- src/PIL/FtexImagePlugin.py | 2 +- src/PIL/GbrImagePlugin.py | 2 +- src/PIL/GdImageFile.py | 2 +- src/PIL/GifImagePlugin.py | 2 +- src/PIL/GribStubImagePlugin.py | 2 +- src/PIL/Hdf5StubImagePlugin.py | 2 +- src/PIL/IcnsImagePlugin.py | 22 +++++++++++++++++++++- src/PIL/IcoImagePlugin.py | 13 ++++++++++++- src/PIL/ImImagePlugin.py | 2 +- src/PIL/Image.py | 12 ++++++++---- src/PIL/ImtImagePlugin.py | 4 ++-- src/PIL/IptcImagePlugin.py | 2 +- src/PIL/Jpeg2KImagePlugin.py | 8 ++++---- src/PIL/JpegImagePlugin.py | 6 +++--- src/PIL/McIdasImagePlugin.py | 2 +- src/PIL/MpegImagePlugin.py | 2 +- src/PIL/MspImagePlugin.py | 2 +- src/PIL/PcdImagePlugin.py | 4 ++-- src/PIL/PcxImagePlugin.py | 2 +- src/PIL/PixarImagePlugin.py | 2 +- src/PIL/PngImagePlugin.py | 2 +- src/PIL/PpmImagePlugin.py | 2 +- src/PIL/PsdImagePlugin.py | 2 +- src/PIL/SgiImagePlugin.py | 2 +- src/PIL/SpiderImagePlugin.py | 2 +- src/PIL/SunImagePlugin.py | 2 +- src/PIL/TgaImagePlugin.py | 2 +- src/PIL/TiffImagePlugin.py | 2 +- src/PIL/WebPImagePlugin.py | 4 ++-- src/PIL/WmfImagePlugin.py | 2 +- src/PIL/XVThumbImagePlugin.py | 2 +- src/PIL/XbmImagePlugin.py | 2 +- src/PIL/XpmImagePlugin.py | 2 +- 44 files changed, 94 insertions(+), 60 deletions(-) diff --git a/Tests/test_image.py b/Tests/test_image.py index 7222e389b..ad56a079a 100644 --- a/Tests/test_image.py +++ b/Tests/test_image.py @@ -56,9 +56,8 @@ class TestImage(PillowTestCase): 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: diff --git a/Tests/test_imagefile.py b/Tests/test_imagefile.py index 837e81d30..c95611b08 100644 --- a/Tests/test_imagefile.py +++ b/Tests/test_imagefile.py @@ -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)] diff --git a/src/PIL/BlpImagePlugin.py b/src/PIL/BlpImagePlugin.py index 9b1a99ae1..398e0fa0c 100644 --- a/src/PIL/BlpImagePlugin.py +++ b/src/PIL/BlpImagePlugin.py @@ -270,7 +270,7 @@ class BlpImageFile(ImageFile.ImageFile): self._blp_alpha_encoding, = struct.unpack("= 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 diff --git a/src/PIL/BufrStubImagePlugin.py b/src/PIL/BufrStubImagePlugin.py index 16d83c74d..a1957b32a 100644 --- a/src/PIL/BufrStubImagePlugin.py +++ b/src/PIL/BufrStubImagePlugin.py @@ -47,7 +47,7 @@ class BufrStubImageFile(ImageFile.StubImageFile): # make something up self.mode = "F" - self.size = 1, 1 + self._size = 1, 1 loader = self._load() if loader: diff --git a/src/PIL/CurImagePlugin.py b/src/PIL/CurImagePlugin.py index db9ea9874..3e8f32102 100644 --- a/src/PIL/CurImagePlugin.py +++ b/src/PIL/CurImagePlugin.py @@ -63,7 +63,7 @@ class CurImageFile(BmpImagePlugin.BmpImageFile): 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 diff --git a/src/PIL/DdsImagePlugin.py b/src/PIL/DdsImagePlugin.py index 3bd65c93d..7660827c5 100644 --- a/src/PIL/DdsImagePlugin.py +++ b/src/PIL/DdsImagePlugin.py @@ -114,7 +114,7 @@ class DdsImageFile(ImageFile.ImageFile): 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)) diff --git a/src/PIL/EpsImagePlugin.py b/src/PIL/EpsImagePlugin.py index 7932ad58c..b2dec7809 100644 --- a/src/PIL/EpsImagePlugin.py +++ b/src/PIL/EpsImagePlugin.py @@ -217,7 +217,7 @@ class EpsImageFile(ImageFile.ImageFile): box = None self.mode = "RGB" - self.size = 1, 1 # FIXME: huh? + self._size = 1, 1 # FIXME: huh? # # Load EPS header @@ -244,7 +244,7 @@ class EpsImageFile(ImageFile.ImageFile): # 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: @@ -293,7 +293,7 @@ class EpsImageFile(ImageFile.ImageFile): except ValueError: break - self.size = int(x), int(y) + self._size = int(x), int(y) return s = fp.readline().strip('\r\n') @@ -331,7 +331,7 @@ class EpsImageFile(ImageFile.ImageFile): 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): diff --git a/src/PIL/FitsStubImagePlugin.py b/src/PIL/FitsStubImagePlugin.py index be926cadb..63c195c43 100644 --- a/src/PIL/FitsStubImagePlugin.py +++ b/src/PIL/FitsStubImagePlugin.py @@ -50,7 +50,7 @@ class FITSStubImageFile(ImageFile.StubImageFile): # make something up self.mode = "F" - self.size = 1, 1 + self._size = 1, 1 loader = self._load() if loader: diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index 2c190b635..c78c8c622 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -54,7 +54,7 @@ class FliImageFile(ImageFile.ImageFile): # 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]) diff --git a/src/PIL/FpxImagePlugin.py b/src/PIL/FpxImagePlugin.py index 509fd7d91..9f284fd85 100644 --- a/src/PIL/FpxImagePlugin.py +++ b/src/PIL/FpxImagePlugin.py @@ -81,7 +81,7 @@ class FpxImageFile(ImageFile.ImageFile): # size (highest resolution) - self.size = prop[0x1000002], prop[0x1000003] + self._size = prop[0x1000002], prop[0x1000003] size = max(self.size) i = 1 diff --git a/src/PIL/FtexImagePlugin.py b/src/PIL/FtexImagePlugin.py index 72378d79f..08ce0e006 100644 --- a/src/PIL/FtexImagePlugin.py +++ b/src/PIL/FtexImagePlugin.py @@ -61,7 +61,7 @@ class FtexImageFile(ImageFile.ImageFile): def _open(self): magic = struct.unpack("> 1 - self.size = (int((self.size[0] + adjust) / power), - int((self.size[1] + adjust) / power)) + self._size = (int((self.size[0] + adjust) / power), + int((self.size[1] + adjust) / power)) if self.tile: # Update the reduce and layers settings diff --git a/src/PIL/JpegImagePlugin.py b/src/PIL/JpegImagePlugin.py index e38306041..f2068189f 100644 --- a/src/PIL/JpegImagePlugin.py +++ b/src/PIL/JpegImagePlugin.py @@ -159,7 +159,7 @@ def SOF(self, marker): n = i16(self.fp.read(2))-2 s = ImageFile._safe_read(self.fp, n) - self.size = i16(s[3:]), i16(s[1:]) + self._size = i16(s[3:]), i16(s[1:]) self.bits = i8(s[0]) if self.bits != 8: @@ -390,7 +390,7 @@ class JpegImageFile(ImageFile.ImageFile): if scale >= s: break e = e[0], e[1], (e[2]-e[0]+s-1)//s+e[0], (e[3]-e[1]+s-1)//s+e[1] - self.size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s) + self._size = ((self.size[0]+s-1)//s, (self.size[1]+s-1)//s) scale = s self.tile = [(d, e, o, a)] @@ -423,7 +423,7 @@ class JpegImageFile(ImageFile.ImageFile): pass self.mode = self.im.mode - self.size = self.im.size + self._size = self.im.size self.tile = [] diff --git a/src/PIL/McIdasImagePlugin.py b/src/PIL/McIdasImagePlugin.py index 06da33f77..161fb5e50 100644 --- a/src/PIL/McIdasImagePlugin.py +++ b/src/PIL/McIdasImagePlugin.py @@ -59,7 +59,7 @@ class McIdasImageFile(ImageFile.ImageFile): raise SyntaxError("unsupported McIdas format") self.mode = mode - self.size = w[10], w[9] + self._size = w[10], w[9] offset = w[34] + w[15] stride = w[15] + w[10]*w[11]*w[14] diff --git a/src/PIL/MpegImagePlugin.py b/src/PIL/MpegImagePlugin.py index fca7f9d9f..15c7afccc 100644 --- a/src/PIL/MpegImagePlugin.py +++ b/src/PIL/MpegImagePlugin.py @@ -72,7 +72,7 @@ class MpegImageFile(ImageFile.ImageFile): raise SyntaxError("not an MPEG file") self.mode = "RGB" - self.size = s.read(12), s.read(12) + self._size = s.read(12), s.read(12) # -------------------------------------------------------------------- diff --git a/src/PIL/MspImagePlugin.py b/src/PIL/MspImagePlugin.py index b2c7a3d79..74c68172a 100644 --- a/src/PIL/MspImagePlugin.py +++ b/src/PIL/MspImagePlugin.py @@ -63,7 +63,7 @@ class MspImageFile(ImageFile.ImageFile): raise SyntaxError("bad MSP checksum") self.mode = "1" - self.size = i16(s[4:]), i16(s[6:]) + self._size = i16(s[4:]), i16(s[6:]) if s[:4] == b"DanM": self.tile = [("raw", (0, 0)+self.size, 32, ("1", 0, 1))] diff --git a/src/PIL/PcdImagePlugin.py b/src/PIL/PcdImagePlugin.py index fa95b5008..87e5792eb 100644 --- a/src/PIL/PcdImagePlugin.py +++ b/src/PIL/PcdImagePlugin.py @@ -48,14 +48,14 @@ class PcdImageFile(ImageFile.ImageFile): self.tile_post_rotate = -90 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)] def load_end(self): if self.tile_post_rotate: # Handle rotated PCDs self.im = self.im.rotate(self.tile_post_rotate) - self.size = self.im.size + self._size = self.im.size # diff --git a/src/PIL/PcxImagePlugin.py b/src/PIL/PcxImagePlugin.py index 564713a98..daa58b3f3 100644 --- a/src/PIL/PcxImagePlugin.py +++ b/src/PIL/PcxImagePlugin.py @@ -100,7 +100,7 @@ class PcxImageFile(ImageFile.ImageFile): raise IOError("unknown PCX mode") self.mode = mode - self.size = bbox[2]-bbox[0], bbox[3]-bbox[1] + self._size = bbox[2]-bbox[0], bbox[3]-bbox[1] bbox = (0, 0) + self.size logger.debug("size: %sx%s", *self.size) diff --git a/src/PIL/PixarImagePlugin.py b/src/PIL/PixarImagePlugin.py index 220577cce..d07b28d07 100644 --- a/src/PIL/PixarImagePlugin.py +++ b/src/PIL/PixarImagePlugin.py @@ -50,7 +50,7 @@ class PixarImageFile(ImageFile.ImageFile): # read rest of header s = s + self.fp.read(508) - self.size = i16(s[418:420]), i16(s[416:418]) + self._size = i16(s[418:420]), i16(s[416:418]) # get channel/depth descriptions mode = i16(s[424:426]), i16(s[426:428]) diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 4f1f0f9cf..15077fceb 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -577,7 +577,7 @@ class PngImageFile(ImageFile.ImageFile): # (believe me, I've tried ;-) 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.text = self.png.im_text # experimental self.tile = self.png.im_tile diff --git a/src/PIL/PpmImagePlugin.py b/src/PIL/PpmImagePlugin.py index 9866c9040..8002678fb 100644 --- a/src/PIL/PpmImagePlugin.py +++ b/src/PIL/PpmImagePlugin.py @@ -107,7 +107,7 @@ class PpmImageFile(ImageFile.ImageFile): self.mode = 'I' rawmode = 'I;32B' - self.size = xsize, ysize + self._size = xsize, ysize self.tile = [("raw", (0, 0, xsize, ysize), self.fp.tell(), diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index f6e04f78b..2d64ecd9e 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -71,7 +71,7 @@ class PsdImageFile(ImageFile.ImageFile): raise IOError("not enough channels") self.mode = mode - self.size = i32(s[18:]), i32(s[14:]) + self._size = i32(s[18:]), i32(s[14:]) # # color mode data diff --git a/src/PIL/SgiImagePlugin.py b/src/PIL/SgiImagePlugin.py index 113d44fac..88df35135 100644 --- a/src/PIL/SgiImagePlugin.py +++ b/src/PIL/SgiImagePlugin.py @@ -96,7 +96,7 @@ class SgiImageFile(ImageFile.ImageFile): if rawmode == "": raise ValueError("Unsupported SGI image mode") - self.size = xsize, ysize + self._size = xsize, ysize self.mode = rawmode.split(";")[0] # orientation -1 : scanlines begins at the bottom-left corner diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index a0d5f17a4..3f5795210 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -120,7 +120,7 @@ class SpiderImageFile(ImageFile.ImageFile): if iform != 1: raise SyntaxError("not a Spider 2D image") - self.size = int(h[12]), int(h[2]) # size in pixels (width, height) + self._size = int(h[12]), int(h[2]) # size in pixels (width, height) self.istack = int(h[24]) self.imgnumber = int(h[27]) diff --git a/src/PIL/SunImagePlugin.py b/src/PIL/SunImagePlugin.py index 3126bd9d6..898350e02 100644 --- a/src/PIL/SunImagePlugin.py +++ b/src/PIL/SunImagePlugin.py @@ -59,7 +59,7 @@ class SunImageFile(ImageFile.ImageFile): offset = 32 - self.size = i32(s[4:8]), i32(s[8:12]) + self._size = i32(s[4:8]), i32(s[8:12]) depth = i32(s[12:16]) # data_length = i32(s[16:20]) # unreliable, ignore. diff --git a/src/PIL/TgaImagePlugin.py b/src/PIL/TgaImagePlugin.py index 02893e837..c266d50c1 100644 --- a/src/PIL/TgaImagePlugin.py +++ b/src/PIL/TgaImagePlugin.py @@ -64,7 +64,7 @@ class TgaImageFile(ImageFile.ImageFile): flags = i8(s[17]) - self.size = i16(s[12:]), i16(s[14:]) + self._size = i16(s[12:]), i16(s[14:]) # validate header fields if colormaptype not in (0, 1) or\ diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 9a7bbdb48..8bd3bef10 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1174,7 +1174,7 @@ class TiffImageFile(ImageFile.ImageFile): # size xsize = self.tag_v2.get(IMAGEWIDTH) ysize = self.tag_v2.get(IMAGELENGTH) - self.size = xsize, ysize + self._size = xsize, ysize if DEBUG: print("- size:", self.size) diff --git a/src/PIL/WebPImagePlugin.py b/src/PIL/WebPImagePlugin.py index 08c6b26ac..03031db8f 100644 --- a/src/PIL/WebPImagePlugin.py +++ b/src/PIL/WebPImagePlugin.py @@ -42,7 +42,7 @@ class WebPImageFile(ImageFile.ImageFile): self.info["icc_profile"] = icc_profile if exif: self.info["exif"] = exif - self.size = width, height + self._size = width, height self.fp = BytesIO(data) self.tile = [("raw", (0, 0) + self.size, 0, self.mode)] self._n_frames = 1 @@ -55,7 +55,7 @@ class WebPImageFile(ImageFile.ImageFile): # Get info from decoder width, height, loop_count, bgcolor, frame_count, mode = \ self._decoder.get_info() - self.size = width, height + self._size = width, height self.info["loop"] = loop_count bg_a, bg_r, bg_g, bg_b = \ (bgcolor >> 24) & 0xFF, \ diff --git a/src/PIL/WmfImagePlugin.py b/src/PIL/WmfImagePlugin.py index 6811ddcec..81699bda7 100644 --- a/src/PIL/WmfImagePlugin.py +++ b/src/PIL/WmfImagePlugin.py @@ -143,7 +143,7 @@ class WmfStubImageFile(ImageFile.StubImageFile): raise SyntaxError("Unsupported file format") self.mode = "RGB" - self.size = size + self._size = size loader = self._load() if loader: diff --git a/src/PIL/XVThumbImagePlugin.py b/src/PIL/XVThumbImagePlugin.py index a7d39ed89..8cdd84817 100644 --- a/src/PIL/XVThumbImagePlugin.py +++ b/src/PIL/XVThumbImagePlugin.py @@ -65,7 +65,7 @@ class XVThumbImageFile(ImageFile.ImageFile): s = s.strip().split() 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) diff --git a/src/PIL/XbmImagePlugin.py b/src/PIL/XbmImagePlugin.py index b43fbef50..0cccda17c 100644 --- a/src/PIL/XbmImagePlugin.py +++ b/src/PIL/XbmImagePlugin.py @@ -63,7 +63,7 @@ class XbmImageFile(ImageFile.ImageFile): ) self.mode = "1" - self.size = xsize, ysize + self._size = xsize, ysize self.tile = [("xbm", (0, 0)+self.size, m.end(), None)] diff --git a/src/PIL/XpmImagePlugin.py b/src/PIL/XpmImagePlugin.py index a5cca0e27..02bc28a17 100644 --- a/src/PIL/XpmImagePlugin.py +++ b/src/PIL/XpmImagePlugin.py @@ -51,7 +51,7 @@ class XpmImageFile(ImageFile.ImageFile): if m: break - self.size = int(m.group(1)), int(m.group(2)) + self._size = int(m.group(1)), int(m.group(2)) pal = int(m.group(3)) bpp = int(m.group(4)) From cea6ecfdbb3c7cf48815b4ec758946481f78cf13 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 14:07:55 +1000 Subject: [PATCH 2/6] Updated example decoders [ci skip] --- docs/example/DdsImagePlugin.py | 2 +- docs/handbook/writing-your-own-file-decoder.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/example/DdsImagePlugin.py b/docs/example/DdsImagePlugin.py index 71a5b50ea..2877697aa 100644 --- a/docs/example/DdsImagePlugin.py +++ b/docs/example/DdsImagePlugin.py @@ -221,7 +221,7 @@ class DdsImageFile(ImageFile.ImageFile): 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)) diff --git a/docs/handbook/writing-your-own-file-decoder.rst b/docs/handbook/writing-your-own-file-decoder.rst index 107e25f36..2e68656ca 100644 --- a/docs/handbook/writing-your-own-file-decoder.rst +++ b/docs/handbook/writing-your-own-file-decoder.rst @@ -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]) From 6f44ae1d27fa89a9e313e0da9dbfe3d129bb0763 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 15:08:35 +1000 Subject: [PATCH 3/6] Only deprecate setting of TIFF image sizes --- Tests/test_file_tiff.py | 8 ++++++++ src/PIL/TiffImagePlugin.py | 13 +++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Tests/test_file_tiff.py b/Tests/test_file_tiff.py index a920032f3..a92c2351f 100644 --- a/Tests/test_file_tiff.py +++ b/Tests/test_file_tiff.py @@ -69,6 +69,14 @@ class TestFileTiff(PillowTestCase): 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) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 8bd3bef10..d18ca39d8 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1049,6 +1049,19 @@ class TiffImageFile(ImageFile.ImageFile): "Return the current frame number" return self.__frame + @property + def size(self): + return self._size + + @size.setter + def size(self, value): + warnings.warn( + 'Setting the size of a TIFF image direcly is deprecated, and will ' + 'be removed in a future version. Use the resize method instead.', + DeprecationWarning + ) + self._size = value + def load(self): if self.use_load_libtiff: return self._load_libtiff() From e3675f95fbdf2ebeb51dcdb945a68ed8d18c3725 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 14:47:05 +1000 Subject: [PATCH 4/6] Added tests --- Tests/test_file_icns.py | 4 ++++ Tests/test_file_ico.py | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/Tests/test_file_icns.py b/Tests/test_file_icns.py index 06a7e39bb..b19cf2e4c 100644 --- a/Tests/test_file_icns.py +++ b/Tests/test_file_icns.py @@ -64,6 +64,10 @@ class TestFileIcns(PillowTestCase): 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). diff --git a/Tests/test_file_ico.py b/Tests/test_file_ico.py index 20f21db57..d3024ee90 100644 --- a/Tests/test_file_ico.py +++ b/Tests/test_file_ico.py @@ -47,6 +47,11 @@ class TestFileIco(PillowTestCase): 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 From 2c11974b86f9bbb095a0cc54e876823854ad0a10 Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 21:09:42 +1000 Subject: [PATCH 5/6] Fixed typo --- src/PIL/TiffImagePlugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index d18ca39d8..5059a1324 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -1056,8 +1056,8 @@ class TiffImageFile(ImageFile.ImageFile): @size.setter def size(self, value): warnings.warn( - 'Setting the size of a TIFF image direcly is deprecated, and will ' - 'be removed in a future version. Use the resize method instead.', + 'Setting the size of a TIFF image directly is deprecated, and will' + ' be removed in a future version. Use the resize method instead.', DeprecationWarning ) self._size = value From 05f21695c7bbf6c3965d32dc563e66ad9d46912a Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Sun, 30 Sep 2018 21:32:46 +1000 Subject: [PATCH 6/6] Added release notes [ci skip] --- docs/releasenotes/5.3.0.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/releasenotes/5.3.0.rst b/docs/releasenotes/5.3.0.rst index 10d6ecbd2..efa84e214 100644 --- a/docs/releasenotes/5.3.0.rst +++ b/docs/releasenotes/5.3.0.rst @@ -39,6 +39,22 @@ and size, new method ``ImageOps.pad`` pads images to fill a requested aspect ratio and size, filling new space with a provided ``color`` and positioning the image within the new area through a ``centering`` argument. +Image Size +========== + +If you attempt to set the size of an image directly, e.g. +``im.size = (100, 100)``, you will now receive an ``AttributeError``. This is +not about removing existing functionality, but instead about raising an +explicit error to prevent later consequences. The ``resize`` method is the +correct way to change an image's size. + +The exceptions to this are: +* The ICO and ICNS image formats, which use ``im.size = (100, 100)`` to select +a subimage. +* The TIFF image format, which now has a ``DeprecationWarning`` for this +action, as direct image size setting was previously necessary to work around an +issue with tile extents. + Other Changes =============