2026-07-31 21:42:32 +08:00
|
|
|
|
"""浏览器合成海报的文件与尺寸校验。"""
|
|
|
|
|
|
import io
|
|
|
|
|
|
|
|
|
|
|
|
from PIL import Image
|
|
|
|
|
|
|
|
|
|
|
|
from insurance.poster.format_registry import list_poster_formats
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PosterRenderValidationError(ValueError):
|
|
|
|
|
|
"""最终海报文件不符合格式契约。"""
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-31 22:05:57 +08:00
|
|
|
|
def validate_rendered_png(
|
|
|
|
|
|
image_bytes: bytes,
|
|
|
|
|
|
format_id: str,
|
|
|
|
|
|
expected_height: int | None = None,
|
|
|
|
|
|
) -> dict:
|
2026-07-31 21:42:32 +08:00
|
|
|
|
"""完整解码 PNG,并验证其真实像素尺寸。"""
|
|
|
|
|
|
format_spec = next(
|
|
|
|
|
|
(item for item in list_poster_formats() if item["id"] == format_id),
|
|
|
|
|
|
None,
|
|
|
|
|
|
)
|
|
|
|
|
|
if not format_spec:
|
|
|
|
|
|
raise PosterRenderValidationError(f"不支持的海报格式: {format_id}")
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
with Image.open(io.BytesIO(image_bytes)) as image:
|
|
|
|
|
|
image.verify()
|
|
|
|
|
|
with Image.open(io.BytesIO(image_bytes)) as image:
|
|
|
|
|
|
image.load()
|
|
|
|
|
|
width, height = image.size
|
|
|
|
|
|
image_format = image.format
|
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
|
raise PosterRenderValidationError("PNG 文件无法解码或已经损坏") from exc
|
|
|
|
|
|
|
|
|
|
|
|
if image_format != "PNG":
|
|
|
|
|
|
raise PosterRenderValidationError("最终海报必须是 PNG 格式")
|
|
|
|
|
|
|
|
|
|
|
|
expected = format_spec["output"]
|
|
|
|
|
|
if width != expected["width"]:
|
|
|
|
|
|
raise PosterRenderValidationError(
|
|
|
|
|
|
f"海报宽度不匹配,应为 {expected['width']}px,实际为 {width}px"
|
|
|
|
|
|
)
|
|
|
|
|
|
if expected["height"] is not None and height != expected["height"]:
|
|
|
|
|
|
raise PosterRenderValidationError(
|
|
|
|
|
|
f"海报尺寸不匹配,应为 {expected['width']}×{expected['height']},"
|
|
|
|
|
|
f"实际为 {width}×{height}"
|
|
|
|
|
|
)
|
2026-07-31 22:05:57 +08:00
|
|
|
|
if expected["height"] is None and expected_height is not None and height != expected_height:
|
|
|
|
|
|
raise PosterRenderValidationError(
|
|
|
|
|
|
f"长图自定义高度不匹配,应为 {expected['width']}×{expected_height},"
|
|
|
|
|
|
f"实际为 {width}×{height}"
|
|
|
|
|
|
)
|
2026-07-31 21:42:32 +08:00
|
|
|
|
if expected["height"] is None and not 1 <= height <= 32767:
|
|
|
|
|
|
raise PosterRenderValidationError("长图高度超出浏览器安全范围")
|
|
|
|
|
|
|
|
|
|
|
|
return {"width": width, "height": height, "format": image_format}
|