Spaces:
Sleeping
Sleeping
File size: 6,140 Bytes
76684fa |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
import os
from pptx import Presentation
from pptx.util import Inches
from PIL import Image
from utils import remove_all_slides
from logger import LOG # 引入日志模块
def format_text(paragraph, text):
"""
格式化文本,处理加粗内容。假设 ** 包围的文本表示需要加粗。
"""
while '**' in text:
start = text.find('**')
end = text.find('**', start + 2)
if start != -1 and end != -1:
# 添加加粗之前的普通文本
if start > 0:
run = paragraph.add_run()
run.text = text[:start]
# 添加加粗文本
bold_run = paragraph.add_run()
bold_run.text = text[start + 2:end]
bold_run.font.bold = True # 设置加粗
# 处理剩余文本
text = text[end + 2:]
else:
break
# 添加剩余的普通文本
if text:
run = paragraph.add_run()
run.text = text
def insert_image_centered_in_placeholder(new_slide, image_path):
"""
将图片插入到 Slide 中,使其中心与 placeholder 的中心对齐。
如果图片尺寸超过 placeholder,则进行缩小适配。
在插入成功后删除 placeholder。
"""
# 构建图片的绝对路径
image_full_path = os.path.join(os.getcwd(), image_path)
# 检查图片是否存在
if not os.path.exists(image_full_path):
LOG.warning(f"图片路径 '{image_full_path}' 不存在,跳过此图片。")
return
# 打开图片并获取其大小(以像素为单位)
with Image.open(image_full_path) as img:
img_width_px, img_height_px = img.size
# 遍历找到图片的 placeholder(type 18 表示图片 placeholder)
for shape in new_slide.placeholders:
if shape.placeholder_format.type == 18:
placeholder_width = shape.width
placeholder_height = shape.height
placeholder_left = shape.left
placeholder_top = shape.top
# 计算 placeholder 的中心点
placeholder_center_x = placeholder_left + placeholder_width / 2
placeholder_center_y = placeholder_top + placeholder_height / 2
# 图片的宽度和高度转换为 PowerPoint 的单位 (Inches)
img_width = Inches(img_width_px / 96) # 假设图片 DPI 为 96
img_height = Inches(img_height_px / 96)
# 如果图片的宽度或高度超过 placeholder,按比例缩放图片
if img_width > placeholder_width or img_height > placeholder_height:
scale = min(placeholder_width / img_width, placeholder_height / img_height)
img_width *= scale
img_height *= scale
# 计算图片左上角位置,使其中心对准 placeholder 中心
left = placeholder_center_x - img_width / 2
top = placeholder_center_y - img_height / 2
# 插入图片到指定位置并设定缩放后的大小
new_slide.shapes.add_picture(image_full_path, left, top, width=img_width, height=img_height)
LOG.debug(f"图片已插入,并以 placeholder 中心对齐,路径: {image_full_path}")
# 移除占位符
sp = shape._element # 获取占位符的 XML 元素
sp.getparent().remove(sp) # 从父元素中删除
LOG.debug("已删除图片的 placeholder")
break
# 生成 PowerPoint 演示文稿
def generate_presentation(powerpoint_data, template_path: str, output_path: str):
# 检查模板文件是否存在
if not os.path.exists(template_path):
LOG.error(f"模板文件 '{template_path}' 不存在。") # 记录错误日志
raise FileNotFoundError(f"模板文件 '{template_path}' 不存在。")
prs = Presentation(template_path) # 加载 PowerPoint 模板
remove_all_slides(prs) # 清除模板中的所有幻灯片
prs.core_properties.title = powerpoint_data.title # 设置 PowerPoint 的核心标题
# 遍历所有幻灯片数据,生成对应的 PowerPoint 幻灯片
for slide in powerpoint_data.slides:
# 确保布局索引不超出范围,超出则使用默认布局
if slide.layout_id >= len(prs.slide_layouts):
slide_layout = prs.slide_layouts[0]
else:
slide_layout = prs.slide_layouts[slide.layout_id]
new_slide = prs.slides.add_slide(slide_layout) # 添加新的幻灯片
# 设置幻灯片标题
if new_slide.shapes.title:
new_slide.shapes.title.text = slide.content.title
LOG.debug(f"设置幻灯片标题: {slide.content.title}")
# 添加文本内容
for shape in new_slide.shapes:
# 只处理非标题的文本框
if shape.has_text_frame and not shape == new_slide.shapes.title:
text_frame = shape.text_frame
text_frame.clear() # 清除原有内容
# 直接使用第一个段落,不添加新的段落,避免额外空行
first_paragraph = text_frame.paragraphs[0]
# 将要点内容作为项目符号列表添加到文本框中
for point in slide.content.bullet_points:
# 第一个要点覆盖初始段落,其他要点添加新段落
paragraph = first_paragraph if point == slide.content.bullet_points[0] else text_frame.add_paragraph()
paragraph.level = point["level"] # 设置项目符号的级别
format_text(paragraph, point["text"]) # 调用 format_text 方法来处理加粗文本
LOG.debug(f"添加列表项: {paragraph.text},级别: {paragraph.level}")
break
# 插入图片
if slide.content.image_path:
insert_image_centered_in_placeholder(new_slide, slide.content.image_path)
# 保存生成的 PowerPoint 文件
prs.save(output_path)
LOG.info(f"演示文稿已保存到 '{output_path}'")
|