小豬的Python學習之旅 —— 22.安靜!吵到我用TNT了

一句話歸納本文html

靈感來自於5.15錘子鳥巢發佈會上老羅用閃念膠囊一鍵生成了32張PPT, 原理利用Python-pptx庫,經過編寫模板的方式自動生成批量PPT!python


引言git

鏘鏘鏘,失蹤人口迴歸,距離上一篇文章已過去14天。不是我偷懶不更新, 主要是轉崗打雜了,很雜那種,天天要處理一堆和開發無關的雜事, 真的是敲碼五分鐘,打雜兩小時...仍是當個單純的開發仔好啊。github

標題沒錯,是第22篇不是21,不用回去翻,沒看漏,第20篇寫的是爬取Gank.io 接口的全部數據到MySQL,第21篇已經定好利用Flask編寫一個API接口, 代碼是實現了,部署還有些問題,因此還沒些,先佔個坑。bash

本節的話,是最近兩天在折騰的一個東西,由於組內正在整在線早教 相關的東西,老師呢,要作不少的課件,可是大部分的內容都是重複的, 可能就圖片會變下,流程可能會變一點,而後就找到我,讓我想一想有沒有辦法 自動生成減小她們的工做量,對,她們想要的就是 自動生成PPTiview

還記得5.15錘子鳥巢發佈會嗎?不記得?看到這個圖你應該想起什麼了~ide

老羅現場展現了次時代電腦:TNT工做站 ,這裏就不吐槽現場演示時的 各類小失誤和理解萬歲了。直播回顧的視頻能夠到B站看:函數

515錘子科技鳥巢發佈會全程回顧工具

發佈會直播我是有全程看完的,有個地方吸引了個人注意,在視頻裏69:08處, 老羅利用閃念膠囊直接就生成了32張PPT,給人一種錯覺:佈局

臥槽,好屌,之後連PPT都不用本身作了

其實否則,若是是細心的觀衆基本會發現一個規律,生成的PPT都是很是簡單 的PPT,一個黑色漸變的大背景,配幾行字,或者再配個圖片,PPT動畫也沒有。 來,來給你個這樣的PPT生成給我看:

這種批量生成簡單PPT的套路,我以爲思路無非這樣:

根據情形,定義幾套模板,而後約定一個規則,根據不一樣的內容調用 不一樣的模板,進行內容填充。

套路知道了,接下來就是看看Python有沒有支持庫了~ 找到兩個pptxwin32com,本節只用前者,由於後者的文檔是真的 看得人頭皮發麻,並且網上的例子很是少...


1.python-pptx庫


官方文檔python-pptx.readthedocs.io/en/latest/i… 官方倉庫github.com/scanny/pyth… 安裝庫pip install python-pptx

對了,由於win32com那個庫要調用微軟的PowerPoint,我把電腦重裝回 Win 10了,索性安裝了最新版的PyCharm,而後發現建立的工程和之前 建立的工程結構不同,多了個這樣的東西:

終端運行也變成了:(venv) F:\Python> 這樣,這個就是虛擬環境, 簡單點說就是對開發環境進行隔離,好比你這個項目基於Python 2.x,另外一個項目 基於Python 3.x,或者說着兩個項目裏依賴的同一個模塊用着不一樣的版本,經過 虛擬環境可讓這兩個項目互不干擾,將所需的包安裝到獨立的環境中。

Python中經常使用的建立和管理虛擬環境的工具備:virtualenvpyvenv, Pycharm默認帶有virtualenv,新建的時候就能夠看到,具體怎麼定製化, 自行百度吧~對了,下載模塊都在**Lib/site-packages**目錄下!


2.實現流程分析

首先的話,先想一想有哪些模板,羅列下:

  • 1.只有一張圖片
  • 2.只有一條文字
  • 3.一條文字和一張圖片
  • 4.兩條文字
  • 5.四條文字

而後佈局大概這樣咯:

接着定義一個規則,數據怎麼傳,這裏採用最簡單的套路,寫個txt文件, 每行表明一個PPT,參數經過逗號間隔,因而完整的PPT對應這樣的txt文件:

經過逗號分割參數,優先判斷是否有圖片,有的話走模板1,3, 其餘再另外判斷。好的,思路有了,接下來開始一步步實現吧。


3.代碼實現

PS:這裏不去介紹怎麼用,看不懂本身去翻文檔,我也是本身摸索, 有我寫的示例參考,應該以爲很欣慰了。


1.定義一個釐米轉英寸的方法

覺得PPT裏的位置和大小用到的單位都是釐米,須要轉換下

# 釐米轉英寸
def cm_to_in(cm):
    return Inches(cm / 2.54)
複製代碼

2.編寫模板

先是模板1,傳入Presentation的對象,這個你能夠理解成PPT對象, 調用該對象的**.slides.add_slide()方法添加一張幻燈片,pptx庫爲咱們 提供了八個不同的模板,喜歡的能夠本身一個個試,這裏咱們直接用第七 張空白幻燈片**,下標從0開始,因此是**prs.slide_layouts[6],幻燈片 加了以後,調用Presentation的save(ppt文件名)**函數打開生成的PPT, 而後點擊設置 -> 幻燈片大小 -> 直接選擇16:9或者設置幻燈片大小,好比我 的,這裏的寬度和高度就是咱們幻燈片的大小了,後面填充滿屏的圖片就要 用到這個。

而後調用add_picture函數添加一個滿屏圖片:

slide.shapes.add_picture(ppt_bg_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
複製代碼

而後模板1就寫完了,完成代碼以下:

# 模板1:只有一張圖片
def model_1(prs, pic_path):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(pic_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
    
# 調用:
presentation = Presentation(ppt_file_name)
model_1(presentation, laoluo_bg_path)
    
複製代碼

打開生成的ppt:

喲,成功生成,接着到模板2:

填充滿屏圖片,而後新建一個文本框:

title_box = slide.shapes.add_textbox(cm_to_in(3.89), cm_to_in(5.35), cm_to_in(17.61), cm_to_in(3.59))
複製代碼

再接着添加一個文本域:

paragraph = title_box.text_frame.add_paragraph()
複製代碼

而後就能夠對文本域裏進行文字相關的操做了:

paragraph.text = title  # 設置文本
    paragraph.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE  # 設置垂直方向對齊方式
    paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER # 設置水平方向對齊方式
    paragraph.font.size = Pt(60)    # 設置文本大小,PT表明磅
    paragraph.font.name = '微軟雅黑'    # 設置字體
    paragraph.font.color.rgb = RGBColor(255, 255, 255)  # 設置字體顏色
複製代碼

參數傳遞下,調用這個模板2,查看下生成的效果:

接下來如法炮製剩下的三個模板,主要是難點是控件的位置和寬高設置, 有兩種操做:

最簡單的操做:

隨便填個座標和寬高,運行後打開生成的PPT,自行調整 位置,而後記錄下什麼時候的位置和寬高,而後改代碼。

複雜點的操做:

自行計算,好比模板5,三個小標題,先減去左右的間隔, 而後三等分,循環動態計算小標題的起始位置。


3.配置文件讀取

接下來編寫一個讀取文件內容,調用對應方法的函數,代碼以下

# 讀取配置文件調用模板的方法
def read_rules(prs, filename):
    if os.path.exists(filename):
        with open(filename, 'r+', encoding='utf-8') as f:
            for rule in f:
                word_list = rule.replace('\n', '').split(',')
                if 'png' in rule or 'jpg' in rule:
                    if len(word_list) == 1:
                        model_1(prs, os.path.join(c.res_pictures, word_list[0]))
                    else:
                        model_3(prs, word_list[0], os.path.join(c.res_pictures, word_list[1]))
                else:
                    if len(word_list) == 1:
                        model_2(prs, word_list[0])
                    elif len(word_list) == 2:
                        model_4(prs, word_list[0], word_list[1])
                    elif len(word_list) == 4:
                        model_5(prs, word_list[0], word_list[1], word_list[2], word_list[3])
複製代碼

4.代碼執行

調用配置文件讀取的函數

if __name__ == '__main__':
    t.is_dir_existed(c.outputs_documents_path)
    ppt_existed(ppt_file_name)
    presentation = Presentation(ppt_file_name)
    read_rules(presentation, rules_path)
    presentation.save(ppt_file_name)
複製代碼

運行結果


4.有些東西要說說

批量生成是挺爽的,不過呢,不支持直接生成動畫哦!!! 而後這種簡單的PPT,其實粘貼複製修改圖片的效率可能比起你一個個 模板編寫快一些...不得不說有些雞肋,哦,對哦,這個還支持生成圖表, 怎麼整能夠自行查閱官方文檔。

另外的win32com的庫,貌似功能更增強大,可能支持動畫吧,可是文檔是 真的難啃,就沒有深刻去研究了,有興趣能夠本身去折騰折騰。附上用 win32com這個庫時遇到的問題的解決方法:

  • 1.Python3安裝win32com
pip install pypiwin32
複製代碼
  • 2.哪裏有win32com的文檔

微軟官網有,不過看到腦袋痛,介紹個工具:oleview,網上一搜一堆 不過這個用的時候會遇到一個問題,這裏順帶記錄下筆者win10電腦遇到的 一些狀況:

IVIEWERS.DLL缺失:

網上搜下這個dll文件,下載完把文件複製到Windows/system32, 而後管理員模式打開命令提示符,鍵入:regsvr32 iviewers.dll 註冊這個dll運行庫就能夠了。不過呢,win10 64位這樣的執行是會報錯的:

模塊iviewers.dll可能與您正在運行的Windows版本不兼容,檢查該模塊是否與 regsvr.exe的x86或x64版本兼容

你要作的是把dll文件拷貝到Windows/SysWOW64,而後管理員模式打開命令提示符 cd到這個目錄下,接着執行regsvr32 iviewers.dll便可。

若是出現:對DllRegisterServer的調用失敗,錯誤代碼爲0x80070005 那是UAC的緣故,你沒有以管理員模式打開命令提示符

若是解決了,應該能正常打開,左側招到PowerPoint那項,雙擊打開, 而後呢,這個工具不支持查找,你能夠把內容全選而後複製到如Sublime Text 這樣的代碼查看工具上,ctrl + f 查找關鍵字,而後一步步定位出實現某個 功能須要用到的一些函數。


小結

本節講解了一波利用Python-pptx批量生成N張PPT的套路,不由再一次感嘆 人生苦短,我用Python,最後祝六一兒童節快樂~


參考文獻


附:最終代碼(均可以在:github.com/coder-pig/R… 找到):

import pptx
import config as c
import tools as t
from pptx import Presentation
from pptx.dml.color import RGBColor
from pptx.util import Inches, Pt
from pptx.enum.text import MSO_VERTICAL_ANCHOR, PP_PARAGRAPH_ALIGNMENT
import os

rules_path = os.path.join(c.res_documents, 'ppt_rules.txt')
ppt_bg_path = os.path.join(c.res_pictures, 'ppt_bg.png')
laoluo_bg_path = os.path.join(c.res_pictures, 'laoluo.jpg')
last_bg_path = os.path.join(c.res_pictures, 'last.png')
story_bg_path = os.path.join(c.res_pictures, 'story.png')
ppt_file_name = os.path.join(c.outputs_documents_path, 'result.pptx')


# 釐米轉英寸
def cm_to_in(cm):
    return Inches(cm / 2.54)


# 判斷課件是否存在,不存在的新建一個空白
def ppt_existed(ppt_name):
    if not os.path.exists(ppt_name):
        prs = Presentation()
        prs.slide_height = cm_to_in(14.35)
        prs.slide_width = cm_to_in(25.5)
        prs.save(ppt_name)


# 模板1:只有一張圖片
def model_1(prs, pic_path):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(pic_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))


# 模板2:只有一個標題
def model_2(prs, title):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(ppt_bg_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
    title_box = slide.shapes.add_textbox(cm_to_in(3.89), cm_to_in(5.35), cm_to_in(17.61), cm_to_in(3.59))
    paragraph = title_box.text_frame.add_paragraph()
    paragraph.text = title
    paragraph.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
    paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
    paragraph.font.size = Pt(60)
    paragraph.font.name = '微軟雅黑'
    paragraph.font.color.rgb = RGBColor(255, 255, 255)


# 模板3:有字,有圖片
def model_3(prs, title, pic_path):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(ppt_bg_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
    img = slide.shapes.add_picture(pic_path, cm_to_in(0), cm_to_in(0), height=cm_to_in(11.72))
    img.left = int(prs.slide_width / 2 + (prs.slide_width / 2 - img.width) / 2)
    img.top = int((prs.slide_height - img.height) / 2)
    title_box = slide.shapes.add_textbox(cm_to_in(2), cm_to_in(5.35), int(prs.slide_width / 3), cm_to_in(3.59))
    paragraph = title_box.text_frame.add_paragraph()
    paragraph.text = title
    paragraph.font.size = Pt(44)
    paragraph.font.name = '微軟雅黑'
    paragraph.font.color.rgb = RGBColor(255, 255, 255)


# 模板4:兩行文字,一大一小
def model_4(prs, title, content):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(ppt_bg_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
    # 一級標題
    title_box_1 = slide.shapes.add_textbox(cm_to_in(1.27), cm_to_in(2.04), cm_to_in(22.86), cm_to_in(3.18))
    paragraph_1 = title_box_1.text_frame.add_paragraph()
    paragraph_1.text = title
    paragraph_1.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
    paragraph_1.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
    paragraph_1.font.size = Pt(44)
    paragraph_1.font.name = '微軟雅黑'
    paragraph_1.font.color.rgb = RGBColor(255, 255, 255)
    # 二級標題
    title_box_2 = slide.shapes.add_textbox(cm_to_in(7.46), cm_to_in(6.4), cm_to_in(10.47), cm_to_in(2.39))
    paragraph_2 = title_box_2.text_frame.add_paragraph()
    paragraph_2.text = title
    paragraph_2.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
    paragraph_2.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
    paragraph_2.font.size = Pt(32)
    paragraph_2.font.name = '微軟雅黑'
    paragraph_2.font.color.rgb = RGBColor(255, 255, 255)


# 模板5:一行文字,多個小標題
def model_5(prs, title, *content):
    slide = prs.slides.add_slide(prs.slide_layouts[6])
    slide.shapes.add_picture(ppt_bg_path, cm_to_in(0), cm_to_in(0), cm_to_in(25.4), cm_to_in(14.288))
    title_box_1 = slide.shapes.add_textbox(cm_to_in(1.27), cm_to_in(2.04), cm_to_in(22.86), cm_to_in(3.18))
    paragraph_1 = title_box_1.text_frame.add_paragraph()
    paragraph_1.text = title
    paragraph_1.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
    paragraph_1.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
    paragraph_1.font.size = Pt(44)
    paragraph_1.font.name = '微軟雅黑'
    paragraph_1.font.color.rgb = RGBColor(255, 255, 255)
    # 動態構建小標題
    module_width = (prs.slide_width - cm_to_in(1.27) * 2) / len(content)
    for i in range(0, 3):
        title_box = slide.shapes.add_textbox(cm_to_in(1.27) + i * module_width, cm_to_in(6.4), module_width,
                                             cm_to_in(2.39))
        paragraph = title_box.text_frame.add_paragraph()
        paragraph.text = content[i]
        paragraph.vertical_anchor = MSO_VERTICAL_ANCHOR.MIDDLE
        paragraph.alignment = PP_PARAGRAPH_ALIGNMENT.CENTER
        paragraph.font.size = Pt(32)
        paragraph.font.name = '微軟雅黑'
        paragraph.font.color.rgb = RGBColor(255, 255, 255)


# 讀取配置文件調用模板的方法
def read_rules(prs, filename):
    if os.path.exists(filename):
        with open(filename, 'r+', encoding='utf-8') as f:
            for rule in f:
                word_list = rule.replace('\n', '').split(',')
                if 'png' in rule or 'jpg' in rule:
                    if len(word_list) == 1:
                        model_1(prs, os.path.join(c.res_pictures, word_list[0]))
                    else:
                        model_3(prs, word_list[0], os.path.join(c.res_pictures, word_list[1]))
                else:
                    if len(word_list) == 1:
                        model_2(prs, word_list[0])
                    elif len(word_list) == 2:
                        model_4(prs, word_list[0], word_list[1])
                    elif len(word_list) == 4:
                        model_5(prs, word_list[0], word_list[1], word_list[2], word_list[3])


if __name__ == '__main__':
    t.is_dir_existed(c.outputs_documents_path)
    ppt_existed(ppt_file_name)
    presentation = Presentation(ppt_file_name)
    read_rules(presentation, rules_path)
    presentation.save(ppt_file_name)

複製代碼

來啊,Py交易啊

想加羣一塊兒學習Py的能夠加下,智障機器人小Pig,驗證信息裏包含: PythonpythonpyPy加羣交易屁眼 中的一個關鍵詞便可經過;

驗證經過後回覆 加羣 便可得到加羣連接(不要把機器人玩壞了!!!)~~~ 歡迎各類像我同樣的Py初學者,Py大神加入,一塊兒愉快地交流學♂習,van♂轉py。

相關文章
相關標籤/搜索