python-pptx将多个ppt文件按照给定模板ppt格式整合(亲测有效)

from pptx import Presentation

from pptx.enum.shapes import MSO_SHAPE_TYPE

pr = Presentation('周彤.pptx')

for slide in pr.slides:

for shape in slide.shapes:

if shape.shape_type==MSO_SHAPE_TYPE.TEXT_BOX:

print(shape.text_frame.font.name,end='\n\n')

#shape.has_text_frame 判断是否为文本框形状

from pptx import Presentation
from pptx.util import Inches, Cm
from pptx.enum.shapes import MSO_SHAPE_TYPE
import io
from pptx.dml.color import RGBColor
from pptx.util import Pt

import re

def load_template(ppt_template_path):
""" 加载模板 PPT """
prs = Presentation(ppt_template_path)
return prs

def copy_slide_layout(prs, idx):
""" 复制模板中的幻灯片布局 """
slide_layout = prs.slide_layouts[idx]
return slide_layout

def create_slide_from_layout(prs, slide_layout, content, images):
""" 使用布局创建新幻灯片,填充内容和图片,并添加姓名文本框 """
slide = prs.slides.add_slide(slide_layout)
if 'title' in content and 'body' in content:
title = slide.shapes.title
body = slide.placeholders[1] if len(slide.placeholders) > 1 else None
if title:
title.text = content['title']
if body:
tf = body.text_frame
tf.text = content['body']

# 添加图片
left = top = Inches(1)
for image in images:
    slide.shapes.add_picture(image, left, top, width=Inches(2))
    left += Inches(2.5)  # 调整下一张图片的位置

# 移除姓名文本框的添加,因为这个功能在 adjust_text_format_and_position 中已经实现

return slide

def merge_ppts(template_path, single_page_ppts, output_path):
""" 合并多个单页 PPT 到模板中,包括图片,并输出结果 """
prs = load_template(template_path)

# 获取第一个布局作为标准格式
standard_layout = prs.slide_layouts[0]

for ppt in single_page_ppts:
    single_prs = Presentation(ppt)
    if len(single_prs.slides) > 0:
        content = {'title': '', 'body': '', 'name': ''}
        images = []
        slide = single_prs.slides[0]
        
        title_shape = slide.shapes.title
        if title_shape:
            content['title'] = title_shape.text
            # 假设标题就是姓名
            content['name'] = title_shape.text
        
        for shape in slide.shapes:
            if shape.has_text_frame:
                content['body'] += shape.text_frame.text + "\n"
            elif shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
                # 提取图片
                image = shape.image
                image_bytes = image.blob
                images.append(io.BytesIO(image_bytes))
        
        # 使用标准布局创建新幻灯片,包括图片
        new_slide = create_slide_from_layout(prs, standard_layout, content, images)
        
        # 调整文本框格式和位置
        extracted_name = adjust_text_format_and_position(new_slide)
        
        # 调整图片位置和大小
        image_shape = adjust_image_position_and_size(new_slide)
        
        # 如果有图片,再次调整名字文本框的位置
        if image_shape:
            adjust_name_position(new_slide, image_shape, extracted_name)

prs.save(output_path)
print(f"合并的幻灯片(包括图片)已保存到 {output_path}")

def adjust_text_format_and_position(slide):
""" 调整幻灯片文本框格式和位置,并提取姓名 """
max_text_shape = None
max_text_length = 0
extracted_name = "" # 默认为空字符串

for shape in slide.shapes:
    if shape.has_text_frame:
        text_length = len(shape.text_frame.text)
        if text_length > max_text_length:
            max_text_length = text_length
            max_text_shape = shape

if max_text_shape:
    # 尝试从文本中提取姓名
    text = max_text_shape.text_frame.text
    name_match = re.search(r'([\u4e00-\u9fa5]{2,4})', text)
    if name_match:
        extracted_name = name_match.group(1)

    # 设置最大文本框的格式和位置
    max_text_shape.width = Cm(23.26)
    max_text_shape.height = Cm(13.57)
    max_text_shape.left = Cm(9.81)
    max_text_shape.top = Cm(4.31)

    # 设置文本格式
    text_frame = max_text_shape.text_frame
    for paragraph in text_frame.paragraphs:
        paragraph.alignment = 1  # 1 表示左对齐
        paragraph.space_after = Pt(0)  # 设置段落后间距为0
        paragraph.space_before = Pt(0)  # 设置段落前间距为0
        for run in paragraph.runs:
            run.font.name = '微软雅黑'
            run.font.size = Pt(16)
            run.font.color.rgb = RGBColor(255, 255, 255)  # 白色

return extracted_name

def adjust_name_position(slide, image_shape, extracted_name):
""" 调整姓名文本框的位置和样式 """
name_box = None
for shape in slide.shapes:
if shape.has_text_frame and shape.text_frame.text == extracted_name:
name_box = shape
break

if not name_box and extracted_name:
    name_box = slide.shapes.add_textbox(Cm(2.04), Cm(12.61), Cm(5), Cm(1))

if name_box and extracted_name:
    # 使用 round() 函数将浮点数转换为整数
    name_box.left = round(image_shape.left + (image_shape.width - name_box.width) / 2)
    name_box.top = round(image_shape.top + image_shape.height + Cm(0.5))

    name_frame = name_box.text_frame
    name_frame.text = extracted_name
    name_frame.paragraphs[0].alignment = 1  # 居中对齐
    name_frame.paragraphs[0].font.name = '微软雅黑'
    name_frame.paragraphs[0].font.size = Pt(16)
    name_frame.paragraphs[0].font.bold = True
    name_frame.paragraphs[0].font.color.rgb = RGBColor(255, 255, 255)

    if len(extracted_name) == 2:
        name_frame.paragraphs[0].runs[0].font.char_spacing = Pt(16)

def adjust_image_position_and_size(slide):
""" 调整图片位置和大小 """
image_shape = None
for shape in slide.shapes:
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
shape.left = Cm(3.23)
shape.top = Cm(4.46)
shape.width = Cm(5.54)
shape.height = Cm(7.79)
image_shape = shape
break # 只调整第一张图片
return image_shape

获取所有文件文件名

import os
dd = os.listdir('userdetial')

将文件夹路径和文件名称组合加入新的列表中

ss=[]
for i in dd:
rr = 'userdetial\'+i
ss.append(rr)

示例调用

template_path = '1.pptx'
single_page_ppts = ss
output_path = 'merged_output.pptx'
merge_ppts(template_path, single_page_ppts, output_path)

posted @ 2024-09-04 15:58  龙岩龙  阅读(318)  评论(0)    收藏  举报