目录

前言:

解析:

remove_pdf() 函数:

pic2pdf() 函数:

clear_file() 函数:

add_watermark(content) 函数:

主程序部分:

引用的库:

逐段分析:(包含我自己做的时候遇到的各种问题)

去水印环节:

添加水印环节:

主循环部分:

源码:

写在最后: 


前言:

题主大一,为了完成信息技术作业,而在网上到处研究学习,完成了一个python代码,能实现去水印和加水印,但是功能非常局限,只能去除最普通的水印,和加普通水印,这是受到库的限制,还有我学术不精

python 盲水印提取 python批量去水印_python 盲水印提取

python 盲水印提取 python批量去水印_搜索_02

python 盲水印提取 python批量去水印_开发语言_03

解析:

以下都是我自己定义的函数,源代码在最后面需要自取,但是注意时间,编写时间2024/3/29,python3.7,库是最新的

remove_pdf() 函数:

  • 这个函数的目的是去除PDF文件中的水印。
  • 它首先通过 fitz.open() 打开PDF文件。
  • 然后遍历PDF的每一页,使用 get_pixmap() 方法获取页面的像素图。
  • 接着,它会遍历像素图中的每一个像素点,并检查该点的RGB值之和是否大于等于576(这里假设水印的颜色较深,RGB值之和较大)。
  • 如果是,它会将该像素点的颜色设置为白色,即 (pixmap.set_pixel(pos[0], pos[1], (255, 255, 255))。
  • 最后,它会将修改后的像素图保存为PNG图片,并打印出相应的完成信息。

pic2pdf() 函数:

  • 这个函数用于将一系列图片文件转换成一个PDF文件。
  • 它首先通过 os.listdir() 获取指定目录下的所有图片文件,并按照文件名前的数字排序。
  • 然后,它会遍历这些图片文件,使用 fitz.open() 打开每一个图片文件,并使用 convert_to_pdf() 方法将图片转换成PDF格式。
  • 接着,它会创建一个新的PDF文件,并将转换后的PDF文件插入到这个新PDF中。
  • 最后,它会保存并关闭这个新PDF文件。

clear_file() 函数:

  • 这个函数用于删除指定文件夹下的所有文件。
  • 它首先检查指定的文件夹是否存在。
  • 如果存在,它会获取该文件夹下的所有文件和子文件夹,并遍历它们。
  • 对于每一个文件,它会使用 os.remove() 方法将其删除,并打印出相应的完成信息。

add_watermark(content) 函数:

  • 这个函数用于给PDF文件添加水印。
  • 它首先通过 fitz.open() 打开PDF文件,并遍历每一页。
  • 对于每一页,它会将页面的像素图保存为PNG图片。
  • 然后,它会调用 add_mark() 函数,将水印添加到这些PNG图片上,并将添加水印后的图片保存回中转文件夹。
  • 注意,add_mark() 函数的具体实现没有在这段代码中给出。

主程序部分:

  • 程序首先提示用户选择一个功能来运行(加水印、去水印或退出)。
  • 然后,它会让用户选择一个中转文件夹,用于存放临时文件。
  • 接着,它会让用户选择一个PDF文件,用于进行水印操作。
  • 最后,它会让用户选择一个输出文件夹,用于存放最终的PDF文件。
  • 用户还可以输入输出文件的名称。
  • 根据用户的选择,程序会调用相应的函数来执行任务。

引用的库:

import time
from itertools import product
from tkinter import filedialog
import fitz
import os
from watermarker.marker import add_mark

这几个库不能少,少一个都用不了,time库引入是为了在每个提示语后留一定时间给使用者看,itertools的这个是为了迭代图片的数值就是像素,一个个获取像素信息,thinker这个库是为了实现选择文件的可视化,因为输入文件路径很麻烦还要退出去复制,很多人甚至不懂,所以就用它跳到Windows的文件管理进行选择,fitz库是用来将图片转换成pdf的一个库,用它可以打开指定图片保存到一个文档中,然后继续插入图片,最后导出成pdf,os库是为了指定文件的路径选择,确保定位到那个文件,最后一个watermarker是添加水印的集成库,好像是简化了那个PIL(Python Imaging Library)。安装所需要的库需要用到指令,这个可以在pycharm的terminal指令台里输入,但我更喜欢使用系统的命令提示符,打开win,搜索cmd就会看到,他们是一样的。

pip install xxxx

例如要安装itertools,就直接输入pip install itertools,这个是内置的库所以不用指令安装,里面也有一些库是本来就自带的如time,math之类的,不过你也可以多尝试,watermaker就是需要安装的

python 盲水印提取 python批量去水印_python 盲水印提取_04

如果已经有了的话就会看到satisfied。你也可以去搜这些库的具体说明,因为你看到的文章或者什么代码之类的编写时间和版本都会天差地别,可能你抄下来一运行就会遇到各种报错,举个例子吧

def pic2pdf():
    pic_dir = midfile_packeage
    pdf = fitz.open()
    img_files = sorted(os.listdir(pic_dir), key=lambda x: int(str(x).split('.')[0]))
    print(img_files)
    for img in img_files:
        print(img)
        imgdoc = fitz.open(pic_dir + "\\" + img)
        pdfbytes = imgdoc.convert_to_pdf()
        imgpdf = fitz.open("pdf", pdfbytes)
        pdf.insert_pdf(imgpdf)
    pdf.save(fr'{output_file}\{name}.pdf')
    pdf.close()
    print('图片已合成pdf')

就这个部分啊,我一开始直接摘下来发现一直报valueerror,找了很久,直到我去这个库的官网看

def pic2pdf():
    pic_dir = input("请输入图片文件夹路径:")
    
    pdf = fitz.open()
    img_files = sorted(os.listdir(pic_dir),key=lambda x:int(str(x).split('.')[0]))
    for img in img_files:
        print(img)
        imgdoc = fitz.open(pic_dir + '/' + img)  
        pdfbytes = imgdoc.convertToPDF()   
        imgpdf = fitz.open("pdf", pdfbytes)
        pdf.insertPDF(imgpdf)       
    pdf.save("d:/demo.pdf")         
    pdf.close()

上面是那个博客抄的源码,发现没有,convertToPDF,和insertPDF这两个代码不同,是因为下面这个是旧版本的库所使用的语法,去官网看看,就找到了这个convert_to _pdf,问题迎刃而解,但是如果你没找到的话,一直耗得筋疲力尽。

python 盲水印提取 python批量去水印_开发语言_05

一开始着手这个作业时,我先去搜索了有没有完整的程序,发现没有,去GitHub上有一些做好的,但是看不到源代码啥的,也看不懂,然后我看到上面这篇文章,我的去水印部分,基本都是借鉴这个人的,他讲的很清晰,原理就是把像素块替换,通过rgb的数值来判断是否为水印,但是他给的数值是三个210,即R:210,G:210,B:210,计算总值,顺便讲一下RGB,数值越大颜色越浅,(255,255,255)就是白色,RGB分别代表三原色,red,green,blue,三原色混合形成所有的颜色,数值大小表示这三个通道分别的颜色深浅。我直接套用他的发现不行,是因为我要改变的那个图片我用ps打开取色(这也是一种方法),看了看RGB,我的是192,还有199的,因为我的那个图片是用word生成的水印,会不一样,所以具体问题具体分析。接着就是把图片合成pdf,用的也是他的方法,但是这样子操作呢,会需要一个地方来存放图片,然后再把图片给合成,所以我做了一个中转文件夹的操作,其实也不用但是你也得找到一个地方放,你可以直接定位到桌面,但是每个人电脑不一样,所以我设置了自己选择一个。

pixmap.pil_save(fr"{midfile_packeage}\{page_num}.png")

看这个,他给每张图片排序设置名字,其实这点挺重要,因为这样子才能保证pdf原本怎么样的页码顺序输出后就还是怎么样的,而且有没有注意到我写多了一个clear_file的函数,这个是为了让他每次执行完程序后中转文件夹的文件全部清除,如果不清除的话,可能会不同文件混杂在一起,组成的pdf就错乱了,所以在去水印和添加水印后都运行一遍这个方法,而且这个删除函数也是有讲究的,因为他其实只有两种功能要么整个一起移除要么移除文件,所以里面又得加一个遍历进行逐个清除。其实也可以不用搞一个中转文件夹,我的意思是可以当场创建,然后用完后进行整个删除,这样子删除的函数就变得简单,这个也是我写完之后才想到的。

import os

# 获取当前脚本所在的文件夹路径
current_directory = os.getcwd()

# 指定要在当前文件夹中创建的新文件夹名称
new_folder_name = 'new_folder'

# 构建完整的新文件夹路径
new_folder_path = os.path.join(current_directory, new_folder_name)

# 创建新文件夹,如果文件夹已存在,不会抛出异常
os.makedirs(new_folder_path, exist_ok=True)

print(f"新文件夹 '{new_folder_name}' 已在当前文件夹中创建。")

还有删除的

import os
import shutil

# 指定要删除的文件夹路径
folder_path = 'path/to/your/folder'

# 删除空文件夹
# 注意:如果文件夹中有文件或其他文件夹,这个方法将会失败。
os.rmdir(folder_path)

# 或者,删除非空文件夹及其所有内容
shutil.rmtree(folder_path)

这个样子的话程序会更加优美

添加水印环节:

我看的是这一篇文章用Python给图片添加水印的3种方法,简单实用

文章介绍了三种不同的方法来实现图片水印的添加,这些方法各具特点,适用于不同的场景和需求。

  1. OpenCV模块:
  • 使用cv2.putText()方法给图片添加文字水印。
  • 该方法提供了丰富的参数,可以调整字体、颜色、位置等,非常适合需要精确控制水印样式的场景。
  1. PIL模块:
  • 使用ImageDraw.Draw.text()方法在图片上添加文本水印。
  • PIL(Python Imaging Library)是一个功能强大的图像处理库,适合进行图像的基本操作和处理。
  1. watermarker库:
  • 使用add_mark()方法添加水印,该方法封装了PIL库的ImageDraw.Draw.text()方法,使得添加水印更加简便。
  • 这个方法支持批量处理图片,适合需要处理大量图片的场景。

文章还提供了每种方法的代码示例,以及添加水印后的效果展示。读者可以根据自己的需求选择合适的方法,并尝试在实际项目中应用。所以我直接使用了最简单的watermarker,他里面还是有许多参数可以设置的这个可以把鼠标移到调用的方法那里就会显示,当然也可以像我上面说的去官网

python 盲水印提取 python批量去水印_python_06

主循环部分:

主循环部分我是用的是

if __name__ == "__main__":

当 Python 脚本被直接运行时,Python 解释器会将内置的特殊变量 __name__ 设置为 "__main__"。因此,if __name__ == "__main__": 后面的代码块只有在该脚本被直接运行时才会执行。

这种做法允许一个脚本既可以作为可执行脚本直接运行,也可以作为模块被其他脚本导入并使用其中的函数、类等定义,而不会执行脚本中的测试代码或示例代码。这对于提高代码的可重用性和组织结构非常有用。

然后我就写了几个获取关键信息的调用,分别将他们赋值到好记的名字里,然后用if实现进入不同模式的判断,然后将一个个模块叠加起来,但是我写的时候很凌乱,将pdf变成图片的这个部分也应该分出来一个模块,这样子就可以像搭积木一样,所以在不断做项目的过程中也会产生很多思考,和反省改进

print('请选择一个中转文件夹')
    time.sleep(1)
    midfile_packeage = filedialog.askdirectory()
    print('请选择pdf文件')
    time.sleep(1)
    pdf_file = filedialog.askopenfilename()
    print('请选择输出文件夹')
    time.sleep(1)
    output_file = filedialog.askdirectory()
    name = input('请输入输出文件名称:')

这里使用的那个time.sleep()来让程序停一秒,让使用者看清楚提示词,很人性化吧,嘻嘻。可视化选择文件我问ai的,一开始得到的就是

pdf_file = filedialog.askopenfilename()

但是后面我发现我要选定文件夹的话这个不行,然后我又搜到了也是这个库里面的

output_file = filedialog.askdirectory()

成功实现可视化选择,但是不知道为什么这个可视化选择弹出的窗口分辨率很低,而且不会自己弹到最前面的窗口,而且还会带着一个tk的小框。

名称和水印内容都是我后面补上去的,当然其实你能看懂代码好像也没必要,我只要在代码里注释就可以了,直接改代码的文字,更加方便,因为反正你都要打开python的解释器来执行

源码:

import time
from itertools import product
from tkinter import filedialog
import fitz
import os
from watermarker.marker import add_mark


def remove_pdf():
    page_num = 0
    pdf = fitz.open(pdf_file)
    for page in pdf:
        pixmap = page.get_pixmap()
        for pos in product(range(pixmap.width), range(pixmap.height)):
            rgb = pixmap.pixel(pos[0], pos[1])
            if (sum(rgb) >= 576):
                pixmap.set_pixel(pos[0], pos[1], (255, 255, 255))
        pixmap.pil_save(fr"{midfile_packeage}\{page_num}.png")
        print(f"第{page_num}水印去除完成")
        page_num = page_num + 1


def pic2pdf():
    pic_dir = midfile_packeage
    pdf = fitz.open()
    img_files = sorted(os.listdir(pic_dir), key=lambda x: int(str(x).split('.')[0]))
    print(img_files)
    for img in img_files:
        print(img)
        imgdoc = fitz.open(pic_dir + "\\" + img)
        pdfbytes = imgdoc.convert_to_pdf()
        imgpdf = fitz.open("pdf", pdfbytes)
        pdf.insert_pdf(imgpdf)
    pdf.save(fr'{output_file}\{name}.pdf')
    pdf.close()
    print('图片已合成pdf')


def clear_file():
    folder_path = fr'{midfile_packeage}'

    # 检查文件夹是否存在
    if os.path.exists(folder_path):
        # 获取文件夹内的所有文件和子文件夹的名称
        entries = os.listdir(folder_path)

        # 遍历所有条目
        for entry in entries:
            # 完整路径构建
            full_path = os.path.join(folder_path, entry)

            # 判断该路径是否是文件
            if os.path.isfile(full_path) or os.path.islink(full_path):
                # 如果是文件,删除文件
                os.remove(full_path)
                print(f"文件 {full_path} 已被删除。")


def add_watermark(content):
    page_num = 0

    pdf = fitz.open(pdf_file)
    for page in pdf:
        pixmap = page.get_pixmap()
        pixmap.save(fr"{midfile_packeage}/{page_num}.png")  # 保存原始图片
        add_mark(file=fr'{midfile_packeage}/{page_num}.png', out=midfile_packeage, mark=f'{content}')  # 添加水印
        page_num = page_num + 1
    pdf.close()


if __name__ == "__main__":
    user_choice = input("Please choose a function to run \n(1:加水印, 2:去水印, or 3:退出): ")
    print('请选择一个中转文件夹')
    time.sleep(1)
    midfile_packeage = filedialog.askdirectory()
    print('请选择pdf文件')
    time.sleep(1)
    pdf_file = filedialog.askopenfilename()
    print('请选择输出文件夹')
    time.sleep(1)
    output_file = filedialog.askdirectory()
    name = input('请输入输出文件名称:')

    if user_choice == "1":
        watermark = input('请输入水印内容:')
        add_watermark(f'{watermark}')
        pic2pdf()
        clear_file()
    elif user_choice == "2":
        remove_pdf()
        pic2pdf()
        clear_file()
    elif user_choice == "3":
        exit()

写在最后: 

本人能力有限,才学习了python一个多月,好多地方都不懂,每次看到大佬们写的代码就特别羡慕,每次去搜索想要实现的代码,也能看到很多种解法,每一种遇到的错误也有人会解答,所以我也希望能奉献出自己的一份力,来完善这个学习研究环境,恳请多多指点,这个代码中还有很多要优化的地方,太冗杂,而且很多不必要的循环,和逻辑,但我不知道如何去流畅的思路写一个项目代码。