summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro M. Baeza <pedro.baeza@gmail.com>2018-09-20 13:08:50 +0200
committerOlivier Dony <odo@odoo.com>2018-10-03 17:48:14 +0200
commit1ad4d42f0b6da1677a5114c0b79a86b7be35577a (patch)
tree92f266fc1f196de1c2aa97666ca3dec97954146e
parent1be50fdeafcd2b94f7b2f47d6e5bc4b6ebaceadd (diff)
[ADD] *: replace hardcoded data URIs with helper
- Add a method for generating an image data URI, and expose it in QWeb context - Fix reports, website templates or mail templates with data hardcoded data URIs, to use the helper (Python cases), or the existing kanban_image helper (for JS cases) This will gracefully handle SVG support in addition to classical image formats. Closes #26635
-rw-r--r--addons/account/views/account_portal_templates.xml2
-rw-r--r--addons/event/report/event_event_templates.xml4
-rw-r--r--addons/gamification/data/goal_base.xml5
-rw-r--r--addons/hr_attendance/report/hr_employee_badge.xml4
-rw-r--r--addons/l10n_de/report/din5008_report.xml2
-rw-r--r--addons/project/views/project_portal_templates.xml8
-rw-r--r--addons/project/views/project_rating_templates.xml4
-rw-r--r--addons/sale/report/sale_report_templates.xml2
-rw-r--r--addons/sale/views/sale_portal_templates.xml4
-rw-r--r--addons/web/views/report_templates.xml8
-rw-r--r--addons/website_livechat/views/website_livechat.xml4
-rw-r--r--addons/website_sale/views/product_views.xml3
-rw-r--r--odoo/addons/base/models/ir_ui_view.py2
-rw-r--r--odoo/addons/base/views/res_partner_views.xml3
-rw-r--r--odoo/tools/image.py18
15 files changed, 47 insertions, 26 deletions
diff --git a/addons/account/views/account_portal_templates.xml b/addons/account/views/account_portal_templates.xml
index 07654ee275a..858a7cf58df 100644
--- a/addons/account/views/account_portal_templates.xml
+++ b/addons/account/views/account_portal_templates.xml
@@ -108,7 +108,7 @@
<div class="small mb-1"><strong class="text-muted">Your Contact</strong></div>
<div class="row">
<div class="col flex-grow-0 pr-2">
- <img t-if="invoice.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{invoice.user_id.image}" alt="Contact"/>
+ <img t-if="invoice.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(invoice.user_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-0">
diff --git a/addons/event/report/event_event_templates.xml b/addons/event/report/event_event_templates.xml
index 23664ec8d94..67ac8267bc7 100644
--- a/addons/event/report/event_event_templates.xml
+++ b/addons/event/report/event_event_templates.xml
@@ -15,7 +15,7 @@
<div t-field="o.event_id.event_logo"/>
</t>
<span t-if="not o.event_id.event_logo and o.event_id.organizer_id.company_id.logo_web and o.event_id.organizer_id.is_company">
- <img t-att-src="'data:image/png;base64,%s' % to_text(o.event_id.organizer_id.company_id.logo_web)" style="max-height:1cm; max-width:4cm;" alt="Logo"/>
+ <img t-att-src="image_data_uri(o.event_id.organizer_id.company_id.logo_web)" style="max-height:1cm; max-width:4cm;" alt="Logo"/>
</span>
<h5 t-field="o.event_id.name"/>
<h5>( <i class="fa fa-clock-o" aria-label="Period" role="img" title="Period"></i> <span itemprop="startDate" t-field="o.event_id.with_context(tz=o.event_id.date_tz).date_begin" t-options='{"hide_seconds": True}'> </span> <i>to</i> <span itemprop="endDate" t-field="o.event_id.with_context(tz=o.event_id.date_tz).date_end" t-options='{"hide_seconds": True}'> </span> )</h5>
@@ -65,7 +65,7 @@
<div class="col-12">
<span t-if="event.organizer_id.is_company and event.organizer_id.company_id.logo_web">
<div t-field="event.event_logo">
- <img t-att-src="'data:image/png;base64,%s' % to_text(event.organizer_id.company_id.logo_web)" style="max-height:1cm; max-width:4cm;" alt="Logo"/>
+ <img t-att-src="image_data_uri(event.organizer_id.company_id.logo_web)" style="max-height:1cm; max-width:4cm;" alt="Logo"/>
</div>
</span>
<h4 t-field="event.name"/>
diff --git a/addons/gamification/data/goal_base.xml b/addons/gamification/data/goal_base.xml
index 3552be22061..80018820414 100644
--- a/addons/gamification/data/goal_base.xml
+++ b/addons/gamification/data/goal_base.xml
@@ -142,9 +142,8 @@ Thank you,
<div style="height:${heightA}px;">
${extra_div | safe}
<div style="height:55px;">
- % set path = object.env['res.users'].browse(goal['user_id']).partner_id.image_small
- <img style="margin-bottom:5px;width:50px;height:50px;border-radius:50%;" src="data:image/jpeg;base64,${path}" alt="${goal['name']}"/>
- </div>
+ <img style="margin-bottom:5px;width:50px;height:50px;border-radius:50%;" t-att-src="image_data_uri(object.env['res.users'].browse(goal['user_id']).partner_id.image_small)" alt="${goal['name']}"/>
+ </div>
<div align="center" style ="color:${bgColor};height:20px">
${goal['name']}
</div>
diff --git a/addons/hr_attendance/report/hr_employee_badge.xml b/addons/hr_attendance/report/hr_employee_badge.xml
index b121b9c34f3..708a4932cbc 100644
--- a/addons/hr_attendance/report/hr_employee_badge.xml
+++ b/addons/hr_attendance/report/hr_employee_badge.xml
@@ -20,12 +20,12 @@
<table style="width:77pt; height:150pt">
<tr style="height:30%">
<td align="center" valign="center">
- <img t-if="employee.company_id and employee.company_id.logo" t-att-src="'data:image/png;base64,%s' % to_text(employee.company_id.logo)" style="max-height:45pt;max-width:90%" alt="Company Logo"/>
+ <img t-if="employee.company_id.logo" t-att-src="image_data_uri(employee.company_id.logo)" style="max-height:45pt;max-width:90%" alt="Company Logo"/>
</td>
</tr>
<tr style="height:70%;">
<td align="center" valign="center">
- <img t-if="employee.image" t-att-src="'data:image/png;base64,%s' % to_text(employee.image)" style="max-height:85pt;max-width:90%" alt="Employee Image"/>
+ <img t-if="employee.image" t-att-src="image_data_uri(employee.image)" style="max-height:85pt;max-width:90%" alt="Employee Image"/>
</td>
</tr>
</table>
diff --git a/addons/l10n_de/report/din5008_report.xml b/addons/l10n_de/report/din5008_report.xml
index ffd7ea97f83..84c03e9ccd8 100644
--- a/addons/l10n_de/report/din5008_report.xml
+++ b/addons/l10n_de/report/din5008_report.xml
@@ -39,7 +39,7 @@
<div class="float-right">
<h3 class="mt0 text-right" t-field="company.report_header"/>
</div>
- <img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % to_text(company.logo)" class="float-left"/>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" class="float-left"/>
</div>
<div class="article din" t-att-data-oe-model="o and o._name" t-att-data-oe-id="o and o.id">
diff --git a/addons/project/views/project_portal_templates.xml b/addons/project/views/project_portal_templates.xml
index a093a741378..db82de63fe8 100644
--- a/addons/project/views/project_portal_templates.xml
+++ b/addons/project/views/project_portal_templates.xml
@@ -91,7 +91,7 @@
<h6>Customer</h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
- <img t-if="project.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{project.partner_id.image}" alt="Contact"/>
+ <img t-if="project.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(project.partner_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-sm-0">
@@ -103,7 +103,7 @@
<h6>Project Manager</h6>
<div class="row">
<div class="col flex-grow-0 pr-3">
- <img t-if="project.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{project.user_id.image}" alt="Contact"/>
+ <img t-if="project.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(project.user_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-sm-0">
@@ -205,7 +205,7 @@
<strong>Assigned to</strong>
<div class="row">
<div class="col flex-grow-0 pr-3">
- <img t-if="task.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{task.user_id.image}" alt="Contact"/>
+ <img t-if="task.user_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(task.user_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-md-0">
@@ -217,7 +217,7 @@
<strong>Reported by</strong>
<div class="row">
<div class="col flex-grow-0 pr-3">
- <img t-if="task.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-attf-src="data:image/png;base64,#{task.partner_id.image}" alt="Contact"/>
+ <img t-if="task.partner_id.image" class="rounded-circle mt-1 o_portal_contact_img" t-att-src="image_data_uri(task.partner_id.image)" alt="Contact"/>
<img t-else="" class="rounded-circle mt-1 o_portal_contact_img" src="/web/static/src/img/user_menu_avatar.png" alt="Contact"/>
</div>
<div class="col pl-md-0">
diff --git a/addons/project/views/project_rating_templates.xml b/addons/project/views/project_rating_templates.xml
index acc17cef767..0bed3db0219 100644
--- a/addons/project/views/project_rating_templates.xml
+++ b/addons/project/views/project_rating_templates.xml
@@ -77,7 +77,7 @@
<t t-foreach="partner_stats.values()" t-as="partner_stat">
<div class="row mt8" t-if="partner_stat['total']" title="Top 5 partner ratings of last 15 days.">
<div class="col-md-1">
- <img t-if="partner_stat['rated_partner'].image" class="o_top_partner_image" t-attf-src="data:image/png;base64,#{partner_stat['rated_partner'].image}" alt="Rated partner"/>
+ <img t-if="partner_stat['rated_partner'].image" class="o_top_partner_image" t-att-src="image_data_uri(partner_stat['rated_partner'].image)" alt="Rated partner"/>
<img t-if="not partner_stat['rated_partner'].image" class="o_top_partner_image" src='/web/static/src/img/placeholder.png' alt="Placeholder"/>
</div>
<div class="col-md-4 o_smiley_no_padding_right">
@@ -126,7 +126,7 @@
<div t-attf-id="rating_#{rating.id}" class="container d-none">
<div class="row">
<div class="col-lg-2">
- <img t-if="rating.partner_id.image" class="o_top_partner_image" t-attf-src="data:image/png;base64,#{rating.partner_id.image}" alt="Rated partner"/>
+ <img t-if="rating.partner_id.image" class="o_top_partner_image" t-att-src="image_data_uri(rating.partner_id.image)" alt="Rated partner"/>
<img t-if="not rating.partner_id.image" class="o_top_partner_image" src='/web/static/src/img/placeholder.png' alt="Placeholder"/>
</div>
<div class="col-lg-10">
diff --git a/addons/sale/report/sale_report_templates.xml b/addons/sale/report/sale_report_templates.xml
index 9a7647180d3..cf9019d7e3b 100644
--- a/addons/sale/report/sale_report_templates.xml
+++ b/addons/sale/report/sale_report_templates.xml
@@ -202,7 +202,7 @@
<strong>Signature</strong>
</div>
<div class="offset-8 col-4">
- <img t-att-src="'data:image/png;base64,%s' % to_text(doc.signature)" style="max-height: 4cm; max-width: 8cm;"/>
+ <img t-att-src="image_data_uri(doc.signature)" style="max-height: 4cm; max-width: 8cm;"/>
</div>
<div class="offset-8 col-4 text-center">
<p t-field="doc.signed_by"/>
diff --git a/addons/sale/views/sale_portal_templates.xml b/addons/sale/views/sale_portal_templates.xml
index ca1fde9bc49..1466714587b 100644
--- a/addons/sale/views/sale_portal_templates.xml
+++ b/addons/sale/views/sale_portal_templates.xml
@@ -183,7 +183,7 @@
<div class="small mb-1"><strong class="text-muted">Your Contact</strong></div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pr-2">
- <img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="sale_order.user_id.image" t-attf-src="data:image/png;base64,#{sale_order.user_id.image}" alt="Contact"/>
+ <img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="sale_order.user_id.image" t-att-src="image_data_uri(sale_order.user_id.image)" alt="Contact"/>
<img class="rounded-circle mr4 float-left o_portal_contact_img" t-if="not sale_order.user_id.image" src="/web/static/src/img/placeholder.png" alt="Contact"/>
</div>
<div class="col pl-0" style="min-width: 150px">
@@ -579,7 +579,7 @@
<div class="row mt-4" name="signature">
<div t-attf-class="#{'col-3' if report_type != 'html' else 'col-sm-7 col-md-4'} ml-auto text-center">
<h5>Signature</h5>
- <img t-att-src="'data:image/png;base64,%s' % to_text(sale_order.signature)" style="max-height: 6rem; max-width: 100%;"/>
+ <img t-att-src="image_data_uri(sale_order.signature)" style="max-height: 6rem; max-width: 100%;"/>
<p t-field="sale_order.signed_by"/>
</div>
</div>
diff --git a/addons/web/views/report_templates.xml b/addons/web/views/report_templates.xml
index a410aad17a0..3250167b54b 100644
--- a/addons/web/views/report_templates.xml
+++ b/addons/web/views/report_templates.xml
@@ -168,7 +168,7 @@
<div class="float-right">
<h3 class="mt0 text-right" t-field="company.report_header"/>
</div>
- <img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % to_text(company.logo)" class="float-left" alt="Logo"/>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" class="float-left" alt="Logo"/>
<div class="float-left company_address">
<div>
<strong t-field="company.partner_id.name"/>
@@ -209,7 +209,7 @@
<div class="o_boxed_header">
<div class="row mb8">
<div class="col-6">
- <img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % to_text(company.logo)" alt="Logo"/>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/>
</div>
<div class="col-6 text-right mb4">
<h4 class="mt0" t-field="company.report_header"/>
@@ -248,7 +248,7 @@
<div class="o_clean_header">
<div class="row">
<div class="col-6">
- <img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % to_text(company.logo)" alt="Logo"/>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" alt="Logo"/>
</div>
<div class="col-5 offset-1" name="company_address">
<ul class="list-unstyled">
@@ -293,7 +293,7 @@
<div class="header">
<div class="row">
<div class="col-3 mb4">
- <img t-if="company.logo" t-att-src="'data:image/png;base64,%s' % to_text(company.logo)" style="max-height: 45px;" alt="Logo"/>
+ <img t-if="company.logo" t-att-src="image_data_uri(company.logo)" style="max-height: 45px;" alt="Logo"/>
</div>
<div class="col-9 text-right" style="margin-top:22px;" t-field="company.report_header" name="moto"/>
</div>
diff --git a/addons/website_livechat/views/website_livechat.xml b/addons/website_livechat/views/website_livechat.xml
index a7673243222..6afcda0cd0e 100644
--- a/addons/website_livechat/views/website_livechat.xml
+++ b/addons/website_livechat/views/website_livechat.xml
@@ -147,7 +147,7 @@
<t t-foreach="team" t-as="user">
<div class="media mt-3">
<t t-if="user.image_small">
- <img t-att-src="user.image_small and ('data:image/png;base64,' + to_text(user.image_small)) or '/web/static/src/img/placeholder.png'"
+ <img t-att-src="user.image_small and image_data_uri(user.image_small) or '/web/static/src/img/placeholder.png'"
class="rounded" style="padding-right: 8px;" t-att-alt="user.name"/>
</t>
<div class="media-body">
@@ -180,7 +180,7 @@
<t t-foreach="channels" t-as="channel">
<div t-attf-class="media#{' mt-3' if channel_index else ''}">
<a t-attf-href="/livechat/channel/#{ slug(channel)}">
- <img t-att-src="channel.image_small and ('data:image/png;base64,' + to_text(channel.image_small)) or '/web/static/src/img/placeholder.png'" t-att-alt="channel.name" />
+ <img t-att-src="channel.image_small and image_data_uri(channel.image_small) or '/web/static/src/img/placeholder.png'" t-att-alt="channel.name" />
</a>
<div class="media-body">
<h4><t t-esc="channel.name"/></h4>
diff --git a/addons/website_sale/views/product_views.xml b/addons/website_sale/views/product_views.xml
index 72452ce93b7..3f541d31943 100644
--- a/addons/website_sale/views/product_views.xml
+++ b/addons/website_sale/views/product_views.xml
@@ -88,6 +88,7 @@
<group name="extra_images" string="Extra Images">
<field name="product_image_ids" class="o_website_sale_image_list" context="{'default_name': name, 'default_product_tmpl_id': active_id}" nolabel="1">
<kanban string="Product Images" class="o_attachments_previews">
+ <field name="id"/>
<field name="name"/>
<field name="image"/>
<templates>
@@ -95,7 +96,7 @@
<div class="o_attachment oe_kanban_global_click o_website_sale_image_card">
<div class="o_attachment_wrap">
<div class="o_image_box">
- <div class="o_attachment_image" t-att-style="'background-image:url(data:image/png;base64,'+record.image.raw_value +')'"/>
+ <div class="o_attachment_image" t-attf-style="background-image:url({{kanban_image('product.image', 'image', record.id.raw_value)}});"/>
<div t-attf-class="o_image_overlay" t-att-title="record.name.value"/>
<div class="o_website_sale_image_card_title" t-att-title="record.name.value">
<field name="name"/>
diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py
index 96e0593cbc1..407bec75af1 100644
--- a/odoo/addons/base/models/ir_ui_view.py
+++ b/odoo/addons/base/models/ir_ui_view.py
@@ -33,6 +33,7 @@ from odoo.tools.parse_version import parse_version
from odoo.tools.safe_eval import safe_eval
from odoo.tools.view_validation import valid_view
from odoo.tools.translate import xml_translate, TRANSLATED_ATTRS
+from odoo.tools.image import image_data_uri
_logger = logging.getLogger(__name__)
@@ -1296,6 +1297,7 @@ actual arch.
xmlid=self.key,
viewid=self.id,
to_text=pycompat.to_text,
+ image_data_uri=image_data_uri,
)
return qcontext
diff --git a/odoo/addons/base/views/res_partner_views.xml b/odoo/addons/base/views/res_partner_views.xml
index a6ba287dcff..9a86939782b 100644
--- a/odoo/addons/base/views/res_partner_views.xml
+++ b/odoo/addons/base/views/res_partner_views.xml
@@ -270,6 +270,7 @@
<page string="Contacts &amp; Addresses" autofocus="autofocus">
<field name="child_ids" mode="kanban" context="{'default_parent_id': active_id, 'default_street': street, 'default_street2': street2, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_supplier': supplier, 'default_customer': customer, 'default_lang': lang, 'default_user_id': user_id}">
<kanban>
+ <field name="id"/>
<field name="color"/>
<field name="name"/>
<field name="title"/>
@@ -298,7 +299,7 @@
<t t-set="color" t-value="kanban_color(record.color.raw_value)"/>
<div t-att-class="color + (record.title.raw_value == 1 ? ' oe_kanban_color_alert' : '') + ' oe_kanban_global_click'">
<div class="o_kanban_image">
- <img alt="" t-if="record.image_small.raw_value" t-att-src="'data:image/png;base64,'+record.image_small.raw_value"/>
+ <img alt="" t-if="record.image_small.raw_value" t-att-src="kanban_image('res.partner', 'image_small', record.id.raw_value)"/>
<t t-if="!record.image_small.raw_value">
<img alt="Delivery" t-if="record.type.raw_value === 'delivery'" t-att-src='_s + "/base/static/img/truck.png"'/>
<img alt="Invoice" t-if="record.type.raw_value === 'invoice'" t-att-src='_s + "/base/static/img/money.png"'/>
diff --git a/odoo/tools/image.py b/odoo/tools/image.py
index 24aa56ced17..2814aaaaa3f 100644
--- a/odoo/tools/image.py
+++ b/odoo/tools/image.py
@@ -14,6 +14,15 @@ from odoo.tools import pycompat
Image.preinit()
Image._initialized = 2
+# Maps only the 6 first bits of the base64 data, accurate enough
+# for our purpose and faster than decoding the full blob first
+FILETYPE_BASE64_MAGICWORD = {
+ b'/': 'jpg',
+ b'R': 'gif',
+ b'i': 'png',
+ b'P': 'svg+xml',
+}
+
# ----------------------------------------
# Image resizing
# ----------------------------------------
@@ -312,6 +321,15 @@ 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 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
+ (PNG, GIF, JPG and SVG), defaulting on PNG type if not mimetype detected.
+ """
+ return 'data:image/%s;base64,%s' % (
+ FILETYPE_BASE64_MAGICWORD.get(base64_source[:1], 'png'),
+ base64_source.decode(),
+ )
if __name__=="__main__":
import sys