這次會去學這個套件
還是同事拜託能不能將舊有浮水印,印在現有的PDF文件上
然後關鍵字一下(python pdf watermark),答案就出來了
使用Reportlab搭配pypdf或pdfrw
哇靠,真是萬能的Python,好像沒什麼是搞不定的
再深入研究一下要怎麼做才可以將浮水印的圖與PDF結合
這才發現Reportlab不是單純的將圖檔合併轉成PDF的套件
而是可以獨立產生完整PDF的集合工具,舉凡寫字、畫圖、製表等等
ReportLab裡都有不少的套件可以使用
比想像中的強大非常多
那麼正式開始啦
如前所說套件很多
但我沒有需求做很華麗的PDF
所以主要使用的是pdfgen底下的Canvas(畫布)這個套件
畫布的主要參數有兩個,一個是存檔用,另一個是畫布本身的大小
存檔用的部分,可以僅使用字串,也就是檔名來處理,到時候使用save函數就可以存成檔案
或是使用byteio的套件,將PDF內容轉成binary形態,同樣也是下save函數才會有資料
畫布大小的參數,可以引入lib.pagesizes裡的A3、A4等來處理
不過都是直式的尺寸,要用橫式的,可以靠lib.pagesizes.landscape來轉換
簡易的使用流程如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from reportlab.pdfgen import canvas from reportlab.lib.pagesizes import A4, landscape #PDF的檔案名稱是sample.pdf pdf_name = 'sample.pdf' #pdf的尺寸是A4大小的橫式 pdfsize = landscape(A4) pdf_canvas = canvas.Canvas(pdf_name, pagesize = pdfsize) """ 中間畫圖啊,寫字啊等等 """ #產生pdf頁面 pdf_canvas.showPage() #存檔 pdf_canvas.save() |
主架構如上,再來就中間的畫圖與寫字
不論畫圖或寫字,顏色是很重要的,尤其是畫圖
不指定的話,畫出來就都是黑色,所以先談一下Reportlab的顏色使用
顏色函數主要有兩種形態,Stroke(筆畫)跟Fill(填滿)
依顏色形態與方式再分為CMYK(印刷四色),RGB(光三原色),直接填色跟Gray(灰階填色)
如列出來如下
canvas.setFillColorCMYK(c, m, y, k)
canvas.setStrikeColorCMYK(c, m, y, k)
canvas.setFillColorRGB(r, g, b)
canvas.setStrokeColorRGB(r, g, b)
canvas.setFillColor(acolor)
canvas.setStrokeColor(acolor)
canvas.setFillGray(gray)
canvas.setStrokeGray(gray)
填入acolor的函數,就是我稱為直接填色的部分
可以從lib.colors直接引入pink,red,blue,black等顏色
或是使用Color(r,g,b,alpha)的方式做出想要的顏色
其中r,g, b與alpha(透明)的部分一樣是從0~1的浮點數
alpha=1.0代表不透明,用0就是全透明
指定好顏色,畫出來的東西才顯示得出來
再來先講畫圖能用的函數
畫線的話是
canvas.line(x1,y1,x2,y2)
canvas.lines(linelist)
畫形狀的話有
canvas.grid(xlist, ylist) #網格
canvas.bezier(x1, y1, x2, y2, x3, y3, x4, y4) #貝茲曲線
canvas.arc(x1,y1,x2,y2) #圓弧
canvas.rect(x, y, width, height, stroke=1, fill=0) #方塊
canvas.ellipse(x1,y1, x2,y2, stroke=1, fill=0) #橢圓
canvas.wedge(x1,y1, x2,y2, startAng, extent, stroke=1, fill=0) #圓餅
canvas.circle(x_cen, y_cen, r, stroke=1, fill=0) #圓
canvas.roundRect(x, y, width, height, radius, stroke=1, fill=0)#圓角方塊
詳情的話就不講太多
簡單實作一下,畫個多啦A夢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from reportlab.lib.colors import black, red from reportlab.lib.units import mm #避免畫太小,用mm當單位 pdf_canvas.setLineWidth( 2 ) #因為線太細,變粗一點 pdf_canvas.setFillColorRGB( 0 , 0.6313 , 0.9176 ) #多啦A夢的藍色 pdf_canvas.setStrokeColor(black) #線的黑色 pdf_canvas.circle( 120 * mm, 120 * mm, 50 * mm, stroke = 1 , fill = 1 ) #頭 pdf_canvas.setFillColorRGB( 1 , 1 , 1 ) #填充變白色 pdf_canvas.circle( 120 * mm, 107 * mm, 36 * mm, stroke = 1 , fill = 1 ) #臉 pdf_canvas.circle( 100 * mm, 147 * mm, 13 * mm, stroke = 1 , fill = 1 ) #左眼 pdf_canvas.circle( 140 * mm, 147 * mm, 13 * mm, stroke = 1 , fill = 1 ) #右眼 pdf_canvas.setFillColor(red) #填充變紅色 pdf_canvas.circle( 120 * mm, 135 * mm, 7 * mm, stroke = 1 , fill = 1 ) #鼻 pdf_canvas.wedge( 90 * mm, 75 * mm, 150 * mm, 145 * mm, 0 , - 179 , stroke = 1 , fill = 1 ) #嘴 pdf_canvas.line( 120 * mm, 128 * mm, 120 * mm, 110 * mm) #正中直線 pdf_canvas.line( 110 * mm, 127 * mm, 85 * mm, 132 * mm) #左上鬍 pdf_canvas.line( 110 * mm, 122 * mm, 85 * mm, 122 * mm) #左中鬍 pdf_canvas.line( 110 * mm, 117 * mm, 85 * mm, 112 * mm) #左下鬍 pdf_canvas.line( 130 * mm, 127 * mm, 155 * mm, 132 * mm) #右上鬍 pdf_canvas.line( 130 * mm, 122 * mm, 155 * mm, 122 * mm) #右中鬍 pdf_canvas.line( 130 * mm, 117 * mm, 155 * mm, 112 * mm) #右下鬍 pdf_canvas.bezier( 88 * mm, 140 * mm, 95 * mm, 150 * mm, 105 * mm, 150 * mm, 112 * mm, 140 * mm) #左微笑眼 pdf_canvas.bezier( 128 * mm, 140 * mm, 135 * mm, 150 * mm, 145 * mm, 150 * mm, 152 * mm, 140 * mm) #右微笑眼 |
畫圖大概就這樣
比較需要解說的,大概是那個x,y位置為什麼要乘以mm
簡單地說,就是要讓畫出來的圖案確實等於印刷上的mm
如果不乘上mm呢?
那就會是常用排板軟體上的最小單位,點
根據維基百科上對於點_印刷的說明
https://zh.wikipedia.org/wiki/%E9%BB%9E_(%E5%8D%B0%E5%88%B7)
很清楚說明,1英吋等於72點
換言之1mm = 72 / 2.54 / 10 = 2.834645 點
這從Reportlib本身lib裡units.py這個檔案可以很明顯看到
裡面就是寫
1 2 3 | inch = 72.0 cm = inch / 2.54 mm = cm * 0.1 |
直接print(A4)就會得到(595.2755905511812, 841.8897637795277)這樣的數值
畫圖完了,接下來是寫字
函數是下面這幾個
canvas.drawString(x, y, text)
canvas.drawRightString(x, y, text)
canvas.drawCentredString(x, y, text)
但,要實際使用之前還需要指定字型與大小
canvas.setFont('Times-Roman', 20)
後面的20就像上面所說,是排板軟體定義上的點
就是跟Office裡Word、Excel與Powerpoint裡面字型大小一樣的定義
如果想要縮放成自己想要的尺寸,一樣乘上mm或cm或inch就行了
當然,指定座標X,Y也是如此,跟畫圖一樣
只是文字上,對中文字來說比較麻煩的是,預設並沒有支援中文字型
這時候就需要另一個模組pdfbase裡的pdfmetrics與ttfonts.TTFont
然後指定給字型檔案位置,並註冊到系統裡
實作如下,我們使用標楷體
1 2 3 4 5 6 | from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont pdfmetrics.registerFont(TTFont( 'Kaiu' , 'C:/Windows/Fonts/kaiu.ttf' , subfontIndex = 1 )) # sufontIndex=0 會取到固定間距的「標楷體」 pdf_canvas.setFont( 'Kaiu' , 20 * mm) pdf_canvas.drawString( 50 * mm, 50 * mm, "這就是多啦A夢!" ) |
那就會是預設的黑色
如果是在畫圖後加這段,那就會變成紅色
也就是文字的顏色是靠Fill(填滿)來決定的
以上是單頁的PDF做法,那多頁呢?
這個很簡單,在canvas.showPage()後加入新的內容
再進行canvas.showPage()就是新的一頁了
以上面畫圖跟文字顯示為例
在這兩段中間,多加上canvas.showPage()
就會發現,圖在第一頁,然後文字在第2頁
而在第2頁的文字,顏色會是預設的黑色
也就是showPage()後一切設定重來
最後要記得存檔,執行canvas.save()才會有檔案產生
Reportlab裡的功能不止這些
還有插入圖片,更方便的排板與繪圖功能
我就不一一說明了
在官方的網站上可以下載UserGuide去研究
https://www.reportlab.com/dev/docs/
算寫的蠻詳細的
還是看不太懂的話,稍微跑一下程式碼應該也能理解
有了這套件,對需要產生報表的人非常方便
沒有留言:
張貼留言