# -*- coding: utf-8 -*- import base64 import io import logging from PIL import Image from odoo import http from odoo.http import request from odoo.tools import image_process from odoo.addons.sign.controllers.main import Sign _logger = logging.getLogger(__name__) class SignController(Sign): @http.route(['/sign/sign//'], type='json', auth='public') def sign_document(self, request_id, token, signature=None, items=None, **kwargs): if items: # Filter items that look like images (base64) # We can't easily know the type of item just from the ID without a lookup # But we can try to decode and compress if it looks like a large base64 string # Optimization: Fetch all item types at once to identify image field types item_ids = [int(k) for k in items.keys()] sign_items = request.env['sign.item'].sudo().browse(item_ids) image_items_ids = set(sign_items.filtered(lambda i: i.type_id.item_type == 'image').ids) for key, value in items.items(): if int(key) in image_items_ids and value and isinstance(value, str): if value.startswith('/sign/image/'): # Skip URLs (handled by sign_sequence_field or already processed) continue try: # Value comes as "data:image/png;base64,..." usually # But Odoo sometimes strips header or not. # sign_image_upload.js sends the full data URL. header = None image_data = value if ',' in value: header, image_data = value.split(',', 1) # Compress # Decode image_bytes = base64.b64decode(image_data) # Process image: limit size to max 1920x1920 and reasonable quality # image_process returns the processed image binary processed_image = image_process(image_bytes, size=(1920, 1920), quality=80, output_format='JPEG') # Re-encode new_base64 = base64.b64encode(processed_image).decode('utf-8') # Re-attach header if it was there, but ensure it matches new format (JPEG) # Actually, keeping original header type might be misleading if we converted to JPEG. # But for Odoo chatter/display, usually data:image/jpeg;base64 is safer if we converted. new_value = f"data:image/jpeg;base64,{new_base64}" items[key] = new_value _logger.info(f"Compressed image for item {key}: {len(value)} -> {len(new_value)} chars") except Exception as e: _logger.warning(f"Failed to compress image for item {key}: {e}") # Leave original value if compression fails return super().sign_document(request_id, token, signature=signature, items=items, **kwargs)