Make Image.crop an immediate operation, not lazy. Fixes #1077

This commit is contained in:
Eric Soroos 2016-09-29 13:28:24 -07:00
parent 2178da8ec2
commit 95b50bf611
2 changed files with 28 additions and 43 deletions

View File

@ -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.

View File

@ -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()