使用python去除PDF简单水印的示例

 更新时间:2024年03月13日 10:34:56   作者:穷儒公羊  
最近在下载PDF书籍的时候,发现有些PDF有水印,于是就寻思着能不能用Python去除这些讨厌的水印,PDF主要有两种类型,一种是文字版,另外一种就是扫描版(图片),这个去除水印主要就是针对扫描版的PDF,所以本文介绍了如何使用python去除PDF简单水印,需要的朋友可以参考下

Python客栈送红包、纸质书

前言

最近在下载PDF书籍的时候,发现有些PDF有水印,于是就寻思着能不能用Python去除这些讨厌的水印

一、PDF文件

关于PDF文件,想必大家都很熟悉了,这里就不过多的介绍了。PDF主要有两种类型,一种是文字版,另外一种就是扫描版(图片)。这个去除水印主要就是针对扫描版的PDF

二、思路整理

在开始写代码之前,先捋一下实现的思路

1、分割图片

对于一个PDF文件,我们只需要图片信息就可以了,所以首先需要先提取里边的图片,再把图片存在一个目录下。这里需要用到fitz模块,直接安装即可,如下:

1
pip install PyMuPDF

模块安装完之后,代码就很简单了,只需要注意一下图片按顺序命名即可,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def split_pdf(file_path, out_path):
    """
    切割pdf为图片
    :param file_path: pdf路径
    :param out_path: 输出图片路径
    :return: 输出路径
    """
    pdf = fitz.open(file_path)
    count = 0
    print("##### 开始保存切割图片 #####")
    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、去除水印

分割完图片后,接下来的问题也随之而来了,要如何区分水印和正常图片? 要替换成什么? 先来看第一个问题,如何区分水印

  • 按水印位置
    这个问题,最直观的想法就是根据水印的位置以及水印的大小,进行替换就可以。但是这样存在问题,首先就是不通用(PDF水印的位置可能不一样),再者就是水印和字混在一起就不好弄了

像这种水印,坐标和大小是可以去除的

在这里插入图片描述

像这种字和水印混在一起就难办了

在这里插入图片描述

在这里插入图片描述

  • 按颜色
    我们在观察下水印,发现水印的颜色一般偏亮一点,而字都是偏暗色的(黑色、灰色)。我们可以根据颜色将亮一点的颜色都替换掉。但这种方式也有问题,如果是彩色的,就够呛了

对于第二个问题:要替换成什么? 如果只有简单的颜色(黑白灰等),我们直接把水印替换成白色即可

接下来来看下代码吧,这里需要用到PIL模块,直接安装就行了,如下:

1
pip install pillow

思路有了,代码就简单了,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
def get_image_arr(img):
    """
    获取图片三色数组
    :param img:图片
    :return: 图片编码、三色数组
    """
    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):
    """
    通过矩阵操作颜色替换程序
    @param  img:    图像矩阵
    @param  src_clr:    需要替换的颜色(r,g,b)
    @param  dst_clr:    目标颜色        (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: 蓝色
    :return: 图片
    """
    # 合并通道
    dst_img = np.array([r_img, g_img, b_img], dtype=np.uint8)
    # 将数据转换为图像数据(h,w,c)
    dst_img = dst_img.transpose(1, 2, 0)
    return dst_img
 
 
def replace_pure_color(img, src_color, dst_color):
    """
    通过矩阵操作颜色替换程序(纯色)
    :param img: 图像矩阵
    :param src_color: 需要替换的颜色
    :param dst_color: 目标颜色
    :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、替换图片

保存完去除水印后的图片,接下来只要把他一个个替换进去就行了

由于原始PDF文件可以有其他东西(书签等),所以我们先把原始文件读取进去,在进行替换,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def save_pdf(src_pdf, dest_pdf, file_list):
    """
    生成最终pdf文件
    :param src_pdf: 源文件
    :param dest_pdf: 目标文件
    :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()

三、实现效果

lu完代码,再来看一下效果怎么样,这边用了两个PDF做实验,第一个PDF效果如下:

去除水印前:

在这里插入图片描述

在这里插入图片描述

去除水印后:

在这里插入图片描述

在这里插入图片描述

第二个PDF效果如下:

去除水印前:

在这里插入图片描述

在这里插入图片描述

去除水印后:

在这里插入图片描述

在这里插入图片描述

感觉效果还阔以,哈哈。不过这里有个问题,对于文字logo,查了PyMuPDF文档没找到罒ω罒,像这种

在这里插入图片描述

四、代码实现

全部代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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("##### 开始保存切割图片 #####")
    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):
    """
    获取图片三色数组
    :param img:图片
    :return: 图片编码、三色数组
    """
    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):
    """
    通过矩阵操作颜色替换程序
    @param  img:    图像矩阵
    @param  src_clr:    需要替换的颜色(r,g,b)
    @param  dst_clr:    目标颜色        (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: 蓝色
    :return: 图片
    """
    # 合并通道
    dst_img = np.array([r_img, g_img, b_img], dtype=np.uint8)
    # 将数据转换为图像数据(h,w,c)
    dst_img = dst_img.transpose(1, 2, 0)
    return dst_img
 
 
def replace_pure_color(img, src_color, dst_color):
    """
    通过矩阵操作颜色替换程序(纯色)
    :param img: 图像矩阵
    :param src_color: 需要替换的颜色
    :param dst_color: 目标颜色
    :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: 目标文件
    :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("####### 开始切割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("####### 开始去除水印 #######")
    for img_file in file_list:
        wipe_watermark(img_file, start_color)
    print("####### 去除水印结束 #######")
 
    # 生成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="重构-改善既有代码的设计.pdf", dest_path="b.pdf", start_color=175)

总结

这里实现相对比较简单,只能去除一些纯色图片的PDF。

以上就是使用python去除PDF简单水印的示例的详细内容,更多关于python去除PDF水印的资料请关注脚本之家其它相关文章!

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://blog.csdn.net/weixin_42789334/article/details/123457763

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

  • python中partial()基础用法说明

    python中partial()基础用法说明

    这篇文章主要给大家介绍了关于python中partial()基础用法的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需要的朋友们下面来一起看看吧
    2018-12-12
  • Django中的FBV和CBV用法详解

    Django中的FBV和CBV用法详解

    这篇文章主要介绍了Django中的FBV和CBV用法详解,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-09-09
  • pygame实现贪吃蛇游戏

    pygame实现贪吃蛇游戏

    这篇文章主要为大家详细介绍了pygame实现贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Python Django 添加首页尾页上一页下一页代码实例

    Python Django 添加首页尾页上一页下一页代码实例

    这篇文章主要介绍了Python Django 添加首页尾页上一页下一页代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-08-08
  • Python为人脸照片添加口罩实战

    Python为人脸照片添加口罩实战

    本文主要介绍了Python为人脸照片添加口罩实战,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • python中封包建立过程实例

    python中封包建立过程实例

    在本篇文章里小编给大家分享的是一篇关于python中封包建立过程实例内容,有兴趣的朋友们可以学习参考下。
    2021-02-02
  • 利用 PyCharm 实现本地代码和远端的实时同步功能

    利用 PyCharm 实现本地代码和远端的实时同步功能

    这篇文章主要介绍了利用 PyCharm 实现本地代码和远端的实时同步功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • Python用csv写入文件_消除空余行的方法

    Python用csv写入文件_消除空余行的方法

    今天小编就为大家分享一篇Python用csv写入文件_消除空余行的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-07-07
  • Python round函数的基本用法与实例代码

    Python round函数的基本用法与实例代码

    round()函数是Python中用于对浮点数进行四舍五入的内置函数,这篇文章详细介绍了round()函数的基本用法、参数详解、特殊情况处理以及应用场景,并提供了丰富的示例代码,需要的朋友可以参考下
    2024-11-11
  • Python3.x+pyqtgraph实现数据可视化教程

    Python3.x+pyqtgraph实现数据可视化教程

    这篇文章主要介绍了Python3.x+pyqtgraph实现数据可视化教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03

最新评论