diff --git a/addons/web/models/ir_qweb_fields.py b/addons/web/models/ir_qweb_fields.py index 2bf7f7164b3..e4cc0f94132 100644 --- a/addons/web/models/ir_qweb_fields.py +++ b/addons/web/models/ir_qweb_fields.py @@ -64,15 +64,19 @@ class Image(models.AbstractModel): "That is because the image goes into the tag, or it gets the " \ "hose again." + src = src_zoom = None if options.get('qweb_img_raw_data', False): - return super(Image, self).record_to_html(record, field_name, options) + value = record[field_name] + if value is False: + return False + src = self._get_src_data_b64(value, options) + else: + src, src_zoom = self._get_src_urls(record, field_name, options) aclasses = ['img', 'img-fluid'] if options.get('qweb_img_responsive', True) else ['img'] aclasses += options.get('class', '').split() classes = ' '.join(map(escape, aclasses)) - src, src_zoom = self._get_src_urls(record, field_name, options) - if options.get('alt-field') and options['alt-field'] in record and record[options['alt-field']]: alt = escape(record[options['alt-field']]) elif options.get('alt'): diff --git a/addons/web/tests/__init__.py b/addons/web/tests/__init__.py index a4a3dac207f..00232ed8159 100644 --- a/addons/web/tests/__init__.py +++ b/addons/web/tests/__init__.py @@ -22,3 +22,4 @@ from . import test_translate from . import test_web_redirect from . import test_res_users from . import test_webmanifest +from . import test_ir_qweb diff --git a/addons/web/tests/test_ir_qweb.py b/addons/web/tests/test_ir_qweb.py new file mode 100644 index 00000000000..06d3bd3e724 --- /dev/null +++ b/addons/web/tests/test_ir_qweb.py @@ -0,0 +1,30 @@ +from lxml import etree +from odoo.tests.common import TransactionCase + +class TestIrQweb(TransactionCase): + def test_image_field(self): + view = self.env["ir.ui.view"].create({ + "key": "web.test_qweb", + "type": "qweb", + "arch": """ + + """ + }) + partner = self.env["res.partner"].create({ + "name": "test image partner", + "image_128": "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAF0lEQVR4nGJxKFrEwMDAxAAGgAAAAP//D+IBWx9K7TUAAAAASUVORK5CYII=", + }) + + html = view._render_template(view.id, {"is_raw_image": True, "record": partner}) + tree = etree.fromstring(html) + img = tree.find("img") + self.assertTrue(img.get("src").startswith("data:image/png;base64")) + self.assertEqual(img.get("class"), "img img-fluid") + self.assertEqual(img.get("alt"), "test image partner") + + html = view._render_template(view.id, {"is_raw_image": False, "record": partner}) + tree = etree.fromstring(html) + img = tree.find("img") + self.assertTrue(img.get("src").startswith("/web/image")) + self.assertEqual(img.get("class"), "img img-fluid") + self.assertEqual(img.get("alt"), "test image partner") diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py index f3844173ab2..431a95d607a 100644 --- a/odoo/addons/base/models/ir_qweb_fields.py +++ b/odoo/addons/base/models/ir_qweb_fields.py @@ -389,7 +389,7 @@ class ImageConverter(models.AbstractModel): _inherit = 'ir.qweb.field' @api.model - def value_to_html(self, value, options): + def _get_src_data_b64(self, value, options): try: # FIXME: maaaaaybe it could also take raw bytes? image = Image.open(BytesIO(base64.b64decode(value))) image.verify() @@ -398,7 +398,11 @@ class ImageConverter(models.AbstractModel): except: # image.verify() throws "suitable exceptions", I have no idea what they are raise ValueError("Invalid image content") - return Markup('' % (Image.MIME[image.format], value.decode('ascii'))) + return "data:%s;base64,%s" % (Image.MIME[image.format], value.decode('ascii')) + + @api.model + def value_to_html(self, value, options): + return Markup('') % self._get_src_data_b64(value, options) class ImageUrlConverter(models.AbstractModel): """ ``image_url`` widget rendering, inserts an image tag in the