Story 2383: Image reduction for Upload Post Images#2429
Conversation
julhoang
left a comment
There was a problem hiding this comment.
Hi @jlchilders11 , please see a couple of change requests below 🙏
44cb65f to
afd0b7a
Compare
julhoang
left a comment
There was a problem hiding this comment.
Hi @jlchilders11 ! I've just discovered Pillow has a handy thumbnail method for us to leverage, please see more below.
| if root: | ||
| file_name = root | ||
| file_name += ".webp" | ||
|
|
||
| width, height = im.size | ||
| p_width, p_height = None, None # Preferred output image width and height | ||
| s_width, s_height = ( | ||
| settings.DOWNSCALED_IMAGE_WIDTH, | ||
| settings.DOWNSCALED_IMAGE_HEIGHT, | ||
| ) # Settings based preferred width and height | ||
|
|
||
| # Scale the preferred width and height in a proportional manner, to not skew the image | ||
|
|
||
| # Scale based on the dimension that is further off from preferred dimensions | ||
| if width - s_width >= height - s_height: | ||
| p_width = s_width | ||
| p_height = math.floor((p_width / width) * height) | ||
| else: | ||
| p_height = s_height | ||
| p_width = math.floor((p_height / height) * width) | ||
|
|
||
| r_image = im.resize((p_width, p_height)) | ||
|
|
||
| # Save to a BytesIO, actual file system saving will be handled by the form calling this function | ||
| img = BytesIO() | ||
| r_image.save(img, format="webp") | ||
| img.seek(0) |
There was a problem hiding this comment.
| if root: | |
| file_name = root | |
| file_name += ".webp" | |
| width, height = im.size | |
| p_width, p_height = None, None # Preferred output image width and height | |
| s_width, s_height = ( | |
| settings.DOWNSCALED_IMAGE_WIDTH, | |
| settings.DOWNSCALED_IMAGE_HEIGHT, | |
| ) # Settings based preferred width and height | |
| # Scale the preferred width and height in a proportional manner, to not skew the image | |
| # Scale based on the dimension that is further off from preferred dimensions | |
| if width - s_width >= height - s_height: | |
| p_width = s_width | |
| p_height = math.floor((p_width / width) * height) | |
| else: | |
| p_height = s_height | |
| p_width = math.floor((p_height / height) * width) | |
| r_image = im.resize((p_width, p_height)) | |
| # Save to a BytesIO, actual file system saving will be handled by the form calling this function | |
| img = BytesIO() | |
| r_image.save(img, format="webp") | |
| img.seek(0) | |
| if root: | |
| file_name = root + ".webp" | |
| # Bake EXIF orientation into pixels so portrait phone photos don't end up sideways | |
| im = ImageOps.exif_transpose(im) | |
| # Fits within the bounding box, preserves aspect ratio, never upscales | |
| im.thumbnail( | |
| (settings.DOWNSCALED_IMAGE_WIDTH, settings.DOWNSCALED_IMAGE_HEIGHT), | |
| PImage.Resampling.LANCZOS, | |
| ) | |
| # Save to a BytesIO, actual file system saving will be handled by the form calling this function | |
| img = BytesIO() | |
| im.save(img, format="webp") | |
| img.seek(0) |
It seems like Pillow offers a handy .thumbnail() method that can handles the math for us – but more important it will not upscale the image like our approach currently permits. The suggested code also adds orientations and resampling. Can we consider using this instead?
There was a problem hiding this comment.
Good call. I saw the thumbnail function, but didn't actually realize all the edge cases it pre covered for me. Thanks!
| from news.utils import downsize_uploaded_image | ||
|
|
||
|
|
||
| def test_downscale_image(): |
There was a problem hiding this comment.
Can we add a few more tests here as well? Some cases to consider:
- Portrait image stays portrait
- Ratio is preserved
- Small image doesn't get upscaled
- New downscale images is smaller than the width and height values that we set in the config.
- Test
png_test.pngfile gets renamed topng_test.webp
There was a problem hiding this comment.
The fix for the CI test is now available on develop – would you mind doing a rebase to remove this change from your branch? 😄🙏
0d34287 to
1b4e83a
Compare
julhoang
left a comment
There was a problem hiding this comment.
This looks great! Thank you for the updates @jlchilders11 ! 🙌
085a5ba to
de75c12
Compare
Issue: #2383
Summary & Context
Adds a helper function to allow for downscaling of uploaded images if they are over the size threshold.
Changes
downsize_uploaded_imagetonews/utils.py, which accepts an uploaded image, downscales it, and returns it for consumptionSelf-review Checklist