From e9ef1d236dcc964c186f76156aeff5db186a2708 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Tue, 4 Feb 2020 20:14:00 +0000 Subject: [PATCH 1/7] Fix size calculation of Image.thumbnail() --- Tests/test_image_thumbnail.py | 8 ++++++++ src/PIL/Image.py | 17 ++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index de15f5e2e98..4c7e8982ac5 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -50,6 +50,14 @@ def test_aspect(): im.thumbnail((33, 33)) assert im.size == (21, 33) # ratio is 0.6363636364 + im = Image.new("L", (145, 100)) # ratio is 1.45 + im.thumbnail((50, 50)) + assert im.size ==(50, 34) # ratio is 1.47058823529 + + im = Image.new("L", (100, 145)) # ratio is 0.689655172414 + im.thumbnail((50, 50)) + assert im.size == (34, 50) # ratio is 0.68 + def test_float(): im = Image.new("L", (128, 128)) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index dec94f2d053..e1ae4a67811 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2237,19 +2237,18 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): """ # preserve aspect ratio - x, y = self.size - if x > size[0]: - y = max(round(y * size[0] / x), 1) - x = round(size[0]) - if y > size[1]: - x = max(round(x * size[1] / y), 1) - y = round(size[1]) - size = x, y - box = None + x, y = size + aspect = self.width / self.height + if x / y >= aspect: + x = max(y * aspect, 1) + else: + y = max(x / aspect, 1) + size = (round(x), round(y)) if size == self.size: return + box = None if reducing_gap is not None: res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap)) if res is not None: From e226e4ed64f7bf9da69a82568683890f9654b603 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Tue, 4 Feb 2020 20:58:54 +0000 Subject: [PATCH 2/7] Don't upscale if the image is smaller than the size --- src/PIL/Image.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index e1ae4a67811..0e9c4722b95 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2236,8 +2236,11 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): :returns: None """ - # preserve aspect ratio x, y = size + if x >= self.width and y >= self.height: + return + + # preserve aspect ratio aspect = self.width / self.height if x / y >= aspect: x = max(y * aspect, 1) @@ -2245,9 +2248,6 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): y = max(x / aspect, 1) size = (round(x), round(y)) - if size == self.size: - return - box = None if reducing_gap is not None: res = self.draft(None, (size[0] * reducing_gap, size[1] * reducing_gap)) From 6d3c7d6941a8cede2b0f4ef4e8f69e7f36e1d784 Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Tue, 4 Feb 2020 22:06:07 +0000 Subject: [PATCH 3/7] Add test against upscaling --- Tests/test_image_thumbnail.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index 4c7e8982ac5..27a552c6bfb 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -34,9 +34,9 @@ def test_aspect(): im.thumbnail((100, 100)) assert im.size == (100, 50) - im = Image.new("L", (256, 128)) - im.thumbnail((100, 50)) - assert im.size == (100, 50) + im = Image.new("L", (64, 64)) + im.thumbnail((100, 100)) + assert im.size == (64, 64) im = Image.new("L", (128, 128)) im.thumbnail((100, 100)) From 2e716de63d3cdfb8c3cfa3b301912324d530f22b Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Sat, 8 Feb 2020 23:48:30 +0000 Subject: [PATCH 4/7] Floor the size --- src/PIL/Image.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index 0e9c4722b95..cf1800bee35 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2236,7 +2236,7 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): :returns: None """ - x, y = size + x, y = map(math.floor, size) if x >= self.width and y >= self.height: return From 64c08f4dbab6b23cf8487b01e4738953b50b3f7b Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Sun, 9 Feb 2020 00:19:53 +0000 Subject: [PATCH 5/7] Fix test --- Tests/test_image_thumbnail.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index 27a552c6bfb..bb259ecde23 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -34,14 +34,14 @@ def test_aspect(): im.thumbnail((100, 100)) assert im.size == (100, 50) + im = Image.new("L", (256, 128)) + im.thumbnail((100, 50)) + assert im.size == (100, 50) + im = Image.new("L", (64, 64)) im.thumbnail((100, 100)) assert im.size == (64, 64) - im = Image.new("L", (128, 128)) - im.thumbnail((100, 100)) - assert im.size == (100, 100) - im = Image.new("L", (256, 162)) # ratio is 1.5802469136 im.thumbnail((33, 33)) assert im.size == (33, 21) # ratio is 1.5714285714 @@ -52,7 +52,7 @@ def test_aspect(): im = Image.new("L", (145, 100)) # ratio is 1.45 im.thumbnail((50, 50)) - assert im.size ==(50, 34) # ratio is 1.47058823529 + assert im.size == (50, 34) # ratio is 1.47058823529 im = Image.new("L", (100, 145)) # ratio is 0.689655172414 im.thumbnail((50, 50)) @@ -62,7 +62,7 @@ def test_aspect(): def test_float(): im = Image.new("L", (128, 128)) im.thumbnail((99.9, 99.9)) - assert im.size == (100, 100) + assert im.size == (99, 99) def test_no_resize(): From 8f21d0ddf0079ef71decd5180d159486dac6c21a Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Fri, 21 Feb 2020 23:30:35 +0000 Subject: [PATCH 6/7] Improve rounding --- Tests/test_image_thumbnail.py | 4 ++++ src/PIL/Image.py | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Tests/test_image_thumbnail.py b/Tests/test_image_thumbnail.py index bb259ecde23..f4ed8e746ff 100644 --- a/Tests/test_image_thumbnail.py +++ b/Tests/test_image_thumbnail.py @@ -58,6 +58,10 @@ def test_aspect(): im.thumbnail((50, 50)) assert im.size == (34, 50) # ratio is 0.68 + im = Image.new("L", (100, 30)) # ratio is 3.333333333333 + im.thumbnail((75, 75)) + assert im.size == (75, 23) # ratio is 3.260869565217 + def test_float(): im = Image.new("L", (128, 128)) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index cf1800bee35..cc9b349370a 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2240,13 +2240,20 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): if x >= self.width and y >= self.height: return + def round_aspect(number): + if x / y >= aspect: + key = lambda n: abs(aspect - n / y) # noqa: E731 + else: + key = lambda n: abs(aspect - x / n) # noqa: E731 + return max(min(math.floor(number), math.ceil(number), key=key), 1) + # preserve aspect ratio aspect = self.width / self.height if x / y >= aspect: - x = max(y * aspect, 1) + x = round_aspect(y * aspect) else: - y = max(x / aspect, 1) - size = (round(x), round(y)) + y = round_aspect(x / aspect) + size = (x, y) box = None if reducing_gap is not None: From 84c33abaa097b50176f33b74ef97ceda2f17b48b Mon Sep 17 00:00:00 2001 From: orlnub123 Date: Sat, 22 Feb 2020 12:30:10 +0000 Subject: [PATCH 7/7] Make key an argument --- src/PIL/Image.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/PIL/Image.py b/src/PIL/Image.py index cc9b349370a..b1e8ad3ea06 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -2240,19 +2240,15 @@ def thumbnail(self, size, resample=BICUBIC, reducing_gap=2.0): if x >= self.width and y >= self.height: return - def round_aspect(number): - if x / y >= aspect: - key = lambda n: abs(aspect - n / y) # noqa: E731 - else: - key = lambda n: abs(aspect - x / n) # noqa: E731 + def round_aspect(number, key): return max(min(math.floor(number), math.ceil(number), key=key), 1) # preserve aspect ratio aspect = self.width / self.height if x / y >= aspect: - x = round_aspect(y * aspect) + x = round_aspect(y * aspect, key=lambda n: abs(aspect - n / y)) else: - y = round_aspect(x / aspect) + y = round_aspect(x / aspect, key=lambda n: abs(aspect - x / n)) size = (x, y) box = None