Files
tuhui.cloud/backend/app/utils/image.py
2026-03-08 19:28:32 +08:00

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
}