製作pdf,
從第1個pdf抓135頁、第2個pdf抓24頁,互相交疊,印成新的pdf檔。
若此5頁之中有關鍵字UHD,則該頁加上浮水印。(最後只有第1、5頁有浮水印)
自己手寫迴圈順序感覺沒問題,
**
可是第5頁會疊印在第1頁。然後原本第5頁的地方變空白。
希望很會跑迴圈的大大可以幫忙看一下。m()m **
import os, PyPDF2
a = "c:\temp\p340use"
os.chdir(a)
print(os.getcwd())
if os.path.exists("p340.pdf"):
os.unlink("p340.pdf")
ps = os.listdir(a)
ps.sort(key=str.lower, reverse=True)
del ps[0] # list erase water.pdf
print(ps)
pr1 = PyPDF2.PdfFileWriter()
pr2 = PyPDF2.PdfFileReader(open('water.pdf', 'rb'))
for m in range(5): # 5 page = 0~4
for n in range(len(ps)): # 2 file = 0~1
if ((m%2== 0)&(n%2==0)): # page135, file1
pr3 =PyPDF2.PdfFileReader(open(ps[n], 'rb'))
i = pr3.getPage(m).extractText()
if 'UHD' in i:
k = pr2.getPage(0) # water.pdf
k.mergePage(pr3.getPage(m))
else:
k = pr3.getPage(m)
pr1.addPage(k)
break
elif ((m%2!=0)&(n%2!=0)): # page24, file2
pr3 = PyPDF2.PdfFileReader(open(ps[n], 'rb'))
pr1.addPage(pr3.getPage(m))
pr1.write(open('p340.pdf', 'wb'))
如果覺得上述流程有能改進、更精簡或更順暢的方式,
也請不吝指導。謝謝。
這段代碼裡面有一些小錯誤和沒必要的操作。在分析代碼之前,先簡述一下需要做的事情:
把兩個 PDF 文件讀入,從每個文件中抓取指定的頁數。
將這些頁數按照一定的順序組合起來,形成一個新的 PDF 文件。
如果第1、5頁包含關鍵字「UHD」,則在這兩頁上增加浮水印。
現在就來一步一步改進這段代碼。
首先,沒必要使用 os 模塊來獲取文件列表,因為 PyPDF2 模塊本身就可以讀取 PDF 文件。改用 PyPDF2 模塊的方法如下:
import PyPDF2
# 讀取文件
file1 = open('file1.pdf', 'rb')
file2 = open('file2.pdf', 'rb')
# 建立 PdfFileReader 對象
reader1 = PyPDF2.PdfFileReader(file1)
reader2 = PyPDF2.PdfFileReader(file2)
接下來,為了抓取每個文件中的指定頁數,需要用到 PyPDF2 模塊中的 getPage() 方法。 getPage() 方法需要一個頁碼作為參數,頁碼是从0開始計算的。因此,要抓取第1個文件中第135頁,可以這樣寫:
# 取出第135頁
page135 = reader1.getPage(134)
現在,我們已經有了所有需要的頁面,可以按照順序組合它們。 PyPDF2 模塊提供了 PdfFileWriter 物件來寫入 PDF 文件,我們可以用它來實現這個功能。
假設我們把第1個文件中的第135頁和第5個文件中的第24頁組合在一起,可以這樣寫:
# 建立 PdfFileWriter 對象
writer = PyPDF2.PdfFileWriter()
# 將第135頁和第24頁加入 writer 對象中
writer.addPage(page135)
writer.addPage(page24)
# 寫入文件
output = open('output.pdf', 'wb')
writer.write(output)
接下來,我們要在第1、5頁上加上浮水印。 PyPDF2 模塊提供了 mergePage() 方法來把一個頁面合并到另一個頁面上。我們需要用這個方法來完成這個任務。
首先,我們需要把浮水印加到一個獨立的頁面上。可以這樣寫:
# 讀入浮水印文件
watermark = open('watermark.pdf', 'rb')
# 建立 PdfFileReader 對象
watermark_reader = PyPDF2.PdfFileReader(watermark)
# 取出浮水印頁面
watermark_page = watermark_reader.getPage(0)
然後,我們就可以把浮水印頁面合并到第1、5頁上了。假設第1頁是 page1,第5頁是 page5,可以這樣寫:
# 合并浮水印
page1.mergePage(watermark_page)
page5.mergePage(watermark_page)
最後,我們需要檢查每一頁是否包含關鍵字「UHD」,如果包含,則加上浮水印。這可以通過 PyPDF2 模塊中的 extractText() 方法來實現。
假設我們想檢查 page1 這一頁是否包含「UHD」,可以這樣寫:
# 檢查 page1 是否包含「UHD」
text = page1.extractText()
if 'UHD' in text:
page1.mergePage(watermark_page)
最後整合起來是:
import PyPDF2
# 讀取文件
file1 = open('file1.pdf', 'rb')
file2 = open('file2.pdf', 'rb')
# 建立 PdfFileReader 對象
reader1 = PyPDF2.PdfFileReader(file1)
reader2 = PyPDF2.PdfFileReader(file2)
# 取出第135頁和第24頁
page135 = reader1.getPage(134)
page24 = reader2.getPage(23)
# 讀入浮水印文件
watermark = open('watermark.pdf', 'rb')
# 建立 PdfFileReader 對象
watermark_reader = PyPDF2.PdfFileReader(watermark)
# 取出浮水印頁面
watermark_page = watermark_reader.getPage(0)
# 建立 PdfFileWriter 對象
writer = PyPDF2.PdfFileWriter()
# 將第135頁和第24頁加入 writer 對象中
writer.addPage(page135)
writer.addPage(page24)
# 檢查 page1 是否包含「UHD」,如果包含,則加上浮水印
text = page1.extractText()
if 'UHD' in text:
page1.mergePage(watermark_page)
# 檢查 page5 是否包含「UHD」,如果包含,則加上浮水印
text = page5.extractText()
if 'UHD' in text:
page5.mergePage(watermark_page)
# 寫入文件
output = open('output.pdf', 'wb')
writer.write(output)
需要注意的是,上面的代碼假設我們只需要第1、5頁,如果需要更多的頁面,則需要使用迴圈來把所有頁面都加入 writer 對象中。
另外,上面的代碼假設需要把第1個文件中的第135頁和第2個文件中的第24頁組合起來。如果需要把其他頁面組合起來,則需要修改代碼以適應不同的情況。
希望這些指導能幫助你完成你的任務。
程式碼的檔案操作主要採用 pathlib
。
程式碼的 PyPDF2 採用 官方文件 的命名與方法取代舊的語法。
另,open()
請搭配close()
或with
語句以控管及降低風險。
## Tested @ Python==3.8.15; pypdf2==2.11.2;
import pathlib, PyPDF2
showDebug = True ## 除錯用:顯示處理細節;
## showDebug 設為 True 時:
## 1. 顯示浮水印外的待處理的檔案
## 2. P[]F[]W :顯示處理頁(P),插入的檔案(F),覆上浮水印(W?)
folderBase = pathlib.Path(r'c:\temp\p340use')
fileOut = folderBase.joinpath('p340.pdf')
fileInW = folderBase.joinpath('water.pdf')
##
if(fileOut.exists()): fileOut.unlink()
filesAll = sorted( \
[x for x in folderBase.glob('*.pdf') if x.is_file()], \
key = lambda path: str(path).lower(), \
reverse = True \
) ## 左斜線(\)可不用;這只是我習慣~
filesFi = [i for i in filesAll if fileInW.name not in i.name]
if(showDebug):
for i in filesFi: print(i.name)
##
readerW = PyPDF2.PdfReader(fileInW)
## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
readers = [PyPDF2.PdfReader(i) for i in filesFi]
writer = PyPDF2.PdfWriter()
for m in range(5):
n = m % len(readers)
if(showDebug): print('P['+str(m)+']F['+str(filesFi[n].name)+']',end='')
## 因為你的程式裡,來源檔案的頁數索引是用 m ,所以這裡我照你的用 m ;
## 如要用第 135、24 頁,請自行修訂(例如判斷式或[檔案-頁數]對應法等)。
writer.add_page(readers[n].pages[m])
pText = readers[n].pages[m].extract_text()
if 'UHD' in pText:
if(showDebug): print('W',end='')
writer.pages[m].merge_page(readerW.pages[0])
if(showDebug): print('')
with open(fileOut, "wb") as fp:
writer.write(fp)
##
Update:
使用:
## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
readers = [PyPDF2.PdfReader(i) for i in filesFi]
取代:
readers = [] ## 用以先載入以降低迴圈時的負載。(不過還是要看 PyPDF2 的運作方式)
for i in filesFi: readers.append(PyPDF2.PdfReader(i))
兩個語法各有用處;因為看到 froce 的回答,回頭看了下,若是初始化的話,用新的感覺比較好。
您的寫法比較複雜,
用了一些我還沒學到的部份。
例如以pathlib取代os。
(那os去哪啦???)
open()、close()、with還沒學到,這些的分開列式能降低風險,
我也會記下來了的,很感謝。
我很喜歡您的寫法,
因為它告訴我,「未來」也許能學到用這些方式來撰寫代碼。
os
一直都在,只是某天注意到 pathlib
後,現在我就偏好用 pathlib
做檔案操作了。 這裡有功能對照表。
檔案操作的open()
、close()
牽涉到檔案系統的占用與鎖定等;只怕發生特殊狀況搞掛檔案系統,不然一般的異常其實都是小問題。open()
+with
等 context manager 相關語法就真的方便好用了;但怕會慣壞或搞亂一堆人就是了~
謝謝您。:D
python 3.10 以上
import PyPDF2
def genPDFByCustom(pdf1, pdf2, watermark, index):
tempPage = None
if index%2 == 0:
tempPage = pdf1.getPage(index)
if index == 0 or index == 4:
if 'UHD' in tempPage.extractText():
tempPage.mergePage(watermark)
else:
tempPage = pdf2.getPage(index)
return tempPage
with (
open('file1.pdf', 'rb') as file1,
open('file2.pdf', 'rb') as file2,
open('watermark.pdf', 'rb') as watermarkfile,
open('output.pdf', 'wb') as output
):
pdf1 = PyPDF2.PdfFileReader(file1)
pdf2 = PyPDF2.PdfFileReader(file2)
watermarkPDF = PyPDF2.PdfFileReader(watermarkfile)
watermark = watermarkPDF.getPage(0)
writer = PyPDF2.PdfFileWriter()
pdfPages = [genPDFByCustom(pdf1, pdf2, watermark, i) for i in range(5)]
for p in pdfPages:
writer.addPage(p)
writer.write(output)