将PPT内的一个组合图形批量导出成图片

本文讲述了作者使用Python和PPTX库尝试自动化处理PPT胸牌设计,通过提取文本框并进行修改,遇到的问题如引用拷贝、背景图片保存、以及转换为图片格式的挑战。最终作者采取了逐个读取和修改原始PPT,然后另存为新文件并转换为图片的策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

近期有一个杂活,需要为活动设计胸牌,需要基于PPT模板,对胸牌中的人名和职务进行替换。为了不想一个个手动操作,想通过python来实现自动化处理。最后发现用的时间比手动操作还要久……

胸牌大致样式如下,是PPT中文本框和图片的组合,需要根据数据,对身份和人名进行替换。
原始模板

基于python PPTX库的操作

由于拿到的是一个.pptx格式,且只需要对其中一个组件进行替换,因此首先想直接使用python基于PPT进行操作。经过浏览,发现PPTX库是一个比较常用的库。在阅读完Python自动化操作PPT看这一篇就够了等相关资料后,发现操作起来难度并不大,于是开始实现。

为了简化操作,我PPT中的其它组件进行组合,只留下需要修改的文本框单独留下。在pptx中,组合的图形的类型为pptx.shapes.group.GroupShape,不包含文本框。所以在遍历组件时通过判断有无文本框即可选中需要进行修改的文本框,然后将文本框中内容进行修改。更多有关pptx的操作可参见python-pptx官方文档

避坑,需要非常注意各个对象的类型末尾有无s,比如slide和slides,groupshape和groupshapes是不一样的。

from pptx import Presentation
from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
from pptx.util import Pt
from pptx.dml.color import RGBColor

ppt = Presentation("运动会.pptx")
firSlide = ppt.slides[0]
shapes = firSlide.shapes

for shape in shapes:
    if shape.has_text_frame:  # 提取文本框并进行修改
        print(shape)
        tf = shape.text_frame
        tf.paragraphs[0].text = "运动员:厉齐马"
        tf.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER  # 对齐方式
        tf.paragraphs[0].font.name = '楷体'  # 字体名称
        tf.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)  # 字体颜色
        tf.paragraphs[0].font.size = Pt(28)  # 字体大小
    else:
        print(shape)

ppt.save("运动会2.pptx")

# 输出为
# <pptx.shapes.group.GroupShape object at 0x000001C146525750> GroupShape,组合
# <pptx.shapes.autoshape.Shape object at 0x000001C146525850>  Shape,为文本框

更改后的图片
在经过上述操作后,完成了修改。得到了新的胸牌,可行性得到了初步验证,于是想通过遍历方式将所有需要调整的内容进行调整,代码如下。

此处有较多bug,由于时间紧迫,我也没有仔细去解决。其一pptx中相关的shape都是引用,拷贝时需要注意。其二是使用copy.deepCopy没法得到背景图片。还望有大佬指导一下。

from pptx import Presentation
from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
from pptx.util import Pt
from pptx.dml.color import RGBColor
import copy

inforList = ["运动员:厉齐马", "裁判员:杜苏芮"]

ppt = Presentation("运动会.pptx")
firSlide = ppt.slides[0]
shapes = firSlide.shapes

for infor in inforList:
    slide = ppt.slides.add_slide(firSlide.slide_layout)
    copyShape = copy.deepcopy(shapes)

    shapeList = []
    for shape in copyShape:
        if shape.has_text_frame:  # 提取文本框并进行修改
            tf = shape.text_frame
            tf.paragraphs[0].text = infor
            tf.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER  # 对齐方式
            tf.paragraphs[0].font.name = '楷体'  # 字体名称
            tf.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)  # 字体颜色
            tf.paragraphs[0].font.size = Pt(28)  # 字体大小
        shapeList.append(shape)
    groundShapes = shapeList[0].shapes
    groundShapes.add_group_shape(shapeList[1:])
    slideShapes = slide.shapes
    slideShapes.add_group_shape([groundShapes.parent])

ppt.save("运动会2.pptx")

错误图片
在报错后,我发现更致命的一点是,pptx库中没有提供将组合保存为图片的相关接口,整个文档中与save有关的只有保存pptx的唯一接口save(file)。

在这两个问题的重叠下,我选择为对于每个需要填写的信息,都从原始pptx文件中进行读取原始数据,再使用python代码进行修改,然后另存为一个新的pptx文件,最后将新的pptx文件转为图片格式的方式,完成转换。这里需要注意的是,为了让最后pptx转出来的图片为我们想要的大小,需要将pptx文件中幻灯片的大小调整为图片大小

在将ppt转换为图片的最后一部,我尝试了多种方法,包括pptx-interface需要下载comtypes库,无法设置分辨率,清晰度欠佳),win32com无法设置分辨率,清晰度欠佳),spire(png,jpg等位图格式可以设置分辨率,但导出png有水印,导出svg可以通过代码定向去掉水印。但是麻烦的地方在于spire的相关函数命名与pptx一样,放在一个文件内容易冲突)。

from pptx import Presentation
from pptx.enum.text import PP_PARAGRAPH_ALIGNMENT
from pptx.util import Pt
from pptx.dml.color import RGBColor
import win32com.client as win32

inforList = ["运动员:厉齐马", "裁判员:杜苏芮"]

for infor in inforList:
    ppt = Presentation("运动会.pptx")
    firSlide = ppt.slides[0]
    shapes = firSlide.shapes
    shapeList = []
    for shape in shapes:
        if shape.has_text_frame:  # 提取文本框并进行修改
            tf = shape.text_frame
            tf.paragraphs[0].text = infor
            tf.paragraphs[0].alignment = PP_PARAGRAPH_ALIGNMENT.CENTER  # 对齐方式
            tf.paragraphs[0].font.name = '楷体'  # 字体名称
            tf.paragraphs[0].font.color.rgb = RGBColor(0, 0, 0)  # 字体颜色
            tf.paragraphs[0].font.size = Pt(28)  # 字体大小
    groundShapes = shapeList[0].shapes
    groundShapes.add_group_shape(shapeList[1:])
    ppt.save("运动会2.pptx")
	
	name = infor[infor.find(":") + 1:]
    fullName = r"fullpath\to\workingDir\运动会2.pptx"
    saveName = r"fullpath\to\workingDir\fig\\" + str(name)
    # pptx-interface
	utils.save_pptx_as_png(png_folder, pptfile, overwrite_folder=True)

    # win32com
    pptClient = win32.Dispatch('PowerPoint.Application')
    pptClient.Visible = 1 # 设置为0表示后台运行,不显示,1则显示
    ppt = pptClient.Presentations.Open(fullName)
    ppt.SaveAs(saveName, 21) # 21为tif格式,18为png格式,17为jpg格式
    pptClient.Quit()


'''
from spire.presentation.common import *
from spire.presentation import *

# 创建一个Presentation对象
presentation = Presentation()
# # 从文件加载名为"输入文档.pptx"的演示文稿数据
presentation.LoadFromFile("运动会2.pptx")
# 启用IsNoteRetained属性以在将演示文稿转换为SVG文件时保留备注内容
presentation.IsNoteRetained = True
# 遍历演示文稿中的每个幻灯片
for i, slide in enumerate(presentation.Slides):
    # 构建输出文件名,格式为"SVG/ToSVG_序号.svg"
    fileName = "SVG/ToSVG_" + str(i) + ".svg"
    # 将当前幻灯片保存为SVG流
    svgStream = slide.SaveToSVG()
    # 将SVG流保存到指定文件名
    svgStream.Save(fileName)

for i, slide in enumerate(presentation.Slides):
    # 构建输出文件名,格式为"Output/ToImage_序号.png"
    fileName = "SVG/ToImage_" + str(i) + ".png"
    # 将每个幻灯片保存为大小为700 * 400像素的PNG图像
    image = slide.SaveAsImageByWH(770, 1125)
    # 将图像保存到指定文件名
    image.Save(fileName)
    # 释放图像资源
    image.Dispose()
# 释放演示文稿资源
presentation.Dispose()
'''

基于python PIL库的操作

除了基于pptx的方法,其实还可以通过将模板中的背景图提取出来,然后使用PIL等工具,加入文本框,实现图片的批量生成。但是基于PIL的方法需要对文本框的位置进行计算和估计,才能确保居中等格式,可参见PIL文本框居中,因此对于不规则的文本,可能会出现排版的问题。

PIL的字体设置,可以去c/windows/fonts中复制相应的ttf文件到相应工作路径

from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont

inforList = ["运动员:厉齐马", "裁判员:杜苏芮", "志愿者:天歌"]

font = ImageFont.truetype("simkai.ttf", 50, encoding="unic")
for infor in inforList:
    img = Image.open("back.png")
    width, height = img.size
    draw = ImageDraw.Draw(img)
    w = draw.textlength(infor, font=font)
    draw.text(((width - w) / 2, 350), infor, fill=(0, 0, 0), font=font)
    name = infor[infor.find(":") + 1:]
    saveName = "./fig/" + name + ".png"
    img.save(saveName)

文本框与文字内容有关

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值