From f12ee7b9211f7bbee3beb4100ae2b6dbf348b222 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Fri, 22 Nov 2024 02:47:39 +0000 Subject: [PATCH 01/10] [IMP] product_carousel_image_attachment --- .../models/ir_attachment.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 85d01d46..604492a1 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import api, models +from odoo.tools import ImageProcess IMAGE_TYPES = ["image/png", "image/jpeg", "image/bmp", "image/gif"] @@ -9,6 +10,22 @@ class IrAttachment(models.Model): _inherit = "ir.attachment" + def _resize_image(self, datas): + ICP = self.env["ir.config_parameter"].sudo().get_param + max_resolution = ( + "1025x1025" # Use 1025 instead of 1024 to enable the zoom feature + ) + quality = int(ICP("base.image_autoresize_quality", 80)) + img = ImageProcess(datas, verify_resolution=False) + w, h = img.image.size + nw, nh = map(int, max_resolution.split("x")) + if w > nw or h > nh: + img = img.resize(nw, nh) # Resize the image + return img.image_base64( + quality=quality + ) # Return the resized image as base64 + return datas + @api.model_create_multi def create(self, vals_list): attachments = super(IrAttachment, self).create(vals_list) @@ -22,20 +39,21 @@ def create(self, vals_list): ] and not attachment.res_field ): + resized_image = self._resize_image(attachment.datas) vals = {} # assignment for pt and p if attachment.res_model == "product.template": pt = self.env["product.template"].browse(attachment.res_id) vals = { "name": attachment.name, - "image_1920": attachment.datas, + "image_1920": resized_image, "product_tmpl_id": pt.id, } if attachment.res_model == "product.product": p = self.env["product.product"].browse(attachment.res_id) vals = { "name": attachment.name, - "image_1920": attachment.datas, + "image_1920": resized_image, "product_variant_id": p.id, } self.env["product.image"].sudo().create(vals) From a87ad027966ccbbde6c33eb47fefe87d395b33cc Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Mon, 25 Nov 2024 06:46:51 +0000 Subject: [PATCH 02/10] adj --- product_carousel_image_attachment/models/ir_attachment.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 604492a1..49313f4b 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -12,10 +12,9 @@ class IrAttachment(models.Model): def _resize_image(self, datas): ICP = self.env["ir.config_parameter"].sudo().get_param - max_resolution = ( - "1025x1025" # Use 1025 instead of 1024 to enable the zoom feature - ) quality = int(ICP("base.image_autoresize_quality", 80)) + # Use 1025 instead of 1024 to enable the zoom feature + max_resolution = (1025, 1025) img = ImageProcess(datas, verify_resolution=False) w, h = img.image.size nw, nh = map(int, max_resolution.split("x")) From 46e40459f7336132dc1cd7c2811a936557a8bd38 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Mon, 25 Nov 2024 08:27:32 +0000 Subject: [PATCH 03/10] adj --- .../__manifest__.py | 1 + .../data/scheduler.xml | 17 +++++++++++++++++ .../models/__init__.py | 1 + .../models/ir_attachment.py | 16 +++++++++------- .../models/product_image.py | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 product_carousel_image_attachment/data/scheduler.xml create mode 100644 product_carousel_image_attachment/models/product_image.py diff --git a/product_carousel_image_attachment/__manifest__.py b/product_carousel_image_attachment/__manifest__.py index 1c3b10a7..e7000589 100644 --- a/product_carousel_image_attachment/__manifest__.py +++ b/product_carousel_image_attachment/__manifest__.py @@ -8,5 +8,6 @@ "category": "Tools", "license": "AGPL-3", "depends": ["website_sale"], + "data": ["data/scheduler.xml"], "installable": True, } diff --git a/product_carousel_image_attachment/data/scheduler.xml b/product_carousel_image_attachment/data/scheduler.xml new file mode 100644 index 00000000..1f3698bd --- /dev/null +++ b/product_carousel_image_attachment/data/scheduler.xml @@ -0,0 +1,17 @@ + + + + + Resize Extra Product Image + + code + model._cron_resize_product_image(1000) + + 1 + days + -1 + + + + diff --git a/product_carousel_image_attachment/models/__init__.py b/product_carousel_image_attachment/models/__init__.py index aaf38a16..3305f2c0 100644 --- a/product_carousel_image_attachment/models/__init__.py +++ b/product_carousel_image_attachment/models/__init__.py @@ -1 +1,2 @@ from . import ir_attachment +from . import product_image diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 49313f4b..1116706f 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -10,19 +10,21 @@ class IrAttachment(models.Model): _inherit = "ir.attachment" + @api.model def _resize_image(self, datas): ICP = self.env["ir.config_parameter"].sudo().get_param + # Use 1025 instead of 1024 to enable the zoom feature. + # Define a static value instead of modifying the system parameter + # 'base.image_autoresize_extensions' to avoid + # affecting other image fields. + nw, nh = (1025, 1025) quality = int(ICP("base.image_autoresize_quality", 80)) - # Use 1025 instead of 1024 to enable the zoom feature - max_resolution = (1025, 1025) img = ImageProcess(datas, verify_resolution=False) w, h = img.image.size - nw, nh = map(int, max_resolution.split("x")) if w > nw or h > nh: - img = img.resize(nw, nh) # Resize the image - return img.image_base64( - quality=quality - ) # Return the resized image as base64 + # Use odoo standard resize + img = img.resize(nw, nh) + return img.image_base64(quality=quality) return datas @api.model_create_multi diff --git a/product_carousel_image_attachment/models/product_image.py b/product_carousel_image_attachment/models/product_image.py new file mode 100644 index 00000000..4f98e67e --- /dev/null +++ b/product_carousel_image_attachment/models/product_image.py @@ -0,0 +1,18 @@ +# Copyright 2024 Quartile +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ProductImage(models.Model): + _inherit = "product.image" + + @api.model + def _cron_resize_product_image(self, limit): + images = self.sudo().search([], limit=limit) + for image in images: + image.image_1920 = self.env["ir.attachment"]._resize_image(image.image_1920) + if len(images) == limit: + self.env.ref( + "product_carousel_image_attachment.resize_product_image" + )._trigger() From 9294c759c63816aeb6de875ad866663f421a74a9 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Mon, 25 Nov 2024 10:59:10 +0000 Subject: [PATCH 04/10] adj --- .../models/product_image.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/product_carousel_image_attachment/models/product_image.py b/product_carousel_image_attachment/models/product_image.py index 4f98e67e..2b0c9f79 100644 --- a/product_carousel_image_attachment/models/product_image.py +++ b/product_carousel_image_attachment/models/product_image.py @@ -1,18 +1,20 @@ # Copyright 2024 Quartile # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import api, models +from odoo import api, fields, models class ProductImage(models.Model): _inherit = "product.image" + resize_done = fields.Boolean() + @api.model def _cron_resize_product_image(self, limit): - images = self.sudo().search([], limit=limit) + images = self.sudo().search( + [("can_image_1024_be_zoomed", "=", True), ("resize_done", "=", False)], + limit=limit, + ) for image in images: image.image_1920 = self.env["ir.attachment"]._resize_image(image.image_1920) - if len(images) == limit: - self.env.ref( - "product_carousel_image_attachment.resize_product_image" - )._trigger() + image.resize_done = True From a47e9d791ca822eda4ae168090e64c4cc36775b3 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Tue, 26 Nov 2024 01:32:28 +0000 Subject: [PATCH 05/10] upd --- product_carousel_image_attachment/data/scheduler.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/product_carousel_image_attachment/data/scheduler.xml b/product_carousel_image_attachment/data/scheduler.xml index 1f3698bd..38ce6b2c 100644 --- a/product_carousel_image_attachment/data/scheduler.xml +++ b/product_carousel_image_attachment/data/scheduler.xml @@ -9,7 +9,7 @@ model._cron_resize_product_image(1000) 1 - days + hours -1 From 025530fb4cdd769959bac0aa36a0421c83e172c2 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Tue, 26 Nov 2024 03:15:04 +0000 Subject: [PATCH 06/10] upd --- product_carousel_image_attachment/models/ir_attachment.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 1116706f..362b48ab 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -15,8 +15,8 @@ def _resize_image(self, datas): ICP = self.env["ir.config_parameter"].sudo().get_param # Use 1025 instead of 1024 to enable the zoom feature. # Define a static value instead of modifying the system parameter - # 'base.image_autoresize_extensions' to avoid - # affecting other image fields. + # 'base.image_autoresize_max_px' to avoid + # affecting attachment resize. nw, nh = (1025, 1025) quality = int(ICP("base.image_autoresize_quality", 80)) img = ImageProcess(datas, verify_resolution=False) From 79ad804b0c2fb5dd33a9f61a72789f8bb91364ba Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Tue, 26 Nov 2024 08:23:46 +0000 Subject: [PATCH 07/10] upd --- .../data/scheduler.xml | 12 +++++++++ .../models/ir_attachment.py | 27 +++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/product_carousel_image_attachment/data/scheduler.xml b/product_carousel_image_attachment/data/scheduler.xml index 38ce6b2c..002ff600 100644 --- a/product_carousel_image_attachment/data/scheduler.xml +++ b/product_carousel_image_attachment/data/scheduler.xml @@ -14,4 +14,16 @@ + + Resize Attachment Image + + code + model._cron_resize_attachment_image(1000) + + 1 + hours + -1 + + + diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 362b48ab..b1213a19 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -1,15 +1,19 @@ # Copyright 2018 Quartile Limited # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api, models +from odoo import api, fields, models from odoo.tools import ImageProcess -IMAGE_TYPES = ["image/png", "image/jpeg", "image/bmp", "image/gif"] +IMAGE_TYPES = ["image/png", "image/jpeg", "image/bmp", "image/tiff"] class IrAttachment(models.Model): _inherit = "ir.attachment" + resize_done = fields.Boolean() + + # This function was for only purpose of updating existing old datas + # Resizing the new image will be handled by attachment_resize_image @api.model def _resize_image(self, datas): ICP = self.env["ir.config_parameter"].sudo().get_param @@ -27,6 +31,20 @@ def _resize_image(self, datas): return img.image_base64(quality=quality) return datas + @api.model + def _cron_resize_attachment_image(self, limit): + attachments = self.sudo().search( + [ + ("mimetype", "in", IMAGE_TYPES), + ("res_model", "in", ["product.template", "product.product"]), + ("resize_done", "=", False), + ], + limit=limit, + ) + for attachment in attachments: + attachment.datas = self._resize_image(attachment.datas) + attachments.resize_done = True + @api.model_create_multi def create(self, vals_list): attachments = super(IrAttachment, self).create(vals_list) @@ -40,21 +58,20 @@ def create(self, vals_list): ] and not attachment.res_field ): - resized_image = self._resize_image(attachment.datas) vals = {} # assignment for pt and p if attachment.res_model == "product.template": pt = self.env["product.template"].browse(attachment.res_id) vals = { "name": attachment.name, - "image_1920": resized_image, + "image_1920": attachment.datas, "product_tmpl_id": pt.id, } if attachment.res_model == "product.product": p = self.env["product.product"].browse(attachment.res_id) vals = { "name": attachment.name, - "image_1920": resized_image, + "image_1920": attachment.datas, "product_variant_id": p.id, } self.env["product.image"].sudo().create(vals) From 3cf682937b341ac2e60f369820a4dec71739a8c4 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Tue, 26 Nov 2024 08:30:39 +0000 Subject: [PATCH 08/10] adj --- product_carousel_image_attachment/models/ir_attachment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index b1213a19..5de22ec4 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -38,6 +38,7 @@ def _cron_resize_attachment_image(self, limit): ("mimetype", "in", IMAGE_TYPES), ("res_model", "in", ["product.template", "product.product"]), ("resize_done", "=", False), + ("res_field", "=", False), ], limit=limit, ) From b4518e9814d4efa134143ca9eaddbf1e9452b992 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Wed, 27 Nov 2024 04:00:50 +0000 Subject: [PATCH 09/10] adj --- .../models/ir_attachment.py | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 5de22ec4..779efc47 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -1,9 +1,16 @@ # Copyright 2018 Quartile Limited # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +import io +import logging + +from PIL import Image + from odoo import api, fields, models from odoo.tools import ImageProcess +_logger = logging.getLogger(__name__) + IMAGE_TYPES = ["image/png", "image/jpeg", "image/bmp", "image/tiff"] @@ -12,23 +19,34 @@ class IrAttachment(models.Model): resize_done = fields.Boolean() - # This function was for only purpose of updating existing old datas - # Resizing the new image will be handled by attachment_resize_image @api.model - def _resize_image(self, datas): + def _resize_image(self, datas, is_raw=False): ICP = self.env["ir.config_parameter"].sudo().get_param # Use 1025 instead of 1024 to enable the zoom feature. # Define a static value instead of modifying the system parameter # 'base.image_autoresize_max_px' to avoid # affecting attachment resize. - nw, nh = (1025, 1025) + max_width, max_height = 1025, 1025 quality = int(ICP("base.image_autoresize_quality", 80)) - img = ImageProcess(datas, verify_resolution=False) - w, h = img.image.size - if w > nw or h > nh: + try: # Use odoo standard resize - img = img.resize(nw, nh) - return img.image_base64(quality=quality) + if is_raw: + img = ImageProcess(False, verify_resolution=False) + img.image = Image.open(io.BytesIO(datas)) + img.original_format = (img.image.format or "").upper() + else: + img = ImageProcess(datas, verify_resolution=False) + width, height = img.image.size + if width > max_width or height > max_height: + img = img.resize(max_width, max_height) + return ( + img.image_quality(quality=quality) + if is_raw + else img.image_base64(quality=quality) + ) + except Exception as e: + _logger.warning(f"Failed to resize image: {e}") + return datas return datas @api.model @@ -48,6 +66,15 @@ def _cron_resize_attachment_image(self, limit): @api.model_create_multi def create(self, vals_list): + # here we resize the image first to avoid bloating the filestore + for values in vals_list: + mimetype = values.get("mimetype") or self._compute_mimetype(values) + if mimetype and mimetype.startswith("image/"): + # Resize raw binary or Base64 data + if "raw" in values and values["raw"]: + values["raw"] = self._resize_image(values["raw"], is_raw=True) + elif "datas" in values and values["datas"]: + values["datas"] = self._resize_image(values["datas"], is_raw=False) attachments = super(IrAttachment, self).create(vals_list) for attachment in attachments: if ( From aff29966e9a91549fe05590b14613644ea49e60b Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Wed, 27 Nov 2024 07:24:49 +0000 Subject: [PATCH 10/10] adj --- .../__manifest__.py | 1 - .../data/scheduler.xml | 29 -------- .../models/__init__.py | 1 - .../models/ir_attachment.py | 66 +------------------ .../models/product_image.py | 20 ------ 5 files changed, 1 insertion(+), 116 deletions(-) delete mode 100644 product_carousel_image_attachment/data/scheduler.xml delete mode 100644 product_carousel_image_attachment/models/product_image.py diff --git a/product_carousel_image_attachment/__manifest__.py b/product_carousel_image_attachment/__manifest__.py index e7000589..1c3b10a7 100644 --- a/product_carousel_image_attachment/__manifest__.py +++ b/product_carousel_image_attachment/__manifest__.py @@ -8,6 +8,5 @@ "category": "Tools", "license": "AGPL-3", "depends": ["website_sale"], - "data": ["data/scheduler.xml"], "installable": True, } diff --git a/product_carousel_image_attachment/data/scheduler.xml b/product_carousel_image_attachment/data/scheduler.xml deleted file mode 100644 index 002ff600..00000000 --- a/product_carousel_image_attachment/data/scheduler.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - Resize Extra Product Image - - code - model._cron_resize_product_image(1000) - - 1 - hours - -1 - - - - - Resize Attachment Image - - code - model._cron_resize_attachment_image(1000) - - 1 - hours - -1 - - - - diff --git a/product_carousel_image_attachment/models/__init__.py b/product_carousel_image_attachment/models/__init__.py index 3305f2c0..aaf38a16 100644 --- a/product_carousel_image_attachment/models/__init__.py +++ b/product_carousel_image_attachment/models/__init__.py @@ -1,2 +1 @@ from . import ir_attachment -from . import product_image diff --git a/product_carousel_image_attachment/models/ir_attachment.py b/product_carousel_image_attachment/models/ir_attachment.py index 779efc47..729721ef 100644 --- a/product_carousel_image_attachment/models/ir_attachment.py +++ b/product_carousel_image_attachment/models/ir_attachment.py @@ -1,15 +1,7 @@ # Copyright 2018 Quartile Limited # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import io -import logging - -from PIL import Image - -from odoo import api, fields, models -from odoo.tools import ImageProcess - -_logger = logging.getLogger(__name__) +from odoo import api, models IMAGE_TYPES = ["image/png", "image/jpeg", "image/bmp", "image/tiff"] @@ -17,64 +9,8 @@ class IrAttachment(models.Model): _inherit = "ir.attachment" - resize_done = fields.Boolean() - - @api.model - def _resize_image(self, datas, is_raw=False): - ICP = self.env["ir.config_parameter"].sudo().get_param - # Use 1025 instead of 1024 to enable the zoom feature. - # Define a static value instead of modifying the system parameter - # 'base.image_autoresize_max_px' to avoid - # affecting attachment resize. - max_width, max_height = 1025, 1025 - quality = int(ICP("base.image_autoresize_quality", 80)) - try: - # Use odoo standard resize - if is_raw: - img = ImageProcess(False, verify_resolution=False) - img.image = Image.open(io.BytesIO(datas)) - img.original_format = (img.image.format or "").upper() - else: - img = ImageProcess(datas, verify_resolution=False) - width, height = img.image.size - if width > max_width or height > max_height: - img = img.resize(max_width, max_height) - return ( - img.image_quality(quality=quality) - if is_raw - else img.image_base64(quality=quality) - ) - except Exception as e: - _logger.warning(f"Failed to resize image: {e}") - return datas - return datas - - @api.model - def _cron_resize_attachment_image(self, limit): - attachments = self.sudo().search( - [ - ("mimetype", "in", IMAGE_TYPES), - ("res_model", "in", ["product.template", "product.product"]), - ("resize_done", "=", False), - ("res_field", "=", False), - ], - limit=limit, - ) - for attachment in attachments: - attachment.datas = self._resize_image(attachment.datas) - attachments.resize_done = True - @api.model_create_multi def create(self, vals_list): - # here we resize the image first to avoid bloating the filestore - for values in vals_list: - mimetype = values.get("mimetype") or self._compute_mimetype(values) - if mimetype and mimetype.startswith("image/"): - # Resize raw binary or Base64 data - if "raw" in values and values["raw"]: - values["raw"] = self._resize_image(values["raw"], is_raw=True) - elif "datas" in values and values["datas"]: - values["datas"] = self._resize_image(values["datas"], is_raw=False) attachments = super(IrAttachment, self).create(vals_list) for attachment in attachments: if ( diff --git a/product_carousel_image_attachment/models/product_image.py b/product_carousel_image_attachment/models/product_image.py deleted file mode 100644 index 2b0c9f79..00000000 --- a/product_carousel_image_attachment/models/product_image.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2024 Quartile -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). - -from odoo import api, fields, models - - -class ProductImage(models.Model): - _inherit = "product.image" - - resize_done = fields.Boolean() - - @api.model - def _cron_resize_product_image(self, limit): - images = self.sudo().search( - [("can_image_1024_be_zoomed", "=", True), ("resize_done", "=", False)], - limit=limit, - ) - for image in images: - image.image_1920 = self.env["ir.attachment"]._resize_image(image.image_1920) - image.resize_done = True