程序员文章、书籍推荐和程序员创业信息与资源分享平台

网站首页 > 技术文章 正文

解放双手,利用python自动完成ppt

hfteth 2025-03-24 16:41:16 技术文章 11 ℃

对于样式固定,且需要每日更新的ppt,可以利用python来自动完成,解放双手。这里以每日更新的降水预报图片为例,对脚本进行简单的介绍。

ppt固定格式

通常我们使用NCL绘制pdf格式的图片,单个pdf中包含多张图片。为了将这些图片贴到ppt中,首先需要将pdf的页面转为png格式,再裁去白边。

pdf转png

这一步主要用到了fitz库

import sys, fitz
import os
import datetime
def pyMuPDF_fitz(pdfPath, imagePath):
    # pdfPath为pdf图片文件的完整目录
    # imagePath为输出png图片目录
    startTime_pdf2img = datetime.datetime.now()   #开始时间
    
    print("imagePath="+imagePath)
    pdfDoc = fitz.open(pdfPath)
    for pg in range(pdfDoc.pageCount):
        print("page = {}".format(pg))
        page = pdfDoc[pg]
        rotate = int(-90)
        # 每个尺寸的缩放系数为1.3,这将为我们生成分辨率提高2.6的图像。
        # 此处若是不做设置,默认图片大小为:792X612, dpi=96
        zoom_x = 1.33333333 #(1.33333333-->1056x816)   (2-->1584x1224)
        zoom_y = 1.33333333
        mat = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
        pix = page.getPixmap(matrix=mat, alpha=False)
        
        if not os.path.exists(imagePath):#判断存放图片的文件夹是否存在
            os.makedirs(imagePath) # 若图片文件夹不存在就创建
        
        #将图片写入指定的文件夹内
        pix.writePNG( os.path.join(imagePath, '{}.png'.format(pg)) )

    endTime_pdf2img = datetime.datetime.now()#结束时间
    print('pdf2img时间=',(endTime_pdf2img - startTime_pdf2img).seconds)

切除白边

这一步主要用到了PIL库

from PIL import Image, ImageOps
# 切除图片四周的白边
def crop_margin(img_fileobj, out, padding=(0, 0, 0, 0)):
    # img_fileobj为原始图片完整路径
    # out为输出图片完整路径
    # padding执行四个边界预留的空白大小
    image = Image.open(img_fileobj).convert('RGB')
    ivt_image = ImageOps.invert(image)
    bbox   = ivt_image.getbbox()
    left   = bbox[0] - padding[0]
    top    = bbox[1] - padding[1]
    right  = bbox[2] + padding[2]
    bottom = bbox[3] + padding[3]
    cropped_image = image.crop([left, top, right, bottom])
    cropped_image.save(out)
    return 

接下来是ppt制作部分的介绍,主要使用pptx库,需要加载的内容包括

from pptx import Presentation
from pptx.util import Inches, Pt, Cm
from pptx.enum.text import MSO_ANCHOR,PP_ALIGN

新建空白页

def new_page(prs, SLD_LAYOUT_TITLE_AND_CONTENT = 6):
    #  prs为ppt对象
    #  SLD_LAYOUT_TITLE_AND_CONTENT 为页面样式,编号可以根据实际需求变更
    slide_layout = prs.slide_layouts[SLD_LAYOUT_TITLE_AND_CONTENT]
    slide = prs.slides.add_slide(slide_layout)
    return

prs = Presentation()     # 创建ppt
slide = new_page(prs)  # 新建空白页面

页面样式

添加图片

def Add_pic(slide, img, img_left, img_top, img_height):
    #slide为ppt页面对象
    
    img_path = img  #图片完整路径
    left = Cm(img_left)
    top = Cm(img_top)
    pic = slide.shapes.add_picture(img_path, left, top, height=Cm(img_height))

图片的相关参数,可以先手动贴一张图到ppt中,右键打开大小和位置,则可获取相关的大小和位置的参数信息。

图片大小及位置参数

添加文本框

def Add_txt(slide, text, text_left, text_top, text_width, text_height):
    # 预设位置和大小
    left = Cm(text_left)
    top = Cm(text_top)
    width = Cm(text_width)
    height = Cm(text_height)
    # 添加文本框
    txBox = slide.shapes.add_textbox(left, top, width, height)
    tf = txBox.text_frame
    #tf.vertical_anchor = MSO_ANCHOR.MIDDLE
    
    # 文本框中写入文字
    para = tf.add_paragraph()
    para.text = text
    para.alignment = PP_ALIGN.CENTER
    #para.line_spacing = 1.5    # 1.5 倍的行距

    ### 设置字体
    # font = para.font
    # font.name = '微软雅黑'    # 字体类型
    # font.bold = True    # 加粗
    # font.size = Pt(32)    # 大小

与图片参数获取类似,可以现在ppt中手动添加文本框,再获取大小和位置参数

主程序伪代码示意

# @Author: Jiao B.F.
# @Email: 1034745512@qq.com

if __name__ == "__main__":
    prs = Presentation()   # 新建ppt
...
        for i, img in enumerate(imgs):
            slide = new_page(prs)  # 新建空白页面
            print(img)

            valid1 = init + datetime.timedelta(hours = i*acc)
            valid2 = init + datetime.timedelta(hours = (i+1)*acc)

						# WRF预报
            txt_info = r"{}月{:02d}日{:02d}时-{}月{:02d}日{:02d}时WRF模拟降水(UTC)".format( valid1.month, valid1.day, valid1.hour,
                                                                                        valid2.month, valid2.day, valid2.hour  )
            crop_margin(img, img)  # 切除白边
            Add_pic(slide, img, 6.77, 0.73, 7.92)
						Add_txt(slide, txt_info, 6, 7.84, 13.4, 1.03)
 
            # EC预报
            til = valid2.strftime("%Y-%m-%d_%H_%M_%S")
            ec_img = "ecplt_Single_pcp{}_{}_zoomout.png".format(acc, til)
            ec_full = os.path.join(ec_dir, ec_img)        
            
              
            txt_info = r"{}月{:02d}日{:02d}时-{}月{:02d}日{:02d}时EC预报降水(UTC)".format( valid1.month, valid1.day, valid1.hour,
                                                                                        valid2.month, valid2.day, valid2.hour  )
            crop_margin(ec_full, ec_full) 
            Add_pic(slide, ec_full, 0.43, 9.9, 7.92)
						Add_txt(slide, txt_info, -0.34, 17.01, 13.4, 1.03)            

            # GFS 预报
            valid2_bjt = valid2 + datetime.timedelta(hours=8)
            til = valid2_bjt.strftime("%Y-%m-%d_%H_%M_%S")
            gfs_img = "gfsplt_Single_pcp{}_{}_zoomout.png".format(acc, til)
            gfs_full = os.path.join(gfs_dir, gfs_img)  
            if not os.path.exists(gfs_full): continue      

            txt_info = r"{}月{:02d}日{:02d}时-{}月{:02d}日{:02d}时GFS预报降水(UTC)".format( valid1.month, valid1.day, valid1.hour,
                                                                                        valid2.month, valid2.day, valid2.hour  )
            crop_margin(gfs_full, gfs_full)   
            Add_pic(slide, gfs_full, 13.6, 9.9, 7.92)
						Add_txt(slide, txt_info, 12.29, 17.01, 13.4, 1.03)   
			
   prs.save('test.pptx') # 保存ppt。重复运行脚本默认覆盖,
   # 注意不要在打开test.pptx的时候运行脚本,会碰到权限的问题
最近发表
标签列表