[IMP] tools,base,web,website_*: keep image ratio on resize

* = website_partner, website_profile, website_sale, website_slides

Before
======

Since commit: 2e3848b394

The images that are resized have additional borders if the target ratio is
different than the image ratio. Those borders are transparent if the image
format supports it, and are white otherwise.

With that current solution, if the background where the image is displayed is
another color than white, it is looking really bad.

Moreover, most images are stored resized like this, so it is not even possible
to decide if it should have borders or not depending on the context, the
original image and ratio is forever lost.

It is also inconsistent because if the image is already smaller than the target
size then it doesn't include borders. In that case it keeps the original ratio
instead of the target ratio. So it isn't even guaranteed that the target
ratio is going to be respected.

After
=====

This commit will solve all of those problems by always keeping the ratio of the
original image.

This implies the views should be taking care of adding borders when necessary.

task-1958000
PR: #31811
This commit is contained in:
Sébastien Theys
2019-04-29 13:45:03 +00:00
parent b230114fcf
commit d870877967
12 changed files with 75 additions and 173 deletions
+1 -1
View File
@@ -168,7 +168,7 @@ class ProductProduct(models.Model):
for record in self:
images = tools.image_get_resized_images(record.image_raw_original, big_name=False)
record.image_raw_big = tools.image_get_resized_images(record.image_raw_original,
large_name=False, medium_name=False, small_name=False, preserve_aspect_ratio=True)['image']
large_name=False, medium_name=False, small_name=False)['image']
record.image_raw_large = images['image_large']
record.image_raw_medium = images['image_medium']
record.image_raw_small = images['image_small']
+3 -3
View File
@@ -1023,8 +1023,8 @@ class Binary(http.Controller):
'/web/image/<int:id>-<string:unique>/<int:width>x<int:height>/<string:filename>'], type='http', auth="public")
def content_image(self, xmlid=None, model='ir.attachment', id=None, field='datas',
filename_field='datas_fname', unique=None, filename=None, mimetype=None,
download=None, width=0, height=0, crop=False, access_token=None, avoid_if_small=False,
upper_limit=False, placeholder='placeholder.png', **kw):
download=None, width=0, height=0, crop=False, access_token=None,
placeholder='placeholder.png', **kwargs):
status, headers, image_base64 = request.env['ir.http'].binary_content(
xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename,
filename_field=filename_field, download=download, mimetype=mimetype,
@@ -1041,7 +1041,7 @@ class Binary(http.Controller):
image_base64 = getattr(odoo.tools, 'image_resize_image_%s' % suffix)(image_base64)
image_base64 = limited_image_resize(
image_base64, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small)
image_base64, width=width, height=height, crop=crop)
content = base64.b64decode(image_base64)
headers.append(('Content-Length', len(content)))
+1 -2
View File
@@ -45,7 +45,6 @@ class Image(models.AbstractModel):
sha = hashlib.sha1(str(getattr(record, '__last_update')).encode('utf-8')).hexdigest()[0:7]
max_size = '' if max_size is None else '/%s' % max_size
avoid_if_small = '&avoid_if_small=true' if options.get('avoid_if_small') else ''
if options.get('filename-field') and getattr(record, options['filename-field'], None):
filename = record[options['filename-field']]
@@ -54,7 +53,7 @@ class Image(models.AbstractModel):
else:
filename = record.display_name
src = '/web/image/%s/%s/%s%s/%s?unique=%s%s' % (record._name, record.id, options.get('preview_image', field_name), max_size, url_quote(filename), sha, avoid_if_small)
src = '/web/image/%s/%s/%s%s/%s?unique=%s' % (record._name, record.id, options.get('preview_image', field_name), max_size, url_quote(filename), sha)
if options.get('alt-field') and getattr(record, options['alt-field'], None):
alt = escape(record[options['alt-field']])
+2 -2
View File
@@ -13,10 +13,10 @@ class TestImage(HttpCase):
"""The goal of this test is to make sure the placeholder image is
resized appropriately depending on the given URL parameters."""
# CASE: resize placeholder to given size
# CASE: resize placeholder, given size but original ratio is always kept
response = self.url_open('/web/image/0/200x150')
image = Image.open(io.BytesIO(response.content))
self.assertEqual(image.size, (200, 150))
self.assertEqual(image.size, (150, 150))
# CASE: resize placeholder to small
response = self.url_open('/web/image/fake/0/image_small')
@@ -17,7 +17,7 @@
<template id="partner_detail" name="Partner Details">
<h1 class="col-lg-12 text-center" id="partner_name" t-field="partner.display_name"/>
<div class="col-lg-4">
<div t-field="partner.image" t-options='{"widget": "image", "class": "d-block mx-auto mb16", "max_width": 512, "avoid_if_small": True}'/>
<div t-field="partner.image" t-options='{"widget": "image", "class": "d-block mx-auto mb16", "max_width": 512}'/>
<address>
<div t-field="partner.self" t-options='{
"widget": "contact",
+2 -2
View File
@@ -80,7 +80,7 @@ class WebsiteProfile(http.Controller):
@http.route([
'/profile/avatar/<int:user_id>',
], type='http', auth="public", website=True, sitemap=False)
def get_user_profile_avatar(self, user_id, field='image_large', width=0, height=0, crop=False, avoid_if_small=False, upper_limit=False, **post):
def get_user_profile_avatar(self, user_id, field='image_large', width=0, height=0, crop=False, **post):
if field not in ('image_small', 'image_medium', 'image_large'):
return werkzeug.exceptions.Forbidden()
@@ -102,7 +102,7 @@ class WebsiteProfile(http.Controller):
image_base64 = self._get_default_avatar(field, headers, width, height)
image_base64 = tools.limited_image_resize(
image_base64, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small)
image_base64, width=width, height=height, crop=crop)
content = base64.b64decode(image_base64)
headers.append(('Content-Length', len(content)))
@@ -167,37 +167,37 @@ class TestWebsiteSaleImage(odoo.tests.HttpCase):
self.assertEqual(product_red.image_big, product_red.image)
self.assertEqual(product_green.image_big, product_green.image)
# Verify large size
# Verify large size: keep aspect ratio
image = Image.open(io.BytesIO(base64.b64decode(template.image_large)))
self.assertEqual(image.size, (256, 256))
self.assertEqual(image.size, (256, 144))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (65, 105, 225), "blue")
image = Image.open(io.BytesIO(base64.b64decode(product_red.image_large)))
self.assertEqual(image.size, (256, 256))
self.assertEqual(image.size, (256, 160))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (205, 92, 92), "red")
image = Image.open(io.BytesIO(base64.b64decode(product_green.image_large)))
self.assertEqual(image.size, (256, 256))
self.assertEqual(image.size, (256, 144))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (34, 139, 34), "green")
# Verify medium size
# Verify medium size: keep aspect ratio
image = Image.open(io.BytesIO(base64.b64decode(template.image_medium)))
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.size, (128, 72))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (65, 105, 225), "blue")
image = Image.open(io.BytesIO(base64.b64decode(product_red.image_medium)))
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.size, (128, 80))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (205, 92, 92), "red")
image = Image.open(io.BytesIO(base64.b64decode(product_green.image_medium)))
self.assertEqual(image.size, (128, 128))
self.assertEqual(image.size, (128, 72))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (34, 139, 34), "green")
# Verify small size
# Verify small size: keep aspect ratio
image = Image.open(io.BytesIO(base64.b64decode(template.image_small)))
self.assertEqual(image.size, (64, 64))
self.assertEqual(image.size, (64, 36))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (65, 105, 225), "blue")
image = Image.open(io.BytesIO(base64.b64decode(product_red.image_small)))
self.assertEqual(image.size, (64, 64))
self.assertEqual(image.size, (64, 40))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (205, 92, 92), "red")
image = Image.open(io.BytesIO(base64.b64decode(product_green.image_small)))
self.assertEqual(image.size, (64, 64))
self.assertEqual(image.size, (64, 36))
self.assertEqual(image.getpixel((image.size[0] / 2, image.size[1] / 2)), (34, 139, 34), "green")
# self.env.cr.commit() # uncomment to save the product to test in browser
+2 -2
View File
@@ -506,7 +506,7 @@ class WebsiteSlides(WebsiteProfile):
return response
@http.route('/slides/slide/<int:slide_id>/get_image', type='http', auth="public", website=True, sitemap=False)
def slide_get_image(self, slide_id, field='image_medium', width=0, height=0, crop=False, avoid_if_small=False, upper_limit=False):
def slide_get_image(self, slide_id, field='image_medium', width=0, height=0, crop=False):
# Protect infographics by limiting access to 256px (large) images
if field not in ('image_small', 'image_medium', 'image_large'):
return werkzeug.exceptions.Forbidden()
@@ -527,7 +527,7 @@ class WebsiteSlides(WebsiteProfile):
image_base64 = self._get_default_avatar(field, headers, width, height)
image_base64 = tools.limited_image_resize(
image_base64, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small)
image_base64, width=width, height=height, crop=crop)
content = base64.b64decode(image_base64)
headers.append(('Content-Length', len(content)))
+1 -1
View File
@@ -28,7 +28,7 @@ class ImageMixin(models.AbstractModel):
for record in self:
images = tools.image_get_resized_images(record.image_original, big_name=False)
record.image_big = tools.image_get_resized_images(record.image_original,
large_name=False, medium_name=False, small_name=False, preserve_aspect_ratio=True)['image']
large_name=False, medium_name=False, small_name=False)['image']
record.image_large = images['image_large']
record.image_medium = images['image_medium']
record.image_small = images['image_small']
+2 -2
View File
@@ -572,7 +572,7 @@ class Partner(models.Model):
("The selected company is not compatible with the companies of the related user(s)"))
# no padding on the big image, because it's used as website logo
tools.image_resize_images(vals, return_big=False)
tools.image_resize_images(vals, return_medium=False, return_small=False, preserve_aspect_ratio=True)
tools.image_resize_images(vals, return_medium=False, return_small=False)
result = True
# To write in SUPERUSER on field is_company and avoid access rights problems.
@@ -601,7 +601,7 @@ class Partner(models.Model):
vals['image'] = self._get_default_image(vals.get('type'), vals.get('is_company'), vals.get('parent_id'))
# no padding on the big image, because it's used as website logo
tools.image_resize_images(vals, return_big=False)
tools.image_resize_images(vals, return_medium=False, return_small=False, preserve_aspect_ratio=True)
tools.image_resize_images(vals, return_medium=False, return_small=False)
partners = super(Partner, self).create(vals_list)
if self.env.context.get('_partners_skip_fields_sync'):
+20 -33
View File
@@ -20,7 +20,6 @@ class TestImage(TransactionCase):
- image_resize_image_small
- image_get_resized_images
- image_resize_images
- image_resize_and_sharpen
- is_image_size_above
"""
def setUp(self):
@@ -72,13 +71,13 @@ class TestImage(TransactionCase):
res = tools.image_resize_image(self.base64_svg)
self.assertEqual(res, self.base64_svg)
# CASE: ok with default parameters
# CASE: ok with default parameters (keep ratio)
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080))
self.assertEqual(image.size, tools.IMAGE_BIG_SIZE)
self.assertEqual(image.size, (1024, 576))
# CASE: correct resize
# CASE: correct resize (keep ratio)
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(800, 600)))
self.assertEqual(image.size, (800, 600))
self.assertEqual(image.size, (800, 450))
# CASE: change filetype to PNG
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, filetype='PNG'))
@@ -105,41 +104,33 @@ class TestImage(TransactionCase):
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(None, 108)))
self.assertEqual(image.size, (192, 108))
# CASE: resize above original size
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(3000, 2000)))
self.assertEqual(image.size, (3000, 2000))
# CASE: avoid_if_small=True and size above, return original
res = tools.image_resize_image(self.base64_image_1920_1080, size=(3000, 2000), avoid_if_small=True)
# CASE: size above, return original
res = tools.image_resize_image(self.base64_image_1920_1080, size=(3000, 2000))
self.assertEqual(res, self.base64_image_1920_1080)
# CASE: same size, no sharpen
# CASE: same size, no change
res = tools.image_resize_image(self.base64_image_1920_1080, size=(1920, 1080))
self.assertEqual(res, self.base64_image_1920_1080)
# CASE: upper_limit=True, no resize if above
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(3000, 2000), upper_limit=True))
self.assertEqual(image.size, (1920, 1080))
# CASE: no resize if above
res = tools.image_resize_image(self.base64_image_1920_1080, size=(3000, None))
self.assertEqual(res, self.base64_image_1920_1080)
# CASE: upper_limit=True, keep ratio, no resize if above
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(3000, None), upper_limit=True))
self.assertEqual(image.size, (1920, 1080))
# CASE: no resize if above
res = tools.image_resize_image(self.base64_image_1920_1080, size=(None, 2000))
self.assertEqual(res, self.base64_image_1920_1080)
# CASE: upper_limit=True, keep ratio, no resize if above
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(None, 2000), upper_limit=True))
self.assertEqual(image.size, (1920, 1080))
# CASE: upper_limit=True, vertical image, correct resize if below
# CASE: vertical image, correct resize if below
base64_image_1080_1920 = tools.image_to_base64(PIL.Image.new('RGB', (1080, 1920)), 'PNG')
image = tools.base64_to_image(tools.image_resize_image(base64_image_1080_1920, size=(3000, 192), upper_limit=True))
image = tools.base64_to_image(tools.image_resize_image(base64_image_1080_1920, size=(3000, 192)))
self.assertEqual(image.size, (108, 192))
# CASE: preserve_aspect_ratio=True, adapt to width
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(192, 200), preserve_aspect_ratio=True))
# CASE: adapt to width
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(192, 200)))
self.assertEqual(image.size, (192, 108))
# CASE: preserve_aspect_ratio=True, adapt to height
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(400, 108), preserve_aspect_ratio=True))
# CASE: adapt to height
image = tools.base64_to_image(tools.image_resize_image(self.base64_image_1920_1080, size=(400, 108)))
self.assertEqual(image.size, (192, 108))
def test_11_image_optimize_for_web(self):
@@ -257,12 +248,8 @@ class TestImage(TransactionCase):
image = tools.base64_to_image(tools.limited_image_resize(self.base64_image_1920_1080, width=192, height=108, crop=True))
self.assertEqual(image.size, (108, 108))
# CASE: if not upper_limit, max 500px * 500px
# keep ratio
image = tools.base64_to_image(tools.limited_image_resize(self.base64_image_1920_1080, width=1000, height=1000))
self.assertEqual(image.size, (500, 500))
# CASE: if upper_limit=True, no limit
image = tools.base64_to_image(tools.limited_image_resize(self.base64_image_1920_1080, width=1000, height=1000, upper_limit=True))
self.assertEqual(image.size, (1000, 562))
def test_17_image_data_uri(self):
+28 -112
View File
@@ -4,7 +4,6 @@ import base64
import io
from PIL import Image
from PIL import ImageEnhance
from random import randrange
from odoo.tools.translate import _
@@ -37,25 +36,10 @@ IMAGE_MAX_RESOLUTION = 45e6
# Image resizing
# ----------------------------------------
def image_resize_image(base64_source, size=IMAGE_BIG_SIZE, filetype=None, avoid_if_small=False, preserve_aspect_ratio=False, upper_limit=False):
def image_resize_image(base64_source, size=IMAGE_BIG_SIZE, filetype=None):
""" Function to resize an image. The image will be resized to the given
size, while keeping the aspect ratios, and holes in the image will be
filled with transparent background. The image will not be stretched if
size, while keeping the aspect ratios. The image will not be resized if
smaller than the expected size.
Steps of the resizing:
- Compute width and height if not specified.
- if avoid_if_small: if both image sizes are smaller than the requested
sizes, the original image is returned. This is used to avoid adding
transparent content around images that we do not want to alter but
just resize if too big. This is used for example when storing images
in the 'image' field: we keep the original image, resized to a maximal
size, without adding transparent content around it if smaller.
- create a thumbnail of the source image through using the thumbnail
function. Aspect ratios are preserved when using it. Note that if the
source image is smaller than the expected size, it will not be
extended, but filled to match the size.
- create a transparent background that will hold the final image.
- paste the thumbnail on the transparent background and center it.
:param base64_source: base64-encoded version of the source
image; if False, returns False
@@ -64,16 +48,15 @@ def image_resize_image(base64_source, size=IMAGE_BIG_SIZE, filetype=None, avoid_
on height or width of the source image.
:param filetype: the output filetype, by default the source image's
:type filetype: str, any PIL image format (supported for creation)
:param avoid_if_small: do not resize if image height and width
are smaller than the expected size.
"""
if not base64_source:
return False
# Return unmodified content if no resize or we etect first 6 bits of '<'
# (0x3C) for SVG documents - This will bypass XML files as well, but it's
# harmless for these purposes
if size == (None, None) or base64_source[:1] == b'P':
if base64_source[:1] == b'P':
return base64_source
image = base64_to_image(base64_source)
# store filetype here, as Image.new below will lose image.format
filetype = (filetype or image.format).upper()
@@ -82,64 +65,19 @@ def image_resize_image(base64_source, size=IMAGE_BIG_SIZE, filetype=None, avoid_
'BMP': 'PNG',
}.get(filetype, filetype)
asked_width, asked_height = size
if upper_limit:
if asked_width:
asked_width = min(asked_width, image.size[0])
if asked_height:
asked_height = min(asked_height, image.size[1])
if size and (size[0] or size[1]):
w, h = image.size
asked_width = size[0] or (w * size[1]) // h
asked_height = size[1] or (h * size[0]) // w
if image.size[0] >= image.size[1]:
asked_height = None
else:
asked_width = None
if asked_width is None and asked_height is None:
return base64_source
image.thumbnail((asked_width, asked_height), Image.LANCZOS)
if asked_width is None:
asked_width = int(image.size[0] * (float(asked_height) / image.size[1]))
if asked_height is None:
asked_height = int(image.size[1] * (float(asked_width) / image.size[0]))
size = asked_width, asked_height
# check image size: do not create a thumbnail if avoiding smaller images
if avoid_if_small and image.size[0] <= size[0] and image.size[1] <= size[1]:
return base64_source
if image.size != size:
image = image_resize_and_sharpen(image, size, preserve_aspect_ratio=preserve_aspect_ratio)
if image.mode not in ["1", "L", "P", "RGB", "RGBA"] or (filetype == 'JPEG' and image.mode == 'RGBA'):
image = image.convert("RGB")
return image_to_base64(image, filetype)
def image_resize_and_sharpen(image, size, preserve_aspect_ratio=False, factor=2.0):
"""
Create a thumbnail by resizing while keeping ratio.
A sharpen filter is applied for a better looking result.
:param image: PIL.Image.Image()
:param size: 2-tuple(width, height)
:param preserve_aspect_ratio: boolean (default: False)
:param factor: Sharpen factor (default: 2.0)
"""
origin_mode = image.mode
if image.mode != 'RGBA':
image = image.convert('RGBA')
image.thumbnail(size, Image.LANCZOS)
if preserve_aspect_ratio:
size = image.size
sharpener = ImageEnhance.Sharpness(image)
resized_image = sharpener.enhance(factor)
# create a transparent image for background and paste the image on it
image = Image.new('RGBA', size, (255, 255, 255, 0))
image.paste(resized_image, ((size[0] - resized_image.size[0]) // 2, (size[1] - resized_image.size[1]) // 2))
if image.mode != origin_mode:
image = image.convert(origin_mode)
return image
def image_optimize_for_web(base64_source, max_width=0, quality=80):
"""Return the given `base64_source` optimized for web usage.
@@ -197,36 +135,36 @@ def image_optimize_for_web(base64_source, max_width=0, quality=80):
return image_to_base64(image, **opt)
def image_resize_image_big(base64_source, filetype=None, avoid_if_small=True, preserve_aspect_ratio=False, upper_limit=False):
def image_resize_image_big(base64_source, filetype=None):
""" Wrapper on image_resize_image, to resize images larger than the standard
'big' image size: 1024x1024px.
Refer to image_resize_image for the parameters.
"""
return image_resize_image(base64_source, IMAGE_BIG_SIZE, filetype, avoid_if_small, preserve_aspect_ratio, upper_limit)
return image_resize_image(base64_source, IMAGE_BIG_SIZE, filetype)
def image_resize_image_large(base64_source, filetype=None, avoid_if_small=True, preserve_aspect_ratio=False, upper_limit=False):
def image_resize_image_large(base64_source, filetype=None):
""" Wrapper on image_resize_image, to resize to the standard 'large'
image size: 256x256.
Refer to image_resize_image for the parameters.
"""
return image_resize_image(base64_source, IMAGE_LARGE_SIZE, filetype, avoid_if_small, preserve_aspect_ratio, upper_limit)
return image_resize_image(base64_source, IMAGE_LARGE_SIZE, filetype)
def image_resize_image_medium(base64_source, filetype=None, avoid_if_small=False, preserve_aspect_ratio=False, upper_limit=False):
def image_resize_image_medium(base64_source, filetype=None):
""" Wrapper on image_resize_image, to resize to the standard 'medium'
image size: 128x128.
Refer to image_resize_image for the parameters.
"""
return image_resize_image(base64_source, IMAGE_MEDIUM_SIZE, filetype, avoid_if_small, preserve_aspect_ratio, upper_limit)
return image_resize_image(base64_source, IMAGE_MEDIUM_SIZE, filetype)
def image_resize_image_small(base64_source, filetype=None, avoid_if_small=False, preserve_aspect_ratio=False, upper_limit=False):
def image_resize_image_small(base64_source, filetype=None):
""" Wrapper on image_resize_image, to resize to the standard 'small' image
size: 64x64.
Refer to image_resize_image for the parameters.
"""
return image_resize_image(base64_source, IMAGE_SMALL_SIZE, filetype, avoid_if_small, preserve_aspect_ratio, upper_limit)
return image_resize_image(base64_source, IMAGE_SMALL_SIZE, filetype)
# ----------------------------------------
@@ -351,9 +289,7 @@ def is_image_size_above(base64_source, size=IMAGE_BIG_SIZE):
def image_get_resized_images(base64_source,
big_name='image', large_name='image_large', medium_name='image_medium', small_name='image_small',
avoid_resize_big=True, avoid_resize_large=True, avoid_resize_medium=True, avoid_resize_small=True,
preserve_aspect_ratio=False, upper_limit=False):
big_name='image', large_name='image_large', medium_name='image_medium', small_name='image_small'):
""" Standard tool function that returns a dictionary containing the
big, medium, large and small versions of the source image.
@@ -368,20 +304,19 @@ def image_get_resized_images(base64_source,
"""
return_dict = dict()
if big_name:
return_dict[big_name] = image_resize_image_big(base64_source, avoid_if_small=avoid_resize_big, preserve_aspect_ratio=preserve_aspect_ratio, upper_limit=upper_limit)
return_dict[big_name] = image_resize_image_big(base64_source)
if large_name:
return_dict[large_name] = image_resize_image_large(base64_source, avoid_if_small=avoid_resize_large, preserve_aspect_ratio=preserve_aspect_ratio, upper_limit=upper_limit)
return_dict[large_name] = image_resize_image_large(base64_source)
if medium_name:
return_dict[medium_name] = image_resize_image_medium(base64_source, avoid_if_small=avoid_resize_medium, preserve_aspect_ratio=preserve_aspect_ratio, upper_limit=upper_limit)
return_dict[medium_name] = image_resize_image_medium(base64_source)
if small_name:
return_dict[small_name] = image_resize_image_small(base64_source, avoid_if_small=avoid_resize_small, preserve_aspect_ratio=preserve_aspect_ratio, upper_limit=upper_limit)
return_dict[small_name] = image_resize_image_small(base64_source)
return return_dict
def image_resize_images(vals,
return_big=True, return_large=False, return_medium=True, return_small=True,
big_name='image', large_name='image_large', medium_name='image_medium', small_name='image_small',
preserve_aspect_ratio=False, upper_limit=False):
big_name='image', large_name='image_large', medium_name='image_medium', small_name='image_small'):
""" Update ``vals`` with image fields resized as expected. """
big_image = vals.get(big_name)
large_image = vals.get(large_name)
@@ -392,11 +327,7 @@ def image_resize_images(vals,
if biggest_image:
vals.update(image_get_resized_images(biggest_image,
big_name=return_big and big_name, large_name=return_large and large_name, medium_name=return_medium and medium_name, small_name=return_small and small_name,
avoid_resize_big=True, avoid_resize_large=True,
avoid_resize_medium=(not big_image and not large_image),
avoid_resize_small=(not big_image and not large_image and not medium_image),
preserve_aspect_ratio=preserve_aspect_ratio, upper_limit=upper_limit))
big_name=return_big and big_name, large_name=return_large and large_name, medium_name=return_medium and medium_name, small_name=return_small and small_name))
elif any(f in vals for f in [big_name, large_name, medium_name, small_name]):
if return_big:
vals[big_name] = False
@@ -408,7 +339,7 @@ def image_resize_images(vals,
vals[small_name] = False
def limited_image_resize(base64_source, width=None, height=None, crop=False, upper_limit=False, avoid_if_small=False):
def limited_image_resize(base64_source, width=None, height=None, crop=False):
"""Return the given `base64_source` image resized to the given `width` and
`height`. Return the original image if both `width` and `height` are fasly.
@@ -422,32 +353,17 @@ def limited_image_resize(base64_source, width=None, height=None, crop=False, upp
:type height: int
:param crop: True if the result should be cropped to a square.
False to resize without cropping, then the result will be controlled
by `upper_limit` and `avoid_if_small`
False to resize without cropping.
:type crop: bool
:param upper_limit: value sent to `image_resize_image` if `crop` is False
:type upper_limit: bool
:param avoid_if_small: value sent to `image_resize_image` if `crop` is False
:type avoid_if_small: bool
:return: resulting image base64 encoded
:rtype: string or bytes
"""
if base64_source and (width or height):
height = int(height or 0)
width = int(width or 0)
if crop:
return crop_image(base64_source, type='center', size=(width or None, height or None), ratio=(1, 1))
return crop_image(base64_source, type='center', size=(width, height), ratio=(1, 1))
else:
if not upper_limit:
# resize maximum 500*500
width = min(width, 500)
height = min(height, 500)
return image_resize_image(
base64_source=base64_source, size=(width or None, height or None), upper_limit=upper_limit,
avoid_if_small=avoid_if_small)
return image_resize_image(base64_source=base64_source, size=(width, height))
return base64_source