From 95b50bf611b53bdff18fb00fd2d272cedf988232 Mon Sep 17 00:00:00 2001 From: Eric Soroos Date: Thu, 29 Sep 2016 13:28:24 -0700 Subject: [PATCH] Make Image.crop an immediate operation, not lazy. Fixes #1077 --- PIL/Image.py | 53 ++++++++-------------------------------- Tests/test_image_crop.py | 18 ++++++++++++++ 2 files changed, 28 insertions(+), 43 deletions(-) diff --git a/PIL/Image.py b/PIL/Image.py index 2f68e88b5..13ab24754 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -1020,10 +1020,7 @@ class Image(object): 4-tuple defining the left, upper, right, and lower pixel coordinate. - This is a lazy operation. Changes to the source image may or - may not be reflected in the cropped image. To break the - connection, call the :py:meth:`~PIL.Image.Image.load` method on - the cropped copy. + Note: Prior to Pillow 3.4.0, this was a lazy operation. :param box: The crop rectangle, as a (left, upper, right, lower)-tuple. :rtype: :py:class:`~PIL.Image.Image` @@ -1034,8 +1031,15 @@ class Image(object): if box is None: return self.copy() - # lazy operation - return _ImageCrop(self, box) + x0, y0, x1, y1 = map(int, map(round, box)) + + if x1 < x0: + x1 = x0 + if y1 < y0: + y1 = y0 + + return self._new(self.im.crop(( x0, y0, x1, y1))) + def draft(self, mode, size): """ @@ -1954,43 +1958,6 @@ class Image(object): return ImageQt.toqpixmap(self) -# -------------------------------------------------------------------- -# Lazy operations - -class _ImageCrop(Image): - - def __init__(self, im, box): - - Image.__init__(self) - - # Round to nearest integer, runs int(round(x)) when unpacking - x0, y0, x1, y1 = map(int, map(round, box)) - - if x1 < x0: - x1 = x0 - if y1 < y0: - y1 = y0 - - self.mode = im.mode - self.size = x1-x0, y1-y0 - - self.__crop = x0, y0, x1, y1 - - self.im = im.im - - def load(self): - - # lazy evaluation! - if self.__crop: - self.im = self.im.crop(self.__crop) - self.__crop = None - - if self.im: - return self.im.pixel_access(self.readonly) - - # FIXME: future versions should optimize crop/paste - # sequences! - # -------------------------------------------------------------------- # Abstract handlers. diff --git a/Tests/test_image_crop.py b/Tests/test_image_crop.py index 2a99a6213..c12e29be4 100644 --- a/Tests/test_image_crop.py +++ b/Tests/test_image_crop.py @@ -66,6 +66,24 @@ class TestImageCrop(PillowTestCase): # Assert self.assertEqual(cropped.size, (3, 5)) + def test_crop_crash(self): + #Image.crop crashes prepatch with an access violation + #apparently a use after free on windows, see + #https://github.com/python-pillow/Pillow/issues/1077 + + test_img = 'Tests/images/bmp/g/pal8-0.bmp' + extents = (1,1,10,10) + #works prepatch + img = Image.open(test_img) + img2 = img.crop(extents) + img2.load() + + # fail prepatch + img = Image.open(test_img) + img = img.crop(extents) + img.load() + + if __name__ == '__main__': unittest.main()