from PIL import Image, ImageDraw, ImageFont, ImageFilter import cv2 import numpy as np def apply_watermark(image_cv: np.ndarray) -> np.ndarray: """ Applies the 'AuraLens' professional text watermark to the bottom-center of the image using a clean minimalist typography style. """ # Convert OpenCV image (BGR) to PIL Image (RGB) img_pil = Image.fromarray(cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB)) # Create a transparent overlay for the watermark overlay = Image.new('RGBA', img_pil.size, (255, 255, 255, 0)) draw = ImageDraw.Draw(overlay) width, height = img_pil.size # Scale font size based on image height font_size = max(int(height * 0.03), 16) # Try to use a good default font, fallback to default if not available try: font = ImageFont.truetype("arial.ttf", font_size) except IOError: font = ImageFont.load_default() # default font is very small, we manually scale the text layer if needed # but for safety we'll just use what we get text = "A U R A L E N S" # Get text bounding box to calculate position if hasattr(font, 'getbbox'): bbox = font.getbbox(text) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] else: # Fallback for older Pillow versions text_width, text_height = draw.textsize(text, font=font) x = (width - text_width) // 2 # Place it at the bottom with some padding (5% of height) y = height - text_height - int(height * 0.05) # Draw drop shadow (slightly offset, black with low opacity) shadow_offset = max(2, int(font_size * 0.05)) draw.text((x + shadow_offset, y + shadow_offset), text, font=font, fill=(0, 0, 0, 150)) # Draw the main white text draw.text((x, y), text, font=font, fill=(255, 255, 255, 230)) # Composite the overlay onto the original image watermarked_pil = Image.alpha_composite(img_pil.convert('RGBA'), overlay) # Convert back to OpenCV BGR watermarked_cv = cv2.cvtColor(np.array(watermarked_pil), cv2.COLOR_RGBA2BGR) return watermarked_cv