From 0ccfe9568f0c013798bc9b97dd4cfc47ea5e9b22 Mon Sep 17 00:00:00 2001 From: Fidel Ramos <f@fidelramos.net> Date: Tue, 10 Mar 2020 23:15:41 +0000 Subject: [PATCH] Fix image resizing failing on slim images Image operations sometimes calculate a target width or height of zero, which make Willow raise a ValueError. If an user uploads one such image it's possible to break the whole Wagtail image manager/picker/uploader for all users. The fix is to use a minimum of 1 pixel for either the target height or the width. The image might lose some aspect ratio, but it's better than an exception. --- CHANGELOG.txt | 1 + docs/releases/2.9.rst | 1 + wagtail/images/image_operations.py | 12 ++++++++++ wagtail/images/tests/test_image_operations.py | 24 +++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 489712a1ba..f8aa20d6d6 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -30,6 +30,7 @@ Changelog * Fix: `{% image ... as var %}` now clears the context variable when passed None as an image (Maylon Pedroso) * Fix: `refresh_index` method on Elasticsearch no longer fails (Lars van de Kerkhof) * Fix: Document tags no longer fail to update when replacing the document file at the same time (Matt Westcott) + * Fix: Prevent error from very tall / wide images being resized to 0 pixels (Fidel Ramos) 2.8 (03.02.2020) diff --git a/docs/releases/2.9.rst b/docs/releases/2.9.rst index b05d344480..c32ab8d287 100644 --- a/docs/releases/2.9.rst +++ b/docs/releases/2.9.rst @@ -48,6 +48,7 @@ Bug fixes * ``{% image ... as var %}`` now clears the context variable when passed None as an image (Maylon Pedroso) * ``refresh_index`` method on Elasticsearch no longer fails (Lars van de Kerkhof) * Document tags no longer fail to update when replacing the document file at the same time (Matt Westcott) + * Prevent error from very tall / wide images being resized to 0 pixels (Fidel Ramos) Upgrade considerations diff --git a/wagtail/images/image_operations.py b/wagtail/images/image_operations.py index 9eb955888a..1996b8cd77 100644 --- a/wagtail/images/image_operations.py +++ b/wagtail/images/image_operations.py @@ -182,6 +182,10 @@ class MinMaxOperation(Operation): # Unknown method return + # prevent zero width or height, it causes a ValueError on willow.resize + width = width if width > 0 else 1 + height = height if height > 0 else 1 + return willow.resize((width, height)) @@ -214,6 +218,10 @@ class WidthHeightOperation(Operation): # Unknown method return + # prevent zero width or height, it causes a ValueError on willow.resize + width = width if width > 0 else 1 + height = height if height > 0 else 1 + return willow.resize((width, height)) @@ -228,6 +236,10 @@ class ScaleOperation(Operation): width = int(image_width * scale) height = int(image_height * scale) + # prevent zero width or height, it causes a ValueError on willow.resize + width = width if width > 0 else 1 + height = height if height > 0 else 1 + return willow.resize((width, height)) diff --git a/wagtail/images/tests/test_image_operations.py b/wagtail/images/tests/test_image_operations.py index ac82747073..01694e31d3 100644 --- a/wagtail/images/tests/test_image_operations.py +++ b/wagtail/images/tests/test_image_operations.py @@ -361,6 +361,14 @@ class TestMinMaxOperation(ImageOperationTestCase): ('max-800x600', dict(width=1000, height=1000), [ ('resize', ((600, 600), ), {}), ]), + # Resize doesn't try to set zero height + ('max-400x400', dict(width=1000, height=1), [ + ('resize', ((400, 1), ), {}), + ]), + # Resize doesn't try to set zero width + ('max-400x400', dict(width=1, height=1000), [ + ('resize', ((1, 400), ), {}), + ]), ] @@ -391,6 +399,14 @@ class TestWidthHeightOperation(ImageOperationTestCase): ('height-400', dict(width=1000, height=500), [ ('resize', ((800, 400), ), {}), ]), + # Resize doesn't try to set zero height + ('width-400', dict(width=1000, height=1), [ + ('resize', ((400, 1), ), {}), + ]), + # Resize doesn't try to set zero width + ('height-400', dict(width=1, height=800), [ + ('resize', ((1, 400), ), {}), + ]), ] @@ -425,6 +441,14 @@ class TestScaleOperation(ImageOperationTestCase): ('scale-83.0322', dict(width=1000, height=500), [ ('resize', ((int(1000 * 0.830322), int(500 * 0.830322)), ), {}), ]), + # Resize doesn't try to set zero height + ('scale-50', dict(width=1000, height=1), [ + ('resize', ((500, 1), ), {}), + ]), + # Resize doesn't try to set zero width + ('scale-50', dict(width=1, height=500), [ + ('resize', ((1, 250), ), {}), + ]), ]