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