mirror of
https://github.com/DrizzleTime/Foxel.git
synced 2026-05-12 02:20:28 +08:00
68 lines
2.6 KiB
Python
68 lines
2.6 KiB
Python
from .base import BaseProcessor
|
|
from typing import Dict, Any
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
from io import BytesIO
|
|
from fastapi.responses import Response
|
|
from services.logging import LogService
|
|
|
|
class ImageWatermarkProcessor:
|
|
name = "图片水印"
|
|
supported_exts = ["jpg", "jpeg", "png", "bmp"]
|
|
config_schema = [
|
|
{"key": "text", "label": "水印文字", "type": "string", "required": True},
|
|
{
|
|
"key": "position",
|
|
"label": "位置",
|
|
"type": "select",
|
|
"required": False,
|
|
"default": "bottom-right",
|
|
"options": [
|
|
{"value": "top-left", "label": "左上"},
|
|
{"value": "center", "label": "居中"},
|
|
{"value": "bottom-right", "label": "右下"},
|
|
],
|
|
},
|
|
{"key": "font_size", "label": "字体大小", "type": "number", "required": False, "default": 24},
|
|
]
|
|
produces_file = True
|
|
|
|
async def process(self, input_bytes: bytes,path: str, config: Dict[str, Any]) -> Response:
|
|
text = config.get("text", "")
|
|
position = config.get("position", "bottom-right")
|
|
font_size = int(config.get("font_size", 24))
|
|
img = Image.open(BytesIO(input_bytes)).convert("RGBA")
|
|
watermark = Image.new("RGBA", img.size)
|
|
draw = ImageDraw.Draw(watermark)
|
|
try:
|
|
font = ImageFont.truetype("arial.ttf", font_size)
|
|
except Exception:
|
|
font = ImageFont.load_default()
|
|
w, h = img.size
|
|
try:
|
|
text_w, text_h = font.getsize(text)
|
|
except AttributeError:
|
|
bbox = draw.textbbox((0, 0), text, font=font)
|
|
text_w, text_h = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
|
if position == "bottom-right":
|
|
xy = (w - text_w - 10, h - text_h - 10)
|
|
elif position == "top-left":
|
|
xy = (10, 10)
|
|
else:
|
|
xy = (w // 2 - text_w // 2, h // 2 - text_h // 2)
|
|
draw.text(xy, text, font=font, fill=(255, 255, 255, 128))
|
|
out = Image.alpha_composite(img, watermark)
|
|
buf = BytesIO()
|
|
out.convert("RGB").save(buf, format="JPEG")
|
|
await LogService.info(
|
|
"processor:image_watermark",
|
|
f"Watermarked image {path}",
|
|
details={"path": path, "config": config},
|
|
)
|
|
return Response(content=buf.getvalue(), media_type="image/jpeg")
|
|
|
|
PROCESSOR_TYPE = "image_watermark"
|
|
PROCESSOR_NAME = ImageWatermarkProcessor.name
|
|
SUPPORTED_EXTS = ImageWatermarkProcessor.supported_exts
|
|
CONFIG_SCHEMA = ImageWatermarkProcessor.config_schema
|
|
PROCESSOR_FACTORY = lambda: ImageWatermarkProcessor()
|