python-pdf的去水印操作

本文介绍如何使用Python编程实现PDF文件的去水印功能,通过PyMuPDF和Pillow库将PDF转图片、去水印并直接保存回PDF,避免了传统方法中的中间转换步骤。重点讨论了原理、代码实现和潜在限制,以及参考的技术资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

为什么做出这个?

  • 就是有时候从网上下载的资料中的pdf有水印,看着不舒服。
  • 比如说我从网上下载的试卷,然后去打印店打印,打印之后水印看着很不舒服,而去水印wps要会员,而我是一个程序员,为什么不做一个呢,何乐而不为。
  • 虽然最后是做出来的,但是还是有限制

原理

  • 把pdf转化为图片,然后将图片去水印
  • 图片去水印,是又条件限制的,必须水印的颜色和pdf中文字的颜色的rgb相差很大,然后把水印的颜色改变成背景颜色。

特色

  • 网上很多和我类似的原理去水印,但是都是先pdf转化为图片存起来,然后图片去水印之后,然后把图片拼接成pdf。
  • 而我就不需要中间步骤,我是直接输入pdf文件,输出pdf文件

成果

安装依赖

  • Image
pip install pillow
  • fitz
pip install PyMuPDF

代码

  • 程序处理pdf需要的时间比较久(因为处理的是像素点),可以先用页数少的pdf进行测试之后再去页数比较多的pdf。
from PIL import Image
import os
import io
import fitz
import time


def single_pdf_clearwater(pdf_path: str):
    pdf = fitz.open(pdf_path)   # 打开pdf目录
    pdf_img = fitz.open()       # 打开空文件,用来存图片pdf
    for page_inf in pdf:
        definition = 3    # 清晰度,感觉输出的pdf不够清晰,可以调大,调大,文件大小也会变大
        matrix = fitz.Matrix(definition, definition)
        img = page_inf.get_pixmap(matrix=matrix).tobytes()
        img = Image.open(io.BytesIO(img))
        width, height = img.size
        for i in range(width):
            for j in range(height):
                if sum(img.getpixel((i, j))) > 600: # 这里的600你需要根据自己的水印的颜色进行更改。
                    img.putpixel((i, j), (255, 255, 255))
        img = img.tobytes()  # = img = np.asarray(img);img = bytearray(img)
        img = fitz.Pixmap(fitz.csRGB, width, height, img)
        img = img.tobytes()
        img = fitz.open("png", img)
        pdf_bytes = img.convert_to_pdf()
        pdf_img.insert_pdf(fitz.open("pdf", pdf_bytes))
    if not os.path.exists("output"):
        os.makedirs("output")  # 处理好的pdf存入了output目录下
    pdf_img.save("output/去水印pdf_" + os.path.basename(pdf_path))


def group_pdf_clearwater(path_array: list[str]):
    print("************去水印时间比较久***********")
    for pdf_path in path_array:
        print(pdf_path, "去水印中...")
        single_pdf_clearwater(pdf_path)
    print("完成")


def folder_pdf_files(folder: str) -> list[str]:  # 一个文件夹里面有多少pdf文件
    file_list = []
    for a, b, c in os.walk(folder):
        for filename in c:
            if filename[-3:].lower() == 'pdf':
                file_path = os.path.join(a, filename)
                file_list.append(file_path)
    print(folder, ": 有", len(file_list), "个pdf文件")
    return file_list


if __name__ == '__main__':
    time_start = time.time()
    path_list = folder_pdf_files("pdf的目录")
    group_pdf_clearwater(path_list)
    time_end = time.time()
    print("程序运行时间:", round(time_end - time_start, 2), "秒")

想法

  • 虽然最后实现了,但是有限制
  • 为了去除保存图片后取图片的中间步骤,我查阅了很多的文献和资料,后面发现只有我最不想看的英文文档才找到了问题的答案。我就感觉,比较偏的点,只有英文文献才有。
  • 因为限制,我在想是不是可以和python-普通pdf的添加水印逆向思维进行操作,就是把水印图层直接取出来。
  • 如果处理的pdf文件比较多,并且页数很多,程序运行就要很久,我都感觉像深度学习了🤣。

参考文献

### 使用 Python 去除 PDF 文件中的水印 #### 安装所需库 为了去除 PDF 中的水印,需要安装 `PyMuPDF` (也称为 `fitz`) 和其他辅助库。可以通过 pip 来完成安装: ```bash pip install pymupdf opencv-python numpy ``` #### 加载并显示 PDF 页面图像 首先加载 PDF 文档,并将其转换为图像以便后续处理。 ```python import fitz # PyMuPDF import cv2 import numpy as np def pdf_page_to_image(pdf_path, page_num=0): doc = fitz.open(pdf_path) page = doc.load_page(page_num) pix = page.get_pixmap() img = np.frombuffer(pix.samples, dtype=np.uint8).reshape(pix.h, pix.w, -1) return img ``` 此函数会打开指定路径下的 PDF 文件,并提取第一页的内容作为 NumPy 数组返回[^1]。 #### 图像预处理与二值化 对于大多数情况来说,简单的阈值法能够有效地分离前景文字和背景水印。 ```python def preprocess_image(image): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _, thresh = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY_INV) kernel = np.ones((3, 3), np.uint8) cleaned = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel) return cleaned ``` 这段代码先将彩色图片转成灰度图,再设定合适的阈值得到黑白二值图;最后使用形态学闭运算填充可能存在的断开字符[^3]。 #### 移除水印区域 基于上述得到的结果,定位并擦除疑似水印部分。 ```python def remove_watermark_from_image(cleaned_img, original_img): contours, _ = cv2.findContours(cleaned_img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) mask = np.zeros_like(original_img[:, :, 0]) for contour in contours: area = cv2.contourArea(contour) if 100 < area < 5000: # 调整这个范围以匹配实际水印大小 x, y, w, h = cv2.boundingRect(contour) cv2.rectangle(mask, (x, y), (x+w, y+h), 255, thickness=cv2.FILLED) result = cv2.inpaint(original_img, mask.astype(np.uint8), inpaintRadius=3, flags=cv2.INPAINT_TELEA) return result ``` 这里定义了一个掩模来标记要修复的位置,之后调用 OpenCV 的修补算法替换掉被遮挡的地方。 #### 将修改后的页面保存回 PDF 当所有页都经过处理后,需把它们重新组合成一个新的无水印版本。 ```python def save_images_as_pdf(images_list, output_filename='output.pdf'): doc = fitz.open() for image_array in images_list: height, width, channels = image_array.shape pixmap = fitz.Pixmap(fitz.csRGB, width, height, False) data = cv2.imencode('.png', image_array)[1].tobytes() pixmap.set_rect(0, 0, width, height, data) page = doc.new_page(width=width, height=height) page.insert_image(page.rect, stream=pixmap.tobytes()) doc.save(output_filename) ``` 该方法遍历给定列表里的每一幅图像数据,创建对应的 PDF 页面并将最终结果存储至磁盘上。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KjPrime

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值