From c035d0003d09289fde0aabcb21849c2914524c01 Mon Sep 17 00:00:00 2001 From: Benoit Socias Date: Wed, 26 Oct 2022 09:06:37 +0000 Subject: [PATCH] [IMP] web_editor: upload a JPEG too when uploading a WEBP The library used to generate PDFs does not support the WEBP image format. For those images to be included in reports, they need to be converted. For security reasons, this conversion cannot be done on the server, therefore it was decided to keep an already converted copy of such images. This commit converts uploaded WEBP images to JPEG and uploads them both so that the report generation can use the JPEG instead. task-2774352 Part-of: odoo/odoo#85494 --- addons/web_editor/controllers/main.py | 10 +++++++- .../upload_progress_toast/upload_service.js | 23 +++++++++++++++++++ .../static/src/js/wysiwyg/wysiwyg.js | 14 +++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/addons/web_editor/controllers/main.py b/addons/web_editor/controllers/main.py index 47ece23cec1..f84b02565ce 100644 --- a/addons/web_editor/controllers/main.py +++ b/addons/web_editor/controllers/main.py @@ -542,7 +542,7 @@ class Web_Editor(http.Controller): return files_data_by_bundle @http.route('/web_editor/modify_image/', type="json", auth="user", website=True) - def modify_image(self, attachment, res_model=None, res_id=None, name=None, data=None, original_id=None, mimetype=None): + def modify_image(self, attachment, res_model=None, res_id=None, name=None, data=None, original_id=None, mimetype=None, alt_data=None): """ Creates a modified copy of an attachment and returns its image_src to be inserted into the DOM. @@ -561,6 +561,14 @@ class Web_Editor(http.Controller): if name: fields['name'] = name attachment = attachment.copy(fields) + if alt_data: + attachment.create({ + 'name': attachment.name + '.jpg', + 'datas': alt_data, + 'res_id': attachment.id, + 'res_model': 'ir_attachment', + 'mimetype': 'image/jpeg', + }) if attachment.url: # Don't keep url if modifying static attachment because static images # are only served from disk and don't fallback to attachments. diff --git a/addons/web_editor/static/src/components/upload_progress_toast/upload_service.js b/addons/web_editor/static/src/components/upload_progress_toast/upload_service.js index de4a42b2e84..6ccddf26105 100644 --- a/addons/web_editor/static/src/components/upload_progress_toast/upload_service.js +++ b/addons/web_editor/static/src/components/upload_progress_toast/upload_service.js @@ -122,6 +122,29 @@ export const uploadService = { file.hasError = true; file.errorMessage = attachment.error; } else { + if (attachment.mimetype === 'image/webp') { + // Generate alternate format for reports. + const image = document.createElement('img'); + image.src = `data:image/webp;base64,${dataURL.split(',')[1]}`; + await new Promise(resolve => image.addEventListener('load', resolve)); + const canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + const ctx = canvas.getContext('2d'); + ctx.fillStyle = 'rgb(255, 255, 255)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(image, 0, 0); + const altDataURL = canvas.toDataURL('image/jpeg', 0.75); + await rpc('/web_editor/attachment/add_data', { + 'name': file.name.replace(/\.webp$/, '.jpg'), + 'data': altDataURL.split(',')[1], + 'res_id': attachment.id, + 'res_model': 'ir.attachment', + 'is_image': true, + 'width': 0, + 'quality': 0, + }, {xhr}); + } file.uploaded = true; await onUploaded(attachment); } diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js index c5f0c8861db..d7001d8d19a 100644 --- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js +++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js @@ -975,12 +975,26 @@ const Wysiwyg = Widget.extend({ // Modifying an image always creates a copy of the original, even if // it was modified previously, as the other modified image may be used // elsewhere if the snippet was duplicated or was saved as a custom one. + let altData = undefined; + if (el.dataset.mimetype === 'image/webp') { + // Generate alternate format for reports. + const image = document.createElement('img'); + image.src = isBackground ? el.dataset.bgSrc : el.getAttribute('src'); + await new Promise(resolve => image.addEventListener('load', resolve)); + const canvas = document.createElement('canvas'); + canvas.width = image.width; + canvas.height = image.height; + const ctx = canvas.getContext('2d'); + ctx.drawImage(image, 0, 0); + altData = canvas.toDataURL('image/jpeg', 0.75).split(',')[1]; + } const newAttachmentSrc = await this._rpc({ route: `/web_editor/modify_image/${encodeURIComponent(el.dataset.originalId)}`, params: { res_model: resModel, res_id: parseInt(resId), data: (isBackground ? el.dataset.bgSrc : el.getAttribute('src')).split(',')[1], + alt_data: altData, mimetype: el.dataset.mimetype, name: (el.dataset.fileName ? el.dataset.fileName : null), },