移除图片 fit 和 background 参数支持,简化图片渲染逻辑。系统恢复到直接使用 python-pptx 原生图片添加功能,图片将被拉伸到指定尺寸。 变更内容: - 移除 ImageElement 的 fit 和 background 字段 - 移除 metadata.dpi 配置 - 删除 utils/image_utils.py 图片处理工具模块 - 删除 validators/image_config.py 验证器 - 简化 PPTX 和 HTML 渲染器的图片处理逻辑 - HTML 渲染器使用硬编码 DPI=96(Web 标准) - 删除相关测试文件(单元测试、集成测试、e2e 测试) - 更新规格文档和用户文档 - 保留 Pillow 依赖用于未来可能的图片处理需求 影响: - 删除 11 个文件 - 修改 10 个文件 - 净减少 1558 行代码 - 所有 402 个测试通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
166 lines
5.8 KiB
Python
166 lines
5.8 KiB
Python
"""
|
||
主验证器
|
||
|
||
协调各子验证器,执行完整的 YAML 文件验证。
|
||
"""
|
||
|
||
from pathlib import Path
|
||
from loaders.yaml_loader import load_yaml_file, validate_presentation_yaml, YAMLError
|
||
from validators.result import ValidationResult, ValidationIssue
|
||
from validators.geometry import GeometryValidator
|
||
from validators.resource import ResourceValidator
|
||
from core.elements import create_element
|
||
|
||
|
||
class Validator:
|
||
"""主验证器"""
|
||
|
||
# 幻灯片尺寸映射(英寸)
|
||
SLIDE_SIZES = {
|
||
"16:9": (10, 5.625),
|
||
"4:3": (10, 7.5),
|
||
}
|
||
|
||
def __init__(self):
|
||
"""初始化验证器"""
|
||
pass
|
||
|
||
def validate(self, yaml_path: Path, template_dir: Path = None) -> ValidationResult:
|
||
"""
|
||
验证 YAML 文件
|
||
|
||
Args:
|
||
yaml_path: YAML 文件路径
|
||
template_dir: 模板文件目录(可选)
|
||
|
||
Returns:
|
||
验证结果
|
||
"""
|
||
errors = []
|
||
warnings = []
|
||
infos = []
|
||
|
||
# 1. 加载 YAML
|
||
try:
|
||
data = load_yaml_file(yaml_path)
|
||
validate_presentation_yaml(data, str(yaml_path))
|
||
except YAMLError as e:
|
||
errors.append(
|
||
ValidationIssue(
|
||
level="ERROR", message=str(e), location="", code="YAML_ERROR"
|
||
)
|
||
)
|
||
return ValidationResult(
|
||
valid=False, errors=errors, warnings=warnings, infos=infos
|
||
)
|
||
except Exception as e:
|
||
errors.append(
|
||
ValidationIssue(
|
||
level="ERROR",
|
||
message=f"加载 YAML 文件失败: {str(e)}",
|
||
location="",
|
||
code="YAML_LOAD_ERROR",
|
||
)
|
||
)
|
||
return ValidationResult(
|
||
valid=False, errors=errors, warnings=warnings, infos=infos
|
||
)
|
||
|
||
# 获取幻灯片尺寸
|
||
size_str = data.get("metadata", {}).get("size", "16:9")
|
||
slide_width, slide_height = self.SLIDE_SIZES.get(size_str, (10, 5.625))
|
||
|
||
# 初始化子验证器
|
||
geometry_validator = GeometryValidator(slide_width, slide_height)
|
||
resource_validator = ResourceValidator(
|
||
yaml_dir=yaml_path.parent, template_dir=template_dir, yaml_data=data
|
||
)
|
||
|
||
# 2. 验证每个幻灯片
|
||
slides = data.get("slides", [])
|
||
for slide_index, slide_data in enumerate(slides, start=1):
|
||
# 验证模板
|
||
template_issues = resource_validator.validate_template(
|
||
slide_data, slide_index
|
||
)
|
||
self._categorize_issues(template_issues, errors, warnings, infos)
|
||
|
||
# 验证模板变量
|
||
template_var_issues = resource_validator.validate_template_vars(
|
||
slide_data, slide_index
|
||
)
|
||
self._categorize_issues(template_var_issues, errors, warnings, infos)
|
||
|
||
# 验证元素
|
||
elements = slide_data.get("elements", [])
|
||
for elem_index, elem_dict in enumerate(elements, start=1):
|
||
# 3. 元素级验证
|
||
try:
|
||
element = create_element(elem_dict)
|
||
|
||
# 调用元素的 validate() 方法
|
||
if hasattr(element, "validate"):
|
||
elem_issues = element.validate()
|
||
# 填充位置信息
|
||
for issue in elem_issues:
|
||
issue.location = f"幻灯片 {slide_index}, 元素 {elem_index}"
|
||
self._categorize_issues(elem_issues, errors, warnings, infos)
|
||
|
||
# 4. 几何验证
|
||
geom_issues = geometry_validator.validate_element(
|
||
element, slide_index, elem_index
|
||
)
|
||
self._categorize_issues(geom_issues, errors, warnings, infos)
|
||
|
||
# 5. 资源验证(图片)
|
||
if elem_dict.get("type") == "image":
|
||
img_issues = resource_validator.validate_image(
|
||
element, slide_index, elem_index
|
||
)
|
||
self._categorize_issues(img_issues, errors, warnings, infos)
|
||
|
||
except ValueError as e:
|
||
# 元素创建失败(__post_init__ 中的验证)
|
||
errors.append(
|
||
ValidationIssue(
|
||
level="ERROR",
|
||
message=str(e),
|
||
location=f"幻灯片 {slide_index}, 元素 {elem_index}",
|
||
code="ELEMENT_VALIDATION_ERROR",
|
||
)
|
||
)
|
||
except Exception as e:
|
||
errors.append(
|
||
ValidationIssue(
|
||
level="ERROR",
|
||
message=f"验证元素时出错: {str(e)}",
|
||
location=f"幻灯片 {slide_index}, 元素 {elem_index}",
|
||
code="ELEMENT_VALIDATION_ERROR",
|
||
)
|
||
)
|
||
|
||
# 返回验证结果
|
||
return ValidationResult(
|
||
valid=len(errors) == 0, errors=errors, warnings=warnings, infos=infos
|
||
)
|
||
|
||
def _categorize_issues(
|
||
self, issues: list, errors: list, warnings: list, infos: list
|
||
):
|
||
"""
|
||
将问题按级别分类
|
||
|
||
Args:
|
||
issues: 问题列表
|
||
errors: 错误列表
|
||
warnings: 警告列表
|
||
infos: 提示列表
|
||
"""
|
||
for issue in issues:
|
||
if issue.level == "ERROR":
|
||
errors.append(issue)
|
||
elif issue.level == "WARNING":
|
||
warnings.append(issue)
|
||
elif issue.level == "INFO":
|
||
infos.append(issue)
|