本地首先需要 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')