"""
Module saves the picture of an object in Odoo.
"""
import base64
import os
import configparser
import io
from PIL import Image
# call the function "get_settings_odoo" to get the parameters
# for the logging of the model on the "odoo Webservice API"
try:
from .get_settings_odoo import get_settings_odoo
except ImportError:
from get_settings_odoo import get_settings_odoo
result = get_settings_odoo()
db = result[0]
uid = result[1]
password = result[3]
models = result[4]
# ------- for the initialisation get parameters from the File "parameter_google.ini" -------
# Name and full path of the Parameter File
file_name = "parameter_google.ini"
path_name = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # Go up to repo root
config_path = os.path.join(path_name, 'config')
fullpath = os.path.join(config_path, file_name)
config = configparser.ConfigParser()
config.read(fullpath)
# get the aspect ratio for the picture to be saved
aspect_ratio = config.get('handle_picture', 'aspect_ratio')
custom_aspect_ratio = float(aspect_ratio)
# get the image size for the picture to be saved
# must be either 1920, 1024, 512, 256 or 128
image_size = config.get('handle_picture', 'image_size')
custom_image_size = int(image_size)
[docs]
def pad_if_needed(img, target_aspect_ratio, padding_color=(0, 0, 0, 0)):
"""
Adds padding only if the image's aspect ratio does not match the target.
Keeps the original image unchanged and centers it on a new canvas if needed.
Parameters:
img: PIL.Image – input image (any mode)
target_aspect_ratio: float – desired aspect ratio (width / height)
padding_color: tuple or int – background color (must match img.mode)
Returns:
PIL.Image – either the original image or a padded one
"""
current_aspect = img.width / img.height
if abs(current_aspect - target_aspect_ratio) < 1e-2:
# Already matches → return unchanged
return img
# Calculate new canvas size
if current_aspect > target_aspect_ratio:
# Too wide → pad height
new_height = int(img.width / target_aspect_ratio)
new_width = img.width
else:
# Too tall → pad width
new_width = int(img.height * target_aspect_ratio)
new_height = img.height
# Create a new canvas in the same mode with the background color
padded = Image.new(img.mode, (new_width, new_height), padding_color)
# Paste original image in the center
offset_x = (new_width - img.width) // 2
offset_y = (new_height - img.height) // 2
padded.paste(img, (offset_x, offset_y))
return padded
[docs]
def save_picture(product_id, perspective_or_image, image=None):
"""
Function saves the picture under the product_template_id of the product.
The image will be stored with the image size from 'custom_image_size'.
"""
# Handle different calling patterns
if image is None:
# Called with 2 parameters: save_picture(product_id, image_data)
perspective = 'general'
image = perspective_or_image
else:
# Called with 3 parameters: save_picture(product_id, perspective, image_data)
perspective = perspective_or_image
# convert base64 string (= image) to PIL image (= img)
buffer = io.BytesIO()
imgdata = base64.b64decode(image)
img = Image.open(io.BytesIO(imgdata))
# initialize the result
custom_id = ''
if product_id != '':
# get the product_template_id for the product
# the picture will be save under the product_template_id as the key value
custom_product = models.execute_kw(db,uid, password,
'product.product', 'search_read',
[[['id', '=', product_id]]],
{'fields': ['product_tmpl_id']})
# if the array is not empty
# get the value for 'product_tmpl_id'
if custom_product:
for key, value in custom_product[0].items():
if key == "product_tmpl_id":
custom_product_tmpl_id = value[0]
# build the "res_field" name for the picture, must be like for example "image_128"
custom_res_field = "image_" + str(custom_image_size)
# build the name for the picture, like for example "image_128_front"
custom_name = custom_res_field + "_" + perspective
# pads the image only if needed, while keeping everything else untouched.
img_padded = pad_if_needed(img, custom_aspect_ratio, padding_color=(0, 0, 0, 0)) # Transparent padding
img_padded.save(buffer, format="PNG")
img_b64 = base64.b64encode(buffer.getvalue())
custom_datas = img_b64.decode('ascii')
# store the image in the Odoo database
# save the picture under the product_template_id
# the value "datas" will keep the picture image
custom_id = models.execute_kw(db,uid, password,'ir.attachment', 'create',
[{'name': custom_name,
'datas': custom_datas,
'type': 'binary',
'res_id': custom_product_tmpl_id,
'res_field': custom_res_field,
'res_model': 'product.template',}])
# the result is the id of the newly created dataset of the image in the table "ir.attachment"
return(custom_id)