"""浏览器合成海报的文件与尺寸校验。""" import io from PIL import Image from insurance.poster.format_registry import list_poster_formats class PosterRenderValidationError(ValueError): """最终海报文件不符合格式契约。""" def validate_rendered_png( image_bytes: bytes, format_id: str, expected_height: int | None = None, ) -> dict: """完整解码 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}" ) 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}" ) if expected["height"] is None and not 1 <= height <= 32767: raise PosterRenderValidationError("长图高度超出浏览器安全范围") return {"width": width, "height": height, "format": image_format}