一句話歸納本文:html
靈感來自於5.15錘子鳥巢發佈會上老羅用閃念膠囊一鍵生成了32張PPT, 原理利用Python-pptx庫,經過編寫模板的方式自動生成批量PPT!python
引言:git
鏘鏘鏘,失蹤人口迴歸,距離上一篇文章已過去14天。不是我偷懶不更新, 主要是轉崗打雜了,很雜那種,天天要處理一堆和開發無關的雜事, 真的是敲碼五分鐘,打雜兩小時...仍是當個單純的開發仔好啊。github
標題沒錯,是第22篇不是21,不用回去翻,沒看漏,第20篇寫的是爬取Gank.io 接口的全部數據到MySQL,第21篇已經定好利用Flask編寫一個API接口, 代碼是實現了,部署還有些問題,因此還沒些,先佔個坑。bash
本節的話,是最近兩天在折騰的一個東西,由於組內正在整在線早教 相關的東西,老師呢,要作不少的課件,可是大部分的內容都是重複的, 可能就圖片會變下,流程可能會變一點,而後就找到我,讓我想一想有沒有辦法 自動生成減小她們的工做量,對,她們想要的就是 自動生成PPT!iview
還記得5.15錘子鳥巢發佈會嗎?不記得?看到這個圖你應該想起什麼了~ide
老羅現場展現了次時代電腦:TNT工做站 ,這裏就不吐槽現場演示時的 各類小失誤和理解萬歲了。直播回顧的視頻能夠到B站看:函數
發佈會直播我是有全程看完的,有個地方吸引了個人注意,在視頻裏69:08處, 老羅利用閃念膠囊直接就生成了32張PPT,給人一種錯覺:佈局
臥槽,好屌,之後連PPT都不用本身作了!
其實否則,若是是細心的觀衆基本會發現一個規律,生成的PPT都是很是簡單 的PPT,一個黑色漸變的大背景,配幾行字,或者再配個圖片,PPT動畫也沒有。 來,來給你個這樣的PPT生成給我看:
這種批量生成簡單PPT的套路,我以爲思路無非這樣:
根據情形,定義幾套模板,而後約定一個規則,根據不一樣的內容調用 不一樣的模板,進行內容填充。
套路知道了,接下來就是看看Python有沒有支持庫了~ 找到兩個pptx和win32com,本節只用前者,由於後者的文檔是真的 看得人頭皮發麻,並且網上的例子很是少...
官方文檔: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中經常使用的建立和管理虛擬環境的工具備:virtualenv和pyvenv, Pycharm默認帶有virtualenv,新建的時候就能夠看到,具體怎麼定製化, 自行百度吧~對了,下載模塊都在**Lib/site-packages
**目錄下!
首先的話,先想一想有哪些模板,羅列下:
而後佈局大概這樣咯:
接着定義一個規則,數據怎麼傳,這裏採用最簡單的套路,寫個txt文件, 每行表明一個PPT,參數經過逗號間隔,因而完整的PPT對應這樣的txt文件:
經過逗號分割參數,優先判斷是否有圖片,有的話走模板1,3, 其餘再另外判斷。好的,思路有了,接下來開始一步步實現吧。
PS:這裏不去介紹怎麼用,看不懂本身去翻文檔,我也是本身摸索, 有我寫的示例參考,應該以爲很欣慰了。
覺得PPT裏的位置和大小用到的單位都是釐米,須要轉換下
# 釐米轉英寸
def cm_to_in(cm):
return Inches(cm / 2.54)
複製代碼
先是模板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,三個小標題,先減去左右的間隔, 而後三等分,循環動態計算小標題的起始位置。
接下來編寫一個讀取文件內容,調用對應方法的函數,代碼以下
# 讀取配置文件調用模板的方法
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)
複製代碼
運行結果:
批量生成是挺爽的,不過呢,不支持直接生成動畫哦!!! 而後這種簡單的PPT,其實粘貼複製修改圖片的效率可能比起你一個個 模板編寫快一些...不得不說有些雞肋,哦,對哦,這個還支持生成圖表, 怎麼整能夠自行查閱官方文檔。
另外的win32com的庫,貌似功能更增強大,可能支持動畫吧,可是文檔是 真的難啃,就沒有深刻去研究了,有興趣能夠本身去折騰折騰。附上用 win32com這個庫時遇到的問題的解決方法:
pip install pypiwin32
複製代碼
微軟官網有,不過看到腦袋痛,介紹個工具: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,驗證信息裏包含: Python,python,py,Py,加羣,交易,屁眼 中的一個關鍵詞便可經過;
驗證經過後回覆 加羣 便可得到加羣連接(不要把機器人玩壞了!!!)~~~ 歡迎各類像我同樣的Py初學者,Py大神加入,一塊兒愉快地交流學♂習,van♂轉py。