chore: initialize tuhui repository
This commit is contained in:
127
backend/app/utils/image.py
Normal file
127
backend/app/utils/image.py
Normal file
@@ -0,0 +1,127 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user