Images with transparent background, like from PNG, get their alpha channel (transparency) converted to black, resulting in weird prints.
This should be defaulted into white, and possibly given an option to change it.
After investigating i found Odoo converts PNG to WEBP, so alpha channel conversion is not so straight forward.
This can be solved with python package pillow.
Solution
requirements.txt
utils/image_flatten.py
"""Image flatten utility: flatten PNG/WebP transparency to white using Pillow.
Moved from image_flatten_helper.py into utils namespace for clarity.
"""
from __future__ import annotations
import base64
import io
try: # Pillow optional at runtime
from PIL import Image # type: ignore
except Exception: # pragma: no cover
Image = None # type: ignore
def flatten_image_transparency_base64(image_data: str):
"""Flatten alpha to white for PNG/WebP base64 input. Returns base64 PNG or original.
Placeholder fallback previously present is removed; if decode fails original is returned.
"""
if not image_data:
return image_data
if not Image:
return image_data
try:
raw = base64.b64decode(image_data)
except Exception:
return image_data
try:
with Image.open(io.BytesIO(raw)) as im:
im.load()
has_alpha = ('A' in im.getbands()) or ('transparency' in im.info)
if has_alpha and im.mode not in ('RGBA', 'LA'):
im = im.convert('RGBA')
if has_alpha:
alpha = im.split()[-1]
bg = Image.new('RGBA', im.size, (255, 255, 255, 255))
bg.paste(im, mask=alpha)
out = bg.convert('RGB')
else:
out = im.convert('RGB') if im.mode not in ('RGB', 'L') else im
buf = io.BytesIO()
out.save(buf, format='PNG', optimize=True)
return base64.b64encode(buf.getvalue()).decode('utf-8')
except Exception:
return image_data
models/sale_order_line.py
from odoo import api, fields, models
from ..utils import image_flatten as image_flatten_helper
try: # Pillow optional; only used indirectly via helper
from PIL import Image # type: ignore
except Exception: # pragma: no cover - environment without Pillow
Image = None # type: ignore
class SaleOrderLine(models.Model):
"""Inherits the model sale.order.line to add a field"""
_inherit = 'sale.order.line'
order_line_image = fields.Binary(string="Image",compute="_compute_order_line_image",help='Product Image with PNG transparency converted to white background')
@api.depends('product_id.image_1920')
def _compute_order_line_image(self):
"""Convert PNG alpha channel to white background using pure Python"""
for line in self:
if not line.product_id.image_1920:
line.order_line_image = False
continue
try:
converted_image = self._flatten_transparency(line.product_id.image_1920)
line.order_line_image = converted_image or line.product_id.image_1920
except Exception:
# On any failure fall back silently to original image
line.order_line_image = line.product_id.image_1920
def _flatten_transparency(self, image_data):
"""Flatten transparency of PNG/WebP images using Pillow (via helper).
Simplified: single helper call, minimal diagnostics. Returns original data on any failure.
Placeholder fallback logic removed; if WebP decode fails upstream it just returns original.
"""
if not image_data:
return image_data
try:
return image_flatten_helper.flatten_image_transparency_base64(image_data)
except Exception: # pragma: no cover - defensive
return image_data
models/res_config_settings.py
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
"""Extend settings with toggles controlling sale order report images."""
_inherit = 'res.config.settings'
is_show_product_image_in_sale_report = fields.Boolean(
string="Show Product Image",
config_parameter='sale_product_image.is_show_product_image_in_sale_report',
help='Display product images on the Sale Order report.')
force_jpeg_sale_report_images = fields.Boolean(
string="Force JPEG Conversion",
config_parameter='sale_product_image.force_jpeg_sale_report_images',
help='After flattening PNG/WebP transparency to white, convert to JPEG to reduce PDF size and avoid edge artifacts.')
manifest.py
add
'external_dependencies': {
'python': ['Pillow']
}
Hope that helps.
Have a nice day !
Images with transparent background, like from PNG, get their alpha channel (transparency) converted to black, resulting in weird prints.
This should be defaulted into white, and possibly given an option to change it.
After investigating i found Odoo converts PNG to WEBP, so alpha channel conversion is not so straight forward.
This can be solved with python package pillow.
Solution
requirements.txt
utils/image_flatten.py
models/sale_order_line.py
models/res_config_settings.py
manifest.py
add
Hope that helps.
Have a nice day !