diff options
| -rw-r--r-- | addons/im_livechat/controllers/main.py | 3 | ||||
| -rw-r--r-- | addons/mail/controllers/main.py | 4 | ||||
| -rw-r--r-- | addons/web/controllers/main.py | 71 | ||||
| -rw-r--r-- | addons/website/models/ir_http.py | 21 | ||||
| -rw-r--r-- | addons/website_forum/controllers/main.py | 4 | ||||
| -rw-r--r-- | odoo/addons/base/models/ir_http.py | 251 | ||||
| -rw-r--r-- | odoo/addons/base/tests/test_ir_http.py | 7 | ||||
| -rw-r--r-- | odoo/tools/image.py | 31 |
8 files changed, 182 insertions, 210 deletions
diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py index abe0e17bb0c..86553625f4d 100644 --- a/addons/im_livechat/controllers/main.py +++ b/addons/im_livechat/controllers/main.py @@ -6,7 +6,6 @@ import base64 from odoo import http, _ from odoo.http import request from odoo.addons.base.models.assetsbundle import AssetsBundle -from odoo.addons.web.controllers.main import binary_content class LivechatController(http.Controller): @@ -22,7 +21,7 @@ class LivechatController(http.Controller): if isinstance(mock_attachment, list): # suppose that CSS asset will not required to be split in pages mock_attachment = mock_attachment[0] # can't use /web/content directly because we don't have attachment ids (attachments must be created) - status, headers, content = binary_content(id=mock_attachment.id, unique=asset.checksum) + status, headers, content = request.env['ir.http'].binary_content(id=mock_attachment.id, unique=asset.checksum) content_base64 = base64.b64decode(content) if content else '' headers.append(('Content-Length', len(content_base64))) return request.make_response(content_base64, headers) diff --git a/addons/mail/controllers/main.py b/addons/mail/controllers/main.py index 6694fbf72b1..38965dcf79b 100644 --- a/addons/mail/controllers/main.py +++ b/addons/mail/controllers/main.py @@ -9,7 +9,6 @@ import werkzeug from werkzeug import url_encode from odoo import api, http, registry, SUPERUSER_ID, _ -from odoo.addons.web.controllers.main import binary_content from odoo.exceptions import AccessError from odoo.http import request from odoo.tools import consteq @@ -216,7 +215,8 @@ class MailController(http.Controller): # if the current user has access to the document, get the partner avatar as sudo() request.env[res_model].browse(res_id).check_access_rule('read') if partner_id in request.env[res_model].browse(res_id).sudo().exists().message_ids.mapped('author_id').ids: - status, headers, _content = binary_content(model='res.partner', id=partner_id, field='image_medium', default_mimetype='image/png', env=request.env(user=SUPERUSER_ID)) + status, headers, _content = request.env['ir.http'].sudo().binary_content( + model='res.partner', id=partner_id, field='image_medium', default_mimetype='image/png') # binary content return an empty string and not a placeholder if obj[field] is False if _content != '': content = _content diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 64cf2ca9ac5..57c86a2c6d6 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -36,7 +36,7 @@ import odoo import odoo.modules.registry from odoo.api import call_kw, Environment from odoo.modules import get_resource_path -from odoo.tools import crop_image, topological_sort, html_escape, pycompat +from odoo.tools import limited_image_resize, topological_sort, html_escape, pycompat from odoo.tools.mimetypes import guess_mimetype from odoo.tools.translate import _ from odoo.tools.misc import str2bool, xlwt, file_open @@ -424,16 +424,6 @@ def xml2json_from_elementtree(el, preserve_whitespaces=False): res["children"] = kids return res -def binary_content(xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, - filename=None, filename_field='datas_fname', download=False, mimetype=None, - default_mimetype='application/octet-stream', related_id=None, access_mode=None, access_token=None, - env=None): - return request.registry['ir.http'].binary_content( - xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, - filename_field=filename_field, download=download, mimetype=mimetype, - default_mimetype=default_mimetype, related_id=related_id, access_mode=access_mode, access_token=access_token, - env=env) - #---------------------------------------------------------- # Odoo Web web Controllers #---------------------------------------------------------- @@ -1029,18 +1019,14 @@ class Binary(http.Controller): '/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public") def content_common(self, xmlid=None, model='ir.attachment', id=None, field='datas', filename=None, filename_field='datas_fname', unique=None, mimetype=None, - download=None, data=None, token=None, access_token=None, related_id=None, access_mode=None, - **kw): - status, headers, content = binary_content( + download=None, data=None, token=None, access_token=None, **kw): + + status, headers, content = 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, - access_token=access_token, related_id=related_id, access_mode=access_mode) - if status == 304: - response = werkzeug.wrappers.Response(status=status, headers=headers) - elif status == 301: - return werkzeug.utils.redirect(content, code=301) - elif status != 200: - response = request.not_found() + filename_field=filename_field, download=download, mimetype=mimetype, access_token=access_token) + + if status != 200: + return request.env['ir.http']._response_by_status(status, headers, content) else: content_base64 = base64.b64decode(content) headers.append(('Content-Length', len(content_base64))) @@ -1068,39 +1054,18 @@ 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, related_id=None, access_mode=None, - access_token=None, avoid_if_small=False, upper_limit=False, signature=False): - status, headers, content = binary_content( + download=None, width=0, height=0, crop=False, access_token=None, avoid_if_small=False, + upper_limit=False, **kw): + status, headers, content = 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, - default_mimetype='image/png', related_id=related_id, access_mode=access_mode, access_token=access_token) - if status == 304: - return werkzeug.wrappers.Response(status=304, headers=headers) - elif status == 301: - return werkzeug.utils.redirect(content, code=301) - elif status != 200 and download: - return request.not_found() - - if headers and dict(headers).get('Content-Type', '') == 'image/svg+xml': # we shan't resize svg images - height = 0 - width = 0 - else: - height = int(height or 0) - width = int(width or 0) - - if crop and (width or height): - content = crop_image(content, type='center', size=(width, height), ratio=(1, 1)) - - elif content and (width or height): - if not upper_limit: - # resize maximum 500*500 - if width > 500: - width = 500 - if height > 500: - height = 500 - content = odoo.tools.image_resize_image(base64_source=content, size=(width or None, height or None), - encoding='base64', upper_limit=upper_limit, - avoid_if_small=avoid_if_small) + default_mimetype='image/png', access_token=access_token) + + if status != 200 and download: + return request.env['ir.http']._response_by_status(status, headers, content) + + content = limited_image_resize( + content, width=width, height=height, crop=crop, upper_limit=upper_limit, avoid_if_small=avoid_if_small) if content: image_base64 = base64.b64decode(content) diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py index 7ca7563159b..25becf9749c 100644 --- a/addons/website/models/ir_http.py +++ b/addons/website/models/ir_http.py @@ -237,25 +237,22 @@ class Http(models.AbstractModel): html = request.env['ir.ui.view'].render_template('website.http_error', values) return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8') - @classmethod - def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas', + def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', unique=False, filename=None, filename_field='datas_fname', download=False, mimetype=None, default_mimetype='application/octet-stream', - access_token=None, related_id=None, access_mode=None, env=None): - env = env or request.env + access_token=None): obj = None if xmlid: - obj = cls._xmlid_to_obj(env, xmlid) - elif id and model in env: - obj = env[model].browse(int(id)) + obj = self._xmlid_to_obj(self.env, xmlid) + elif id and model in self.env: + obj = self.env[model].browse(int(id)) if obj and 'website_published' in obj._fields: - if env[obj._name].sudo().search([('id', '=', obj.id), ('website_published', '=', True)]): - env = env(user=SUPERUSER_ID) - return super(Http, cls).binary_content( + if self.env[obj._name].sudo().search([('id', '=', obj.id), ('website_published', '=', True)]): + self.sudo() + return super(Http, self).binary_content( xmlid=xmlid, model=model, id=id, field=field, unique=unique, filename=filename, filename_field=filename_field, download=download, mimetype=mimetype, - default_mimetype=default_mimetype, access_token=access_token, related_id=related_id, - access_mode=access_mode, env=env) + default_mimetype=default_mimetype, access_token=access_token) @classmethod def _xmlid_to_obj(cls, env, xmlid): diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py index 05c00e8df93..42b1e892fcc 100644 --- a/addons/website_forum/controllers/main.py +++ b/addons/website_forum/controllers/main.py @@ -12,7 +12,6 @@ from datetime import datetime from odoo import http, modules, SUPERUSER_ID, tools, _ from odoo.addons.http_routing.models.ir_http import slug -from odoo.addons.web.controllers.main import binary_content from odoo.addons.website.models.ir_http import sitemap_qs2dom from odoo.http import request @@ -591,7 +590,8 @@ class WebsiteForum(http.Controller): @http.route(['/forum/user/<int:user_id>/avatar'], type='http', auth="public", website=True, sitemap=False) def user_avatar(self, user_id=0, **post): - status, headers, content = binary_content(model='res.users', id=user_id, field='image_medium', default_mimetype='image/png', env=request.env(user=SUPERUSER_ID)) + status, headers, content = request.env['ir.http'].sudo().binary_content( + model='res.users', id=user_id, field='image_medium', default_mimetype='image/png') if not content: img_path = modules.get_module_resource('web', 'static/src/img', 'placeholder.png') diff --git a/odoo/addons/base/models/ir_http.py b/odoo/addons/base/models/ir_http.py index 5d6e84a59b3..1cc910b58f9 100644 --- a/odoo/addons/base/models/ir_http.py +++ b/odoo/addons/base/models/ir_http.py @@ -74,6 +74,10 @@ class IrHttp(models.AbstractModel): _name = 'ir.http' _description = "HTTP Routing" + #------------------------------------------------------ + # Routing map + #------------------------------------------------------ + @classmethod def _get_converters(cls): return {'model': ModelConverter, 'models': ModelsConverter, 'int': SignedIntConverter} @@ -236,176 +240,167 @@ class IrHttp(models.AbstractModel): if hasattr(cls, '_routing_map'): del cls._routing_map - @classmethod - def content_disposition(cls, filename): - return content_disposition(filename) + #------------------------------------------------------ + # Binary server + #------------------------------------------------------ @classmethod def _xmlid_to_obj(cls, env, xmlid): return env.ref(xmlid, False) - @classmethod - def _check_access_mode(cls, env, id, access_mode, model, access_token=None, related_id=None): - """ - Implemented by each module to define an additional way to check access. - - :param env: the env of binary_content - :param id: id of the record from which to fetch the binary - :param access_mode: typically a string that describes the behaviour of the custom check - :param model: the model of the object for which binary_content was called - :param related_id: optional id to check security. - :return: True if the test passes, else False. - """ - return False - - @classmethod - def _get_special_models(cls): - """ - :return: the set of models that have to pass through several specific fields checks: - used for the 'url' and the 'access_token' fields. - """ - return {'ir.attachment'} - - @classmethod - def binary_content(cls, xmlid=None, model='ir.attachment', id=None, field='datas', - unique=False, filename=None, filename_field='datas_fname', download=False, - mimetype=None, default_mimetype='application/octet-stream', - access_token=None, related_id=None, access_mode=None, env=None): - """ Get file, attachment or downloadable content - - If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the - binary field (via ``default_get``), otherwise fetches the field for - that precise record. - - :param str xmlid: xmlid of the record - :param str model: name of the model to fetch the binary from - :param int id: id of the record from which to fetch the binary - :param str field: binary field - :param bool unique: add a max-age for the cache control - :param str filename: choose a filename - :param str filename_field: if not create an filename with model-id-field - :param bool download: apply headers to download the file - :param str mimetype: mintype of the field (for headers) - :param related_id: the id of another record used for custom_check - :param access_mode: if truthy, will call custom_check to fetch the object that contains the binary. - :param str default_mimetype: default mintype if no mintype found - :param str access_token: optional token for unauthenticated access - only available for ir.attachment - :param Environment env: by default use request.env - :returns: (status, headers, content) - """ - env = env or request.env - attachment_models = cls._get_special_models() + def _get_record_and_check(self, xmlid=None, model=None, id=None, field='datas', access_token=None): # get object and content - obj = None + record = None if xmlid: - obj = cls._xmlid_to_obj(env, xmlid) - elif id and model in env.registry: - obj = env[model].browse(int(id)) + record = self._xmlid_to_obj(self.env, xmlid) + elif id and model in self.env: + record = self.env[model].browse(int(id)) + # obj exists - if not obj or not obj.exists() or field not in obj: - return (404, [], None) + if not record or not record.exists() or field not in record: + return None, 404 # access token grant access - if model in attachment_models and access_token: - obj = obj.sudo() - if access_mode: - if not cls._check_access_mode(env, id, access_mode, model, access_token=access_token, - related_id=related_id): - return (403, [], None) - elif not consteq(obj.access_token or u'', access_token): - return (403, [], None) + if model == 'ir.attachment' and access_token: + record = record.sudo() + if not consteq(record.access_token or '', access_token): + return None, 403 # check read access try: - last_update = obj['__last_update'] + last_update = record['__last_update'] except AccessError: - return (403, [], None) + return None, 403 - status, headers, content = None, [], None + return record, 200 - # attachment by url check - module_resource_path = None - if model in attachment_models and obj.type == 'url' and obj.url: - url_match = re.match("^/(\w+)/(.+)$", obj.url) + @classmethod + def _binary_ir_attachment_redirect_content(cls, record, default_mimetype='application/octet-stream'): + # mainly used for theme images attachemnts + status = content = filename = mimetype = filehash = None + if record.type == 'url' and record.url: + # if url in in the form /somehint server locally + url_match = re.match("^/(\w+)/(.+)$", record.url) if url_match: module = url_match.group(1) module_path = get_module_path(module) module_resource_path = get_resource_path(module, url_match.group(2)) + if module_path and module_resource_path: module_path = os.path.join(os.path.normpath(module_path), '') # join ensures the path ends with '/' module_resource_path = os.path.normpath(module_resource_path) if module_resource_path.startswith(module_path): with open(module_resource_path, 'rb') as f: content = base64.b64encode(f.read()) - last_update = str(os.path.getmtime(module_resource_path)) + status = 200 + filename = os.path.basename(module_resource_path) + mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) + filehash = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest() + else: + status = 301 + content = record.url - if not module_resource_path: - module_resource_path = obj.url - if not content: - status = 301 - content = module_resource_path - else: - content = obj[field] or '' + + return status, content, filename, mimetype, filehash + + def _binary_record_content( + self, record, field='datas', filename=None, + filename_field='datas_fname', default_mimetype='application/octet-stream'): + + model = record._name + mimetype = 'mimetype' in record and record.mimetype or False + content = None + filehash = 'checksum' in record and record['checksum'] or False + + field_def = record._fields[field] + if field_def.type == 'binary' and field_def.attachment: + field_attachment = self.env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', record.id), ('res_field', '=', field)], fields=['datas', 'mimetype', 'checksum'], limit=1) + if field_attachment: + mimetype = field_attachment[0]['mimetype'] + content = field_attachment[0]['datas'] + filehash = field_attachment[0]['checksum'] + + if not content: + content = record[field] or '' # filename if not filename: - if filename_field in obj: - filename = obj[filename_field] - elif module_resource_path: - filename = os.path.basename(module_resource_path) + if filename_field in record: + filename = record[filename_field] else: - filename = "%s-%s-%s" % (obj._name, obj.id, field) + filename = "%s-%s-%s" % (record._name, record.id, field) - # mimetype - mimetype = 'mimetype' in obj and obj.mimetype or False if not mimetype: - if filename: - mimetype = mimetypes.guess_type(filename)[0] - if not mimetype and getattr(env[model]._fields[field], 'attachment', False): - # for binary fields, fetch the ir_attachement for mimetype check - attach_mimetype = env['ir.attachment'].search_read(domain=[('res_model', '=', model), ('res_id', '=', id), ('res_field', '=', field)], fields=['mimetype'], limit=1) - mimetype = attach_mimetype and attach_mimetype[0]['mimetype'] - if not mimetype: - mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) + mimetype = guess_mimetype(base64.b64decode(content), default=default_mimetype) - headers += [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] + if not filehash: + filehash = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest() + status = 200 if content else 404 + return status, content, filename, mimetype, filehash + + def _binary_set_headers(self, status, content, filename, mimetype, unique, filehash=None, download=False): + headers = [('Content-Type', mimetype), ('X-Content-Type-Options', 'nosniff')] # cache etag = bool(request) and request.httprequest.headers.get('If-None-Match') - retag = '"%s"' % hashlib.md5(pycompat.to_text(content).encode('utf-8')).hexdigest() - status = status or (304 if etag == retag else 200) - headers.append(('ETag', retag)) + status = status or (304 if filehash and etag == filehash else 200) + if filehash: + headers.append(('ETag', filehash)) headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0))) - # content-disposition default name if download: - headers.append(('Content-Disposition', cls.content_disposition(filename))) + headers.append(('Content-Disposition', content_disposition(filename))) + return (status, headers, content) + def binary_content(self, xmlid=None, model='ir.attachment', id=None, field='datas', + unique=False, filename=None, filename_field='datas_fname', download=False, + mimetype=None, default_mimetype='application/octet-stream', + access_token=None): + """ Get file, attachment or downloadable content -def convert_exception_to(to_type, with_message=False): - """ Should only be called from an exception handler. Fetches the current - exception data from sys.exc_info() and creates a new exception of type - ``to_type`` with the original traceback. - - If ``with_message`` is ``True``, sets the new exception's message to be - the stringification of the original exception. If ``False``, does not - set the new exception's message. Otherwise, uses ``with_message`` as the - new exception's message. - - :type with_message: str|bool - """ - etype, original, tb = sys.exc_info() - try: - if with_message is False: - message = None - elif with_message is True: - message = str(original) - else: - message = str(with_message) + If the ``xmlid`` and ``id`` parameter is omitted, fetches the default value for the + binary field (via ``default_get``), otherwise fetches the field for + that precise record. + + :param str xmlid: xmlid of the record + :param str model: name of the model to fetch the binary from + :param int id: id of the record from which to fetch the binary + :param str field: binary field + :param bool unique: add a max-age for the cache control + :param str filename: choose a filename + :param str filename_field: if not create an filename with model-id-field + :param bool download: apply headers to download the file + :param str mimetype: mintype of the field (for headers) + :param str default_mimetype: default mintype if no mintype found + :param str access_token: optional token for unauthenticated access + only available for ir.attachment + :returns: (status, headers, content) + """ + record, status = self._get_record_and_check(xmlid=xmlid, model=model, id=id, field=field, access_token=access_token) + + if not record: + return (status or 404, [], None) + + content, headers, status = None, [], None + + if record._name == 'ir.attachment': + status, content, filename, mimetype, filehash = self._binary_ir_attachment_redirect_content(record, default_mimetype=default_mimetype) + if not content: + status, content, filename, mimetype, filehash = self._binary_record_content( + record, field=field, filename=None, filename_field=filename_field, + default_mimetype='application/octet-stream') + + status, headers, content = self._binary_set_headers( + status, content, filename, mimetype, unique, filehash=False, download=download) + + return status, headers, content - raise pycompat.reraise(to_type, to_type(message), tb) - except to_type as e: - return e + def _response_by_status(self, status, headers, content): + if status == 304: + return werkzeug.wrappers.Response(status=status, headers=headers) + elif status == 301: + return werkzeug.utils.redirect(content, code=301) + elif status != 200: + return request.not_found() diff --git a/odoo/addons/base/tests/test_ir_http.py b/odoo/addons/base/tests/test_ir_http.py index 4853c808fe4..f369193741f 100644 --- a/odoo/addons/base/tests/test_ir_http.py +++ b/odoo/addons/base/tests/test_ir_http.py @@ -19,7 +19,6 @@ class test_ir_http_mimetype(common.TransactionCase): id=attachment.id, mimetype=None, default_mimetype='application/octet-stream', - env=self.env ) mimetype = dict(headers).get('Content-Type') self.assertEqual(mimetype, 'image/gif') @@ -35,7 +34,6 @@ class test_ir_http_mimetype(common.TransactionCase): id=attachment.id, mimetype=None, default_mimetype='application/octet-stream', - env=self.env ) mimetype = dict(headers).get('Content-Type') # TODO: fix and change it in master, should be image/gif @@ -53,7 +51,6 @@ class test_ir_http_mimetype(common.TransactionCase): id=partner.id, field='image', default_mimetype='application/octet-stream', - env=self.env ) mimetype = dict(headers).get('Content-Type') self.assertEqual(mimetype, 'image/gif') @@ -75,7 +72,6 @@ class test_ir_http_mimetype(common.TransactionCase): id=prop.id, field='value_binary', default_mimetype='application/octet-stream', - env=self.env ) mimetype = dict(headers).get('Content-Type') self.assertEqual(mimetype, 'image/gif') @@ -92,11 +88,10 @@ class test_ir_http_mimetype(common.TransactionCase): defaults = { 'id': attachment.id, 'default_mimetype': 'image/gif', - 'env': public_user.sudo(public_user.id).env, } def test_access(**kwargs): - status, _, _ = self.env['ir.http'].binary_content( + status, _, _ = self.env['ir.http'].sudo(public_user.id).binary_content( **dict(defaults, **kwargs) ) return status diff --git a/odoo/tools/image.py b/odoo/tools/image.py index 0cf79978193..1cec35b8c23 100644 --- a/odoo/tools/image.py +++ b/odoo/tools/image.py @@ -75,11 +75,9 @@ def image_resize_image(base64_source, size=(1024, 1024), encoding='base64', file asked_width, asked_height = size if upper_limit: if asked_width: - if asked_width >= image.size[0]: - asked_width = image.size[0] + asked_width = min(asked_width, image.size[0]) if asked_height: - if asked_height >= image.size[1]: - asked_height = image.size[1] + asked_height = min(asked_height, image.size[1]) if image.size[0] >= image.size[1]: asked_height = None @@ -187,7 +185,7 @@ def image_resize_image_small(base64_source, size=(64, 64), encoding='base64', fi # ---------------------------------------- # Crop Image # ---------------------------------------- -def crop_image(data, type='top', ratio=False, size=None, image_format=None): +def crop_image(data, type='top', ratio=None, size=None, image_format=None): """ Used for cropping image and create thumbnail :param data: base64 data of image. :param type: Used for cropping position possible @@ -319,6 +317,29 @@ def image_resize_images(vals, big_name='image', medium_name='image_medium', smal elif big_name in vals or medium_name in vals or small_name in vals: vals[big_name] = vals[medium_name] = vals[small_name] = False +def limited_image_resize(content, width=None, height=None, crop=False, upper_limit=False, avoid_if_small=False): + """ + :param content: bytes (should be an image) + """ + if content: + signatures = [b'\xFF\xD8\xFF', b'\x89PNG\r\n\x1A\n'] + decoded_content = base64.b64decode(content) + is_image = any(decoded_content.startswith(signature) for signature in signatures) + if (width or height) and is_image: + height = int(height or 0) + width = int(width or 0) + if crop: + return crop_image(content, 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=content, size=(width or None, height or None), encoding='base64', upper_limit=upper_limit, + avoid_if_small=avoid_if_small) + return content + def image_data_uri(base64_source): """This returns data URL scheme according RFC 2397 (https://tools.ietf.org/html/rfc2397) for all kind of supported images |
