import os.path as osp from PIL import Image def apply_watermark_to_pil_image(img_pil: Image.Image, watermark_path: str, opacity: float = 0.7) -> Image.Image: """ Apply watermark to a PIL image Args: img_pil (Image.Image): Source PIL image watermark_path (str): Path to watermark image opacity (float): Watermark opacity (0.0 - 1.0) Returns: Image.Image: Watermarked PIL image """ if not osp.exists(watermark_path): return img_pil try: watermark = Image.open(watermark_path) except Exception: return img_pil # Ensure images are in RGBA mode if img_pil.mode != 'RGBA': img_pil = img_pil.convert('RGBA') if watermark.mode != 'RGBA': watermark = watermark.convert('RGBA') # Fixed watermark size (adjust as needed) WATERMARK_FIXED_WIDTH = 418 WATERMARK_FIXED_HEIGHT = 120 # Resize watermark watermark = watermark.resize((WATERMARK_FIXED_WIDTH, WATERMARK_FIXED_HEIGHT), Image.LANCZOS) # Apply opacity if opacity < 1.0: alpha = watermark.split()[3] alpha = alpha.point(lambda p: p * opacity) watermark.putalpha(alpha) # Get image dimensions img_width, img_height = img_pil.size # Create transparent layer for watermarks wm_layer = Image.new('RGBA', img_pil.size, (0, 0, 0, 0)) # Calculate watermark positions (bottom to top) initial_y = img_height - watermark.height - 10 # 10px from bottom x_position = 10 # 10px from left # Repeat watermark vertically current_y = initial_y while current_y > -watermark.height: if current_y < 0: # Crop watermark if it goes beyond top boundary crop_height = watermark.height + current_y if crop_height > 0: partial_wm = watermark.crop((0, -current_y, watermark.width, watermark.height)) wm_layer.paste(partial_wm, (x_position, 0), partial_wm) else: wm_layer.paste(watermark, (x_position, current_y), watermark) current_y -= 8000 # Vertical spacing (adjust as needed) # Composite original image with watermark layer return Image.alpha_composite(img_pil, wm_layer)