128 lines
3.6 KiB
Python
128 lines
3.6 KiB
Python
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
|
|
}
|