diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index 0f2955574..a6d64051c 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -60,7 +60,8 @@ class TestImageThumbnail(PillowTestCase): im.paste(Image.new("RGB", (235, 235)), (11, 11)) thumb = fromstring(tostring(im, "JPEG", quality=99, subsampling=0)) - thumb.thumbnail((32, 32), Image.BICUBIC) + # small max_reduce to amplify the effect + thumb.thumbnail((32, 32), Image.BICUBIC, max_reduce=1.0) ref = im.resize((32, 32), Image.BICUBIC) # This is still JPEG, some error is present. Without the fix it is 11.5 diff --git a/src/PIL/IcoImagePlugin.py b/src/PIL/IcoImagePlugin.py index 19cb548a6..e43dfa9aa 100644 --- a/src/PIL/IcoImagePlugin.py +++ b/src/PIL/IcoImagePlugin.py @@ -63,8 +63,9 @@ def _save(im, fp, filename): fp.write(struct.pack(" 1 or y_factor > 1: + self = self.reduce((x_factor, y_factor)) + box = ( + box[0] / x_factor, + box[1] / y_factor, + box[2] / x_factor, + box[3] / y_factor, + ) + return self._new(self.im.resize(size, resample, box)) def reduce(self, factor, box=None): @@ -2147,7 +2174,7 @@ class Image: """ return 0 - def thumbnail(self, size, resample=BICUBIC): + def thumbnail(self, size, resample=BICUBIC, max_reduce=2.0): """ Make this image into a thumbnail. This method modifies the image to contain a thumbnail version of itself, no larger than @@ -2166,7 +2193,21 @@ class Image: of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BILINEAR`, :py:attr:`PIL.Image.BICUBIC`, or :py:attr:`PIL.Image.LANCZOS`. If omitted, it defaults to :py:attr:`PIL.Image.BICUBIC`. - (was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0) + (was :py:attr:`PIL.Image.NEAREST` prior to version 2.5.0). + :param max_reduce: Apply optimization by resizing the image + in two steps. First, reducing the image in integer times + using :py:meth:`~PIL.Image.Image.reduce` or + :py:meth:`~PIL.Image.Image.draft` for JPEG images. + Second, resizing using regular resampling. The last step + changes size not less than in ``max_reduce`` times. + ``max_reduce`` could be None (no first step is performed) + or should be greater than 1.0. The bigger `max_reduce`, + the closer the result to the fair resampling. + The smaller `max_reduce`, the faster resizing. + With `max_reduce` greater or equal to 3.0 result is + indistinguishable from fair resampling in most cases. + The default value is 2.0 (very close to fair resampling + while still faster in many cases). :returns: None """ @@ -2184,12 +2225,13 @@ class Image: if size == self.size: return - res = self.draft(None, size) - if res is not None: - box = res[1] + if max_reduce is not None: + res = self.draft(None, (size[0] * max_reduce, size[1] * max_reduce)) + if res is not None: + box = res[1] if self.size != size: - im = self.resize(size, resample, box=box) + im = self.resize(size, resample, box=box, max_reduce=max_reduce) self.im = im.im self._size = size