用 Python 去除 PDF 水印,你學會嗎?
今天介紹下用 Python 去除 PDF (圖片)的水印。思路很簡單,代碼也很簡潔。
首先來考慮 Python 如何去除圖片的水印,然后再將思路復用到 PDF 上面。
這張圖片是前幾天整理《數(shù)據(jù)結構和算法》PDF里的一個截圖,帶著公眾號的水印。
從上圖可以明顯看到,為了不影響閱讀正文,水印顏色一般比較淺。因此,我們可以利用顏色差這個特征來去掉水印。即:用 Python 讀取圖片的顏色,并將淺顏色部分變白。
Python 標準庫 PIL 可以獲取圖片的顏色,Python2 是系統(tǒng)自帶的,Python3 需要自己安裝,我用的 Python 3.8,需要執(zhí)行以下命令安裝
- pip install pillow
安裝完成,讀取圖片,并獲取圖片的尺寸(寬度和高度)
- from PIL import Image
- img = Image.open('watermark_pic.png')
- width, height = img.size
進行下一步之前,先簡單介紹下計算機里關于顏色的知識。光學三原色是紅綠藍(RGB),也就是說它們是不可分解的三種基本顏色,其他顏色都可以通過這三種顏色混合而成,三種顏色等比例混合就是白色,沒有光就是黑色。
在計算機中,可以用三個字節(jié)表示 RGB 顏色,1個字節(jié)能表示的最大數(shù)值是 255, 所以,(255, 0, 0)代表紅色,(0, 255, 0)代表綠色,(0, 0, 255)代表藍色。相應地,(255, 255, 255)代表白色,(0, 0, 0)代表黑色。從(0, 0, 0) ~ (255, 255, 255) 之間的任意組合都可以代表一個不同的顏色。
接下來我們可以通過下面代碼讀取圖片的 RGB
- for i in range(width):
- for j in range(height):
- pos = (i, j)
- print(img.getpixel(pos)[:3])
圖片每個位置顏色由四元組表示,前三位分別是 RGB,第四位是 Alpha 通道,我們不需要關心。
有了 RGB ,我們就可以對其修改。
從圖中可以發(fā)現(xiàn),水印的 RGB 是 #d9d9d9,這里是用十六進制表示的,其實就是(217, 217, 217)。
這三個顏色值都越靠近 255,顏色就越淡,當它們都變成 255,也就成了白色。所以只要 RGB 都大于 217 的位置,我們都可以給它填成白色。即:RGB 三位數(shù)之和大于等于 651。
- if sum(img.getpixel(pos)[:3]) >= 651:
- img.putpixel(pos, (255, 255, 255))
完整代碼如下:
- from PIL import Image
- img = Image.open('watermark_pic.png')
- width, height = img.size
- for i in range(width):
- for j in range(height):
- pos = (i, j)
- if sum(img.getpixel(pos)[:3]) >= 651:
- img.putpixel(pos, (255, 255, 255))
- img.save('watermark_removed_pic.png')
有了上面的基礎,去除 PDF 的水印就簡單了,思路是將每頁 PDF 轉成圖片,然后修改水印的 RGB,最后輸出圖片即可。
安裝 pymupdf 庫,用來來操作 PDF
- pip install pymupdf
讀取 PDF,并轉圖片
- import fitz
- doc = fitz.open("數(shù)據(jù)結構和算法手冊@公眾號渡碼.pdf")
- for page in doc:
- pix = page.get_pixmap()
該 PDF 共 480 頁,所以需要遍歷每一頁,并獲取每一頁對應的圖片pix。pix對象類似于我們上面看到的img對象,可以讀取、修改它的 RGB。
page.get_pixmap() 這個操作是不可逆的,即能夠實現(xiàn)從 PDF 到圖片的轉換,但修改圖片 RGB 后無法應用到 PDF 上,只能輸出為圖片。
修改水印 RGB 跟剛才一樣,區(qū)別是這里的 RGB 是一個三元組,沒有 Alpha 通道,代碼如下:
- from itertools import product
- for pos in product(range(pix.width), range(pix.height)):
- if sum(pix.pixel(pos[0], pos[1])) >= 651:
- pix.set_pixel(pos[0], pos[1], (255, 255, 255))
完整代碼如下:
- from itertools import product
- import fitz
- doc = fitz.open("數(shù)據(jù)結構和算法手冊@公眾號渡碼.pdf")
- page_no = 0
- for page in doc:
- pix = page.get_pixmap()
- for pos in product(range(pix.width), range(pix.height)):
- if sum(pix.pixel(pos[0], pos[1])) >= 651:
- pix.set_pixel(pos[0], pos[1], (255, 255, 255))
- pix.pil_save(f"pdf_pics/page_{page_no}.png", dpi=(30000, 30000))
- print(f'第 {page_no} 頁去除完成')
- page_no += 1
這種方案是有缺點的,第一,輸出并非 PDF 格式;第二,輸出的圖片比較模糊,后續(xù)還有待優(yōu)化,最好是能直接修改 PDF。
完整代碼回復關鍵詞 gp,找great-programmer/python/python項目/去除水印目錄。
PDF 源文件在great-programmer/數(shù)據(jù)結構與算法/ 目錄。
本文轉載自微信公眾號「渡碼」,可以通過以下二維碼關注。轉載本文請聯(lián)系渡碼公眾號。