使用python去除PDF簡(jiǎn)單水印的示例
前言
最近在下載PDF書(shū)籍的時(shí)候,發(fā)現(xiàn)有些PDF有水印,于是就尋思著能不能用Python去除這些討厭的水印
一、PDF文件
關(guān)于PDF文件,想必大家都很熟悉了,這里就不過(guò)多的介紹了。PDF主要有兩種類型,一種是文字版,另外一種就是掃描版(圖片)。這個(gè)去除水印主要就是針對(duì)掃描版的PDF
二、思路整理
在開(kāi)始寫(xiě)代碼之前,先捋一下實(shí)現(xiàn)的思路
1、分割圖片
對(duì)于一個(gè)PDF文件,我們只需要圖片信息就可以了,所以首先需要先提取里邊的圖片,再把圖片存在一個(gè)目錄下。這里需要用到fitz模塊,直接安裝即可,如下:
pip install PyMuPDF
模塊安裝完之后,代碼就很簡(jiǎn)單了,只需要注意一下圖片按順序命名即可,如下:
def split_pdf(file_path, out_path):
"""
切割pdf為圖片
:param file_path: pdf路徑
:param out_path: 輸出圖片路徑
:return: 輸出路徑
"""
pdf = fitz.open(file_path)
count = 0
print("##### 開(kāi)始保存切割圖片 #####")
for page in pdf:
image_list = page.get_images()
for img_info in image_list:
pix = fitz.Pixmap(pdf, img_info[0])
pix.save(os.path.join(out_path, '%d.jpg' % count))
count += 1
print("##### 保存切割圖片完畢 #####")
print("##### {0} 包含 {1} 張圖片 #####".format(file_path, count))
return out_path
2、去除水印
分割完圖片后,接下來(lái)的問(wèn)題也隨之而來(lái)了,要如何區(qū)分水印和正常圖片? 要替換成什么? 先來(lái)看第一個(gè)問(wèn)題,如何區(qū)分水印
- 按水印位置
這個(gè)問(wèn)題,最直觀的想法就是根據(jù)水印的位置以及水印的大小,進(jìn)行替換就可以。但是這樣存在問(wèn)題,首先就是不通用(PDF水印的位置可能不一樣),再者就是水印和字混在一起就不好弄了
像這種水印,坐標(biāo)和大小是可以去除的

像這種字和水印混在一起就難辦了


- 按顏色
我們?cè)谟^察下水印,發(fā)現(xiàn)水印的顏色一般偏亮一點(diǎn),而字都是偏暗色的(黑色、灰色)。我們可以根據(jù)顏色將亮一點(diǎn)的顏色都替換掉。但這種方式也有問(wèn)題,如果是彩色的,就夠嗆了
對(duì)于第二個(gè)問(wèn)題:要替換成什么? 如果只有簡(jiǎn)單的顏色(黑白灰等),我們直接把水印替換成白色即可
接下來(lái)來(lái)看下代碼吧,這里需要用到PIL模塊,直接安裝就行了,如下:
pip install pillow
思路有了,代碼就簡(jiǎn)單了,如下:
def get_image_arr(img):
"""
獲取圖片三色數(shù)組
:param img:圖片
:return: 圖片編碼、三色數(shù)組
"""
img_arr = np.asarray(img, dtype=np.double)
# 分離通道
r_img = img_arr[:, :, 0].copy()
g_img = img_arr[:, :, 1].copy()
b_img = img_arr[:, :, 2].copy()
img = r_img * 256 * 256 + g_img * 256 + b_img
return img, r_img, g_img, b_img
def replace_clr_color(img, src_clr, dst_clr):
"""
通過(guò)矩陣操作顏色替換程序
@param img: 圖像矩陣
@param src_clr: 需要替換的顏色(r,g,b)
@param dst_clr: 目標(biāo)顏色 (r,g,b)
@return 替換后的圖像矩陣
"""
img, r_img, g_img, b_img = get_image_arr(img)
src_color = src_clr[0] * 256 * 256 + src_clr[1] * 256 + src_clr[2]
# 索引并替換顏色
r_img[img == src_color] = dst_clr[0]
g_img[img == src_color] = dst_clr[1]
b_img[img == src_color] = dst_clr[2]
return compound_img(r_img, g_img, b_img)
def compound_img(r_img, g_img, b_img):
"""
合并圖片
:param r_img: 紅色
:param g_img: 綠色
:param b_img: 藍(lán)色
:return: 圖片
"""
# 合并通道
dst_img = np.array([r_img, g_img, b_img], dtype=np.uint8)
# 將數(shù)據(jù)轉(zhuǎn)換為圖像數(shù)據(jù)(h,w,c)
dst_img = dst_img.transpose(1, 2, 0)
return dst_img
def replace_pure_color(img, src_color, dst_color):
"""
通過(guò)矩陣操作顏色替換程序(純色)
:param img: 圖像矩陣
:param src_color: 需要替換的顏色
:param dst_color: 目標(biāo)顏色
:return: 圖片
"""
img, r_img, g_img, b_img = get_image_arr(img)
src_color = src_color * 256 * 256 + src_color * 256 + src_color
# 索引并替換顏色
r_img[img >= src_color] = dst_color
g_img[img >= src_color] = dst_color
b_img[img >= src_color] = dst_color
return compound_img(r_img, g_img, b_img)
def wipe_watermark(img_file, start_color):
"""
去除圖片水印
:param start_color: 顏色起始替換位置
:param img_file: 圖片文件
:return:
"""
img = replace_pure_color(Image.open(img_file).convert('RGB'), start_color, 255)
res_img = Image.fromarray(img)
res_img.save(img_file)
3、替換圖片
保存完去除水印后的圖片,接下來(lái)只要把他一個(gè)個(gè)替換進(jìn)去就行了
由于原始PDF文件可以有其他東西(書(shū)簽等),所以我們先把原始文件讀取進(jìn)去,在進(jìn)行替換,代碼如下:
def save_pdf(src_pdf, dest_pdf, file_list):
"""
生成最終pdf文件
:param src_pdf: 源文件
:param dest_pdf: 目標(biāo)文件
:param file_list: 圖片列表
:return:
"""
pdf = fitz.open(src_pdf)
index = 0
try:
for page in pdf:
# 去除超鏈接
for link in page.get_links():
page.delete_link(link)
# 替換圖片
for img in page.get_images():
page._insert_image(filename=file_list[index], _imgname=img[7])
index = index + 1
pdf.save(dest_pdf)
finally:
pdf.close()
三、實(shí)現(xiàn)效果
lu完代碼,再來(lái)看一下效果怎么樣,這邊用了兩個(gè)PDF做實(shí)驗(yàn),第一個(gè)PDF效果如下:
去除水印前:


去除水印后:


第二個(gè)PDF效果如下:
去除水印前:


去除水印后:


感覺(jué)效果還闊以,哈哈。不過(guò)這里有個(gè)問(wèn)題,對(duì)于文字logo,查了PyMuPDF文檔沒(méi)找到罒ω罒,像這種

四、代碼實(shí)現(xiàn)
全部代碼如下:
import os
import fitz
import numpy as np
from PIL import Image
def split_pdf(file_path, out_path):
"""
切割pdf為圖片
:param file_path: pdf路徑
:param out_path: 輸出圖片路徑
:return: 輸出路徑
"""
pdf = fitz.open(file_path)
count = 0
print("##### 開(kāi)始保存切割圖片 #####")
for page in pdf:
image_list = page.get_images()
for img_info in image_list:
pix = fitz.Pixmap(pdf, img_info[0])
pix.save(os.path.join(out_path, '%d.jpg' % count))
count += 1
print("##### 保存切割圖片完畢 #####")
print("##### {0} 包含 {1} 張圖片 #####".format(file_path, count))
return out_path
def get_image_arr(img):
"""
獲取圖片三色數(shù)組
:param img:圖片
:return: 圖片編碼、三色數(shù)組
"""
img_arr = np.asarray(img, dtype=np.double)
# 分離通道
r_img = img_arr[:, :, 0].copy()
g_img = img_arr[:, :, 1].copy()
b_img = img_arr[:, :, 2].copy()
img = r_img * 256 * 256 + g_img * 256 + b_img
return img, r_img, g_img, b_img
def replace_clr_color(img, src_clr, dst_clr):
"""
通過(guò)矩陣操作顏色替換程序
@param img: 圖像矩陣
@param src_clr: 需要替換的顏色(r,g,b)
@param dst_clr: 目標(biāo)顏色 (r,g,b)
@return 替換后的圖像矩陣
"""
img, r_img, g_img, b_img = get_image_arr(img)
src_color = src_clr[0] * 256 * 256 + src_clr[1] * 256 + src_clr[2]
# 索引并替換顏色
r_img[img == src_color] = dst_clr[0]
g_img[img == src_color] = dst_clr[1]
b_img[img == src_color] = dst_clr[2]
return compound_img(r_img, g_img, b_img)
def compound_img(r_img, g_img, b_img):
"""
合并圖片
:param r_img: 紅色
:param g_img: 綠色
:param b_img: 藍(lán)色
:return: 圖片
"""
# 合并通道
dst_img = np.array([r_img, g_img, b_img], dtype=np.uint8)
# 將數(shù)據(jù)轉(zhuǎn)換為圖像數(shù)據(jù)(h,w,c)
dst_img = dst_img.transpose(1, 2, 0)
return dst_img
def replace_pure_color(img, src_color, dst_color):
"""
通過(guò)矩陣操作顏色替換程序(純色)
:param img: 圖像矩陣
:param src_color: 需要替換的顏色
:param dst_color: 目標(biāo)顏色
:return: 圖片
"""
img, r_img, g_img, b_img = get_image_arr(img)
src_color = src_color * 256 * 256 + src_color * 256 + src_color
# 索引并替換顏色
r_img[img >= src_color] = dst_color
g_img[img >= src_color] = dst_color
b_img[img >= src_color] = dst_color
return compound_img(r_img, g_img, b_img)
def list_file(path, suffix=None):
"""
獲取指定目錄下指定后綴文件
:param path: 路徑
:param suffix: 后綴名
:return: 文件集合
"""
file_names = os.listdir(path);
# 獲取文件名
if suffix is not None:
file_names = [file_name for file_name in file_names if file_name.endswith(suffix)]
file_names.sort(key=lambda x: int(x[:(-len(suffix))]))
# 文件名拼接路徑
return [os.path.join(path, file) for file in file_names]
def wipe_watermark(img_file, start_color):
"""
去除圖片水印
:param start_color: 顏色起始替換位置
:param img_file: 圖片文件
:return:
"""
img = replace_pure_color(Image.open(img_file).convert('RGB'), start_color, 255)
res_img = Image.fromarray(img)
res_img.save(img_file)
def save_pdf(src_pdf, dest_pdf, file_list):
"""
生成最終pdf文件
:param src_pdf: 源文件
:param dest_pdf: 目標(biāo)文件
:param file_list: 圖片列表
:return:
"""
pdf = fitz.open(src_pdf)
index = 0
try:
for page in pdf:
# 去除超鏈接
for link in page.get_links():
page.delete_link(link)
# 替換圖片
for img in page.get_images():
page._insert_image(filename=file_list[index], _imgname=img[7])
index = index + 1
pdf.save(dest_pdf)
finally:
pdf.close()
def start(file_path, dest_path, start_color, out_path=r'out'):
if os.path.exists(out_path):
# shutil.rmtree(out_path)
raise FileExistsError('文件夾:{0} 已存在'.format(out_path))
os.mkdir(out_path)
print("####### 開(kāi)始切割pdf:{0} #######".format(file_path))
split_pdf(file_path, out_path)
print("####### 切割pdf完畢:{0} #######".format(file_path))
# 獲取文件名
file_list = list_file(out_path, ".jpg")
print("####### 開(kāi)始去除水印 #######")
for img_file in file_list:
wipe_watermark(img_file, start_color)
print("####### 去除水印結(jié)束 #######")
# 生成pdf
print("####### 生成pdf文件:{0} #######".format(dest_path))
save_pdf(src_pdf=file_path, dest_pdf=dest_path, file_list=file_list)
print("####### 生成pdf文件:{0} 完成 #######".format(dest_path))
# make_pdf(dest_path, file_list)
if __name__ == '__main__':
# replace_pdf(src_pdf="深入剖析TOMCAT.pdf", dest_pdf='a.pdf', file_list=list_file('out', ".jpg"))
# www.TopSage.com
start(file_path="重構(gòu)-改善既有代碼的設(shè)計(jì).pdf", dest_path="b.pdf", start_color=175)
總結(jié)
這里實(shí)現(xiàn)相對(duì)比較簡(jiǎn)單,只能去除一些純色圖片的PDF。
以上就是使用python去除PDF簡(jiǎn)單水印的示例的詳細(xì)內(nèi)容,更多關(guān)于python去除PDF水印的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python matplotlib繪圖實(shí)現(xiàn)刪除重復(fù)冗余圖例的操作
這篇文章主要介紹了python matplotlib繪圖實(shí)現(xiàn)刪除重復(fù)冗余圖例的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
python3代碼中實(shí)現(xiàn)加法重載的實(shí)例
在本篇文章里小編給大家整理的是一篇關(guān)于python3代碼中實(shí)現(xiàn)加法重載的實(shí)例內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2020-12-12
使用TensorFlow創(chuàng)建生成式對(duì)抗網(wǎng)絡(luò)GAN案例
這篇文章主要為大家介紹了使用TensorFlow創(chuàng)建生成式對(duì)抗網(wǎng)絡(luò)GAN案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Python利用Selenium實(shí)現(xiàn)自動(dòng)觀看學(xué)習(xí)通視頻
Selenium是一個(gè)用于Web應(yīng)用程序測(cè)試的工具。Selenium測(cè)試直接運(yùn)行在瀏覽器中,就像真正的用戶在操作一樣。本文主要介紹了利用Selenium實(shí)現(xiàn)自動(dòng)觀看學(xué)習(xí)通視頻,需要的同學(xué)可以參考一下2021-12-12
python操作mysql實(shí)現(xiàn)一個(gè)超市管理系統(tǒng)
超市管理系統(tǒng)有管理員和普通用戶兩條分支,只需掌握Python基礎(chǔ)語(yǔ)法,就可以完成這個(gè)項(xiàng)目,下面這篇文章主要給大家介紹了關(guān)于python操作mysql實(shí)現(xiàn)一個(gè)超市管理系統(tǒng)的相關(guān)資料,需要的朋友可以參考下2022-12-12
python內(nèi)置函數(shù)anext的具體使用
本文主要介紹了python內(nèi)置函數(shù)anext的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
解決項(xiàng)目pycharm能運(yùn)行,在終端卻無(wú)法運(yùn)行的問(wèn)題
今天小編就為大家分享一篇解決項(xiàng)目pycharm能運(yùn)行,在終端卻無(wú)法運(yùn)行的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01
Python替換Excel表格中的空值或指定值的實(shí)現(xiàn)
本文介紹了使用Python的pandas庫(kù)結(jié)合openpyxl來(lái)批量替換Excel表格中的空值或指定值,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2024-12-12

