脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|shell|

服务器之家 - 脚本之家 - Python - 使用python去除PDF简单水印的示例

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

2024-03-14 15:56穷儒公羊 Python

最近在下载PDF书籍的时候,发现有些PDF有水印,于是就寻思着能不能用Python去除这些讨厌的水印,PDF主要有两种类型,一种是文字版,另外一种就是扫描版(图片),这个去除水印主要就是针对扫描版的PDF,所以本文介绍了如何使用python去除

前言

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

一、PDF文件

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

二、思路整理

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

1、分割图片

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

pip install PyMuPDF

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

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水印的位置可能不一样),再者就是水印和字混在一起就不好弄了

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

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

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

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

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

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

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

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

pip install pillow

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

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文件可以有其他东西(书签等),所以我们先把原始文件读取进去,在进行替换,代码如下:

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效果如下:

去除水印前:

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

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

去除水印后:

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

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

第二个PDF效果如下:

去除水印前:

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

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

去除水印后:

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

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

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

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

四、代码实现

全部代码如下:

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水印的资料请关注服务器之家其它相关文章!

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

延伸 · 阅读

精彩推荐
  • PythonPython基础学习之简单理解函数

    Python基础学习之简单理解函数

    学了函数才算是能推动python的门了,今天就带大家了解一下函数的相关知识,文中有非常详细的介绍,需要的朋友可以参考下...

    布小禅4752021-11-24
  • Pythonpython实现AES和RSA加解密的方法

    python实现AES和RSA加解密的方法

    这篇文章主要为大家详细介绍了python实现AES和RSA加解密的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    如果的事5542021-06-10
  • Pythonpython使用htmllib分析网页内容的方法

    python使用htmllib分析网页内容的方法

    这篇文章主要介绍了python使用htmllib分析网页内容的方法,涉及Python使用htmllib模块的相关技巧,需要的朋友可以参考下 ...

    work242492020-06-24
  • PythonPycharm连接远程服务器过程图解

    Pycharm连接远程服务器过程图解

    这篇文章主要介绍了Pycharm连接远程服务器过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参...

    杰鑫哥6632021-11-18
  • PythonDjango 如何获取前端发送的头文件详解(推荐)

    Django 如何获取前端发送的头文件详解(推荐)

    这篇文章主要介绍了Django 如何获取前端发送的头文件,先需要导入一个类再通过request.environ来获取,具体操作可查看下文,需要的朋友可以参考下...

    beanxyz5282020-12-02
  • Pythonpython 根据正则表达式提取指定的内容实例详解

    python 根据正则表达式提取指定的内容实例详解

    这篇文章主要介绍了python 根据正则表达式提取指定的内容实例详解的相关资料,需要的朋友可以参考下...

    Python教程网15662020-09-13
  • Pythonpython3翻转字符串里的单词点的实现方法

    python3翻转字符串里的单词点的实现方法

    这篇文章主要介绍了python3翻转字符串里的单词点的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的...

    南岸青栀*10922021-09-30
  • PythonNumPy 数组使用大全

    NumPy 数组使用大全

    这篇文章主要介绍了NumPy 数组使用大全,在本教程中,你将学习如何在 NumPy 数组上以多种方式添加、删除、排序和操作元素。 文中通过示例代码介绍的非...

    疯狂的技术宅10352021-06-20