Python实现为PDF大文件批量去除水印

 更新时间:2023年05月23日 09:04:41   作者:力语  
在阅读过程中如果遇到一些带有水印的资料是比较烦心的,而市面上去水印的功能有多要收费且很不方便,那么,如何通过Python来对这类图片水印进行去除呢,本文就来和大家分享一下实现方法吧

导入

在阅读过程中如果遇到一些带有水印的资料是比较烦心的,如下图所示,水印以及类似的内容会影响我们的阅读体验,而市面上去水印的功能有多要收费且很不方便,那么,如何通过Python来对这类图片水印进行去除呢?

适用场景:本教程适合批量去除文件量较大的PDF文档内的图片水印。

使用软件:Python

需安装第三方库:PILfitzpymupdf

pip install PIL
pip install fitz
pip install pymupdf

不说废话,先把代码贴在前面。

from PIL import Image
import fitz
import os
def replace_color(img_path):
    new_color = (255, 255, 255, 255)
    for filename in os.listdir(img_path):
        image = Image.open(os.path.join(img_path, filename))
        new_pixels = [new_color if pixel == (220,220,220) else pixel for pixel in image.getdata()]
        new_image = Image.new(image.mode, image.size)
        new_image.putdata(new_pixels)
        new_image.save(os.path.join(img_path, filename))
def convert_pdf_to_images(img_path,doc):
    for i, page in enumerate(doc):
        pix = page.getPixmap(matrix=fitz.Matrix(2, 2))
        img_output_path = os.path.join(img_path, f"{i+1:04d}.jpg")
        pix.writePNG(img_output_path)
def creat_file(img_path):
    if not os.path.exists(img_path):
        os.makedirs(img_path)
    else:
        for root, dirs, files in os.walk(img_path, topdown=False):
            for name in files:
                os.remove(os.path.join(root, name))
            for name in dirs:
                os.rmdir(os.path.join(root, name))
def convert_images_to_pdf(img_path, output_path):
    image_list = []
    for filename in os.listdir(img_path):
        image_list.append(Image.open(os.path.join(img_path, filename)))
    image_list[0].save(output_path, save_all=True, append_images=image_list[1:])
def delete_watermark(file_path):
    folder_path = os.path.dirname(file_path)
    file_name = os.path.basename(file_path)
    output_path = os.path.join(folder_path, 'new_'+file_name)
    img_path = os.path.join(folder_path, f"img_{os.path.splitext(file_name)[0]}")
    creat_file(img_path)
    convert_pdf_to_images(img_path, doc=fitz.open(file_path))
    replace_color(img_path)
    convert_images_to_pdf(img_path, output_path)
if __name__ == "__main__":
    delete_watermark('E:\...\example.pdf')

正文

为了不影响阅读体验,一般水印都是由灰色或红色等与正文内容明显不同的颜色构成的。因此,要去除此类水印只需要判断出它是哪种颜色,然后将此颜色替换为背景色即可。

以上面图片中的水印为例,我们通过对水印部分进行取色可以看到,水印的 RGB 值为 (128, 130, 133),背景色为白色( RGB为 (255, 255, 255) ),那么我们只需要将 RGB 值为 (128, 130, 133) 的像素值替换为 (255, 255, 255) 即可实现图像水印的去除。

博主使用的取色工具为 Snipaste,也可以用 PS 等其它工具对水印取色。

首先需要将 PDF 中的一页信息提取出来,我们使用的是 fitz 库。

# 将 PDF 文件分解为图片
def convert_pdf_to_images(img_path,doc)
    for i, page in enumerate(doc):
        pix = page.getPixmap(matrix=fitz.Matrix(2, 2))
        img_output_path = os.path.join(img_path, f"{i+1}.jpg")
        pix.writePNG(img_output_path)

然后再对图片中的特定颜色进行替换

def replace_color(pixel, old_color, new_color):
    if pixel in old_color:
        return new_color
    else:
        return pixel
old_color = (128, 130, 133)
new_color = (255, 255, 255) 
# 遍历输入文件夹中的所有.jpg文件并进行颜色替换
for filename in os.listdir(input_folder):
    if filename.endswith('.jpg') or filename.endswith('.png'):
        # 打开图片并获取像素数据
        image = Image.open(os.path.join(input_folder, filename))
        pixels = list(image.getdata())
        # 遍历像素数据并进行颜色替换
        new_pixels = [replace_color(pixel, old_color, new_color) for pixel in pixels]
        # 将修改后的像素数据保存到新文件夹中
        new_image = Image.new(image.mode, image.size)
        new_image.putdata(new_pixels)
        new_image.save(os.path.join(output_folder, filename))

最后再将图片拼接起来则得到去水印后的 PDF

def convert_images_to_pdf(img_path, output_path):
    image_list = []
    for filename in sorted(os.listdir(img_path), key=lambda x: int(x.split('.')[0])):
        image_list.append(Image.open(os.path.join(img_path, filename)))
    image_list[0].save(output_path, save_all=True, append_images=image_list[1:])

将以上三个步骤合并,即可得到我们的最终代码

from PIL import Image
import fitz
import os
def replace_color(img_path):
    new_color = (255, 255, 255, 255)
    for filename in os.listdir(img_path):
        image = Image.open(os.path.join(img_path, filename))
        new_pixels = [new_color if pixel == (220,220,220) else pixel for pixel in image.getdata()]
        new_image = Image.new(image.mode, image.size)
        new_image.putdata(new_pixels)
        new_image.save(os.path.join(img_path, filename))
def convert_pdf_to_images(img_path,doc):
    for i, page in enumerate(doc):
        pix = page.getPixmap(matrix=fitz.Matrix(2, 2))
        img_output_path = os.path.join(img_path, f"{i+1:04d}.jpg")
        pix.writePNG(img_output_path)
def creat_file(img_path):
    if not os.path.exists(img_path):
        os.makedirs(img_path)
    else:
        for root, dirs, files in os.walk(img_path, topdown=False):
            for name in files:
                os.remove(os.path.join(root, name))
            for name in dirs:
                os.rmdir(os.path.join(root, name))
def convert_images_to_pdf(img_path, output_path):
    image_list = []
    for filename in os.listdir(img_path):
        image_list.append(Image.open(os.path.join(img_path, filename)))
    image_list[0].save(output_path, save_all=True, append_images=image_list[1:])
def delete_watermark(file_path):
    folder_path = os.path.dirname(file_path)
    file_name = os.path.basename(file_path)
    output_path = os.path.join(folder_path, 'new_'+file_name)
    img_path = os.path.join(folder_path, f"img_{os.path.splitext(file_name)[0]}")
    creat_file(img_path)
    convert_pdf_to_images(img_path, doc=fitz.open(file_path))
    replace_color(img_path)
    convert_images_to_pdf(img_path, output_path)
if __name__ == "__main__":
    delete_watermark('E:\...\example.pdf')

只需要对水印和背景进行取色,然后更改相应代码即可实现全自动 Python 去水印功能。

由于水印颜色并不总是某一个RGB值,而是一个范围,所以也可以使用 218<pixel[0]<244 and 218<pixel[1]<244 and 218<pixel[2]<244: 替换 pixel == (220,220,220)

上述程序在运行过程中会根据文件名,产生一个"img_[文件名]"文件夹用于存放图片,以及产生一个去除水印后的"new_[文件名].pdf"文件。

若不需要查看单张图片的效果,也可以直接运行如下代码,在等待一段时间后会直接生成去除水印后的 PDF。

import fitz
with fitz.open('example.pdf') as doc:
    for page in doc:
        pix = page.getPixmap(matrix=fitz.Matrix(2, 2))
        pix = pix.applyFunction(lambda r,g,b: (255, 255, 255) if (r,g,b) == (220, 220, 220) else (r,g,b))
        new_page = fitz.new_page(width=pix.width, height=pix.height)
        new_page.insert_image(fitz.Rect(0, 0, pix.width, pix.height), pixmap=pix)
new_doc.save("new_example.pdf")

不过该方法生成的 PDF 文件会远大于原始文件,若是介意这点可继续用前一种方法。关于为什么该方法生成的文件变大这点,笔者目前也不清楚,如果有知道原因的朋友可以留下评论。

对于特别大的文件,可能导致 MemoryError,这时可以尝试先将图片分组,每组图片生成 pdf 文件后,再将多个 pdf 文件合并。

from PyPDF2 import PdfFileMerger
def convert_images_to_pdf2(img_path, pdf_path, output_path, num_group=10):
    image_list = []
    creat_file(pdf_path)
    pdf_file = []
    for i, filename in enumerate(os.listdir(img_path)):
        img = Image.open(os.path.join(img_path, filename))
        image_list.append(img)
        if (i + 1) % num_group == 0:
            split_pdf_path = os.path.join(pdf_path, f"{len(pdf_file)+1:04d}.pdf")
            image_list[0].save(split_pdf_path, save_all=True, append_images=image_list[1:])
            pdf_file.append(split_pdf_path)
            image_list = []
    pdfs = [os.path.join(pdf_path, f) for f in os.listdir(pdf_path)]
    merger = PdfFileMerger()
    for pdf in pdfs:
        merger.append(pdf)
    merger.write(os.path.join(pdf_path, output_path))
    merger.close()

以上就是Python实现为PDF大文件批量去除水印的详细内容,更多关于Python PDF去水印的资料请关注脚本之家其它相关文章!

相关文章

  • python 创建弹出式菜单的实现代码

    python 创建弹出式菜单的实现代码

    这篇文章主要介绍了python 创建弹出式菜单的实现代码的相关资料,需要的朋友可以参考下
    2017-07-07
  • PyQt5根据控件Id获取控件对象的方法

    PyQt5根据控件Id获取控件对象的方法

    今天小编就为大家分享一篇PyQt5根据控件Id获取控件对象的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • Python本地与全局命名空间用法实例

    Python本地与全局命名空间用法实例

    这篇文章主要介绍了Python本地与全局命名空间用法,实例分析了Python命名空间的相关使用技巧,需要的朋友可以参考下
    2015-06-06
  • Python使用进程池并发执行SQL语句的操作代码

    Python使用进程池并发执行SQL语句的操作代码

    Python的进程池是一种并发工具,它允许我们将任务分发给一组工作进程,这些进程可以同时运行并共享一个进程池,本文给大家介绍了Python使用进程池并发执行SQL语句的操作代码,需要的朋友可以参考下
    2024-10-10
  • 使用Python实现广告点击率预测

    使用Python实现广告点击率预测

    广告点击率是指有多少用户点击了您的广告与有多少用户查看了您的广告的比率,本文主要为大家介绍了如何使用Python实现广告点击率预测,感兴趣的小伙伴可以了解下
    2023-10-10
  • Python中torch.norm()用法解析

    Python中torch.norm()用法解析

    本文主要介绍了Python中torch.norm()用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • tensorflow使用神经网络实现mnist分类

    tensorflow使用神经网络实现mnist分类

    这篇文章主要为大家详细介绍了tensorflow使用神经网络实现mnist分类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-09-09
  • Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

    Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版)

    这篇文章主要介绍了Python爬虫实例之2021猫眼票房字体加密反爬策略(粗略版),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-02-02
  • python对象及面向对象技术详解

    python对象及面向对象技术详解

    这篇文章主要介绍了python对象及面向对象技术,结合实例形式详细分析了Python面向对象所涉及的类、对象、方法、属性等概念与使用技巧,需要的朋友可以参考下
    2016-07-07
  • python not关键字实例用法

    python not关键字实例用法

    在本篇文章里小编给大家整理的是一篇关于python not关键字实例用法,有兴趣的朋友们可以学习下。
    2021-04-04

最新评论