from PIL import Image, ImageDraw, ImageFont import os from pathlib import Path from app.core.config import settings def add_watermark(input_path: str, output_path: str, text: str = None) -> str: """ 给图片添加水印 Args: input_path: 输入图片路径 output_path: 输出图片路径 text: 水印文字,默认使用配置 Returns: 输出图片路径 """ if text is None: text = settings.WATERMARK_TEXT # 打开原图 image = Image.open(input_path).convert("RGBA") width, height = image.size # 创建水印层 watermark = Image.new("RGBA", image.size, (0, 0, 0, 0)) draw = ImageDraw.Draw(watermark) # 计算字体大小(根据图片大小自适应) font_size = int(min(width, height) / 20) try: # 尝试使用系统字体 font = ImageFont.truetype("arial.ttf", font_size) except: # 如果没有找到字体,使用默认字体 font = ImageFont.load_default() # 获取文字大小 bbox = draw.textbbox((0, 0), text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] # 计算水印位置(右下角) x = width - text_width - 20 y = height - text_height - 20 # 绘制水印(半透明白色文字 + 黑色描边) # 先绘制黑色描边 for adj_x in range(-2, 3): for adj_y in range(-2, 3): draw.text((x + adj_x, y + adj_y), text, font=font, fill=(0, 0, 0, settings.WATERMARK_OPACITY)) # 再绘制白色文字 draw.text((x, y), text, font=font, fill=(255, 255, 255, settings.WATERMARK_OPACITY)) # 合并图层 watermarked = Image.alpha_composite(image, watermark) # 转换为 RGB 并保存 watermarked_rgb = watermarked.convert("RGB") # 确保输出目录存在 os.makedirs(os.path.dirname(output_path), exist_ok=True) watermarked_rgb.save(output_path, "JPEG", quality=95) return output_path def create_thumbnail(input_path: str, output_path: str, size: int = None) -> str: """ 创建缩略图 Args: input_path: 输入图片路径 output_path: 输出图片路径 size: 缩略图最大尺寸,默认使用配置 Returns: 输出图片路径 """ if size is None: size = settings.THUMBNAIL_SIZE # 打开原图 image = Image.open(input_path) # 计算缩略图尺寸(保持宽高比) image.thumbnail((size, size), Image.Resampling.LANCZOS) # 确保输出目录存在 os.makedirs(os.path.dirname(output_path), exist_ok=True) # 保存缩略图 image.save(output_path, "JPEG", quality=settings.THUMBNAIL_QUALITY) return output_path def process_uploaded_image(original_path: str, work_id: int) -> dict: """ 处理上传的图片:生成水印图和缩略图 Args: original_path: 原图路径 work_id: 作品ID Returns: 包含三个图片路径的字典 """ # 生成文件名 filename = f"{work_id}.jpg" # 定义输出路径 watermarked_path = os.path.join(settings.UPLOAD_DIR, "watermarked", filename) thumbnail_path = os.path.join(settings.UPLOAD_DIR, "thumbnail", filename) # 生成带水印的图片 add_watermark(original_path, watermarked_path) # 生成缩略图 create_thumbnail(original_path, thumbnail_path) return { "original": original_path, "watermarked": watermarked_path, "thumbnail": thumbnail_path }