1
0

feat: 移除图片适配模式功能

移除图片 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>
This commit is contained in:
2026-03-04 14:23:12 +08:00
parent 2fd8bc1b4a
commit f34405be36
31 changed files with 494 additions and 1556 deletions

View File

@@ -1,149 +0,0 @@
"""
图片处理工具模块
提供图片适配模式处理、像素与英寸转换等功能。
"""
from PIL import Image, ImageOps
from typing import Tuple, Optional
def inches_to_pixels(inches: float, dpi: int = 96) -> float:
"""
将英寸转换为像素
Args:
inches: 英寸值
dpi: DPI每英寸像素数默认 96
Returns:
像素值
"""
return inches * dpi
def pixels_to_inches(pixels: float, dpi: int = 96) -> float:
"""
将像素转换为英寸
Args:
pixels: 像素值
dpi: DPI每英寸像素数默认 96
Returns:
英寸值
"""
return pixels / dpi
def create_canvas_with_background(size: Tuple[int, int], background_color: str) -> Image.Image:
"""
创建带背景色的画布
Args:
size: 画布尺寸 (width, height)
background_color: 背景颜色(#RRGGBB 或 #RGB 格式)
Returns:
PIL Image 对象
"""
# 验证颜色格式
import re
if not isinstance(background_color, str):
raise ValueError(f"无效的颜色格式: {background_color}")
pattern = r'^#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})$'
if not re.match(pattern, background_color):
raise ValueError(f"无效的颜色格式: {background_color}")
# 创建 RGB 模式的画布
canvas = Image.new('RGB', size, background_color)
return canvas
def apply_fit_mode(
img: Image.Image,
box_size: Tuple[int, int],
fit: Optional[str] = None,
background: Optional[str] = None
) -> Image.Image:
"""
应用图片适配模式
Args:
img: PIL Image 对象
box_size: 目标尺寸 (width, height) 像素
fit: 适配模式stretch, contain, cover, center默认 stretch
background: 背景颜色(#RRGGBB 或 #RGB 格式),仅对 contain 和 center 模式有效
Returns:
处理后的 PIL Image 对象
"""
if fit is None or fit == 'stretch':
# stretch 模式:直接拉伸到目标尺寸
return img.resize(box_size, Image.Resampling.LANCZOS)
elif fit == 'contain':
# contain 模式:保持宽高比,完整显示在 box 内
# 如果图片比 box 小,保持原始尺寸;如果比 box 大,等比缩小
img_width, img_height = img.size
box_width, box_height = box_size
# 检查图片是否需要缩小
if img_width <= box_width and img_height <= box_height:
# 图片比 box 小,保持原始尺寸
result = img
else:
# 图片比 box 大,使用 contain 缩小
result = ImageOps.contain(img, box_size, Image.Resampling.LANCZOS)
# 如果指定了背景色,创建画布并居中粘贴
if background:
canvas = create_canvas_with_background(box_size, background)
# 计算居中位置
offset_x = (box_size[0] - result.width) // 2
offset_y = (box_size[1] - result.height) // 2
canvas.paste(result, (offset_x, offset_y))
return canvas
return result
elif fit == 'cover':
# cover 模式:保持宽高比,填满 box裁剪超出部分
result = ImageOps.cover(img, box_size, Image.Resampling.LANCZOS)
# ImageOps.cover 可能返回比 box_size 大的图片,需要裁剪到精确尺寸
if result.size != box_size:
# 从中心裁剪到目标尺寸
left = (result.width - box_size[0]) // 2
top = (result.height - box_size[1]) // 2
result = result.crop((left, top, left + box_size[0], top + box_size[1]))
return result
elif fit == 'center':
# center 模式:不缩放,居中显示,超出部分裁剪
img_width, img_height = img.size
box_width, box_height = box_size
# 如果图片比 box 大,需要裁剪
if img_width > box_width or img_height > box_height:
# 计算裁剪区域(从中心裁剪)
left = max(0, (img_width - box_width) // 2)
top = max(0, (img_height - box_height) // 2)
right = min(img_width, left + box_width)
bottom = min(img_height, top + box_height)
result = img.crop((left, top, right, bottom))
else:
result = img
# 如果指定了背景色,创建画布并居中粘贴
if background:
canvas = create_canvas_with_background(box_size, background)
# 计算居中位置
offset_x = (box_size[0] - result.width) // 2
offset_y = (box_size[1] - result.height) // 2
canvas.paste(result, (offset_x, offset_y))
return canvas
return result
else:
raise ValueError(f"不支持的 fit 模式: {fit}")