使用 python-pptx 完成 ppt 页面的复制

发布于:2025-08-15 ⋅ 阅读:(14) ⋅ 点赞:(0)

本地首先需要 pip install python-pptx
在使用 python-pptx 进行页面复制时,主要需要考虑对图片文件的处理,尤其是处于分组中的图片处理

import copy
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx import Presentation

namespaces = {
    'p': 'http://schemas.openxmlformats.org/presentationml/2006/main',
    'p14': 'http://schemas.microsoft.com/office/powerpoint/2010/main',
    'a': 'http://schemas.openxmlformats.org/drawingml/2006/main',
    'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
}

def duplicate_slide(pres_source, pres_dest, index):
    # 获取要复制的模板幻灯片
    template = pres_source.slides[index]
    layout = template.slide_layout

    # 创建新幻灯片
    copied_slide = pres_dest.slides.add_slide(layout)

    # 如果背景是单独的
    if not template.follow_master_background:
        copied_slide.background._element = copy.deepcopy(template.background._element)

    # 再处理 placeholders
    for placeholder in template.placeholders:

        o_text_frame = placeholder.text_frame._element
        idx = placeholder._element.ph_idx
        n_text_frame = copied_slide.placeholders[idx].text_frame._element

        copied_slide.placeholders[idx]._element.replace(n_text_frame, copy.deepcopy(o_text_frame))

    # 逐步处理形状
    n_shps = copied_slide.shapes
    for shp in template.shapes:

        if shp.shape_type == MSO_SHAPE_TYPE.PLACEHOLDER:
            continue

        # 复制 shape
        el = shp.element
        el_n = copy.deepcopy(el)
        n_shps._spTree.insert_element_before(el_n)
        n_shp = n_shps[-1]
        
        # 处理图片
        if shp.shape_type == MSO_SHAPE_TYPE.PICTURE:
            # 复制图片
            _create_image_part(n_shps, n_shp, shp)
        # 处理分组下的图片
        elif shp.shape_type == MSO_SHAPE_TYPE.GROUP:
            _create_image_parts(n_shp.shapes, n_shp.shapes, shp.shapes)

    return copied_slide


def _save_temp_img(img):

    name = img.filename
    dpi = img.dpi
    size = img.size
    blob = img.blob
    content_type = img.content_type
    # 保存图片到临时文件
    with open(name, 'wb') as f:
        f.write(blob)

    return name


def _create_image_part(n_shps, n_shp, o_shp):
    # 在新的 shapes 下,把 o_shp 中的图片复制过来

    temp_img_file = _save_temp_img(o_shp.image)
    # 把图片保存,并生成引用 id
    img_part, rId = n_shps.part.get_or_add_image_part(temp_img_file)
    # 引用 id 在 p:blipFill 的 a:blip 中 r:embed 中
    bilp_info = n_shp._element.xpath('./p:blipFill/a:blip')[0]
    # 设置新的值
    bilp_info.set(f'{{{namespaces['r']}}}embed', rId)


def _create_image_parts(self, n_shps, o_shps):
    # 创建图片文件
    
    for shp in n_shps:

        shp_id = shp.shape_id
        o_shp = [ s for s in o_shps if s.shape_id == shp_id][0]

        if shp.shape_type == MSO_SHAPE_TYPE.PICTURE:
            _create_image_part(n_shps, shp, o_shp)

        elif shp.shape_type == MSO_SHAPE_TYPE.GROUP:
            _create_image_parts(shp.shapes, o_shp.shapes)


if __name__ == '__main__':
    p = Presentation('test_origin.pptx')
    pn = Presentation()

    pn.slide_width = p.slide_width
    pn.slide_height = p.slide_height

    snn = duplicate_slide(p, pn, 0)
    snn = duplicate_slide(p, pn, 1)
    snn = duplicate_slide(p, pn, 2)

    pn.save('test_copied.pptx')

网站公告

今日签到

点亮在社区的每一天
去签到