功能
首先,这份代码的功能是批量修改pdf文件中的一个固定位置图像,可用于修改水印,或用其他图片覆盖。
缺点:这是用图片覆盖的方式,不能保留覆盖位置的文本内容,不能去除复杂水印。
整体代码
import os
import fitz # PyMuPDF
import logging
import tkinter as tk
from tkinter import simpledialog, filedialog, messagebox
from tkinter import PhotoImage
# 配置日志记录
logging.basicConfig(filename='process_pdfs.log', level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s')
def convert_color_to_range(color):
return tuple(c / 255.0 for c in color)
def remove_watermark_from_pdf(input_pdf, output_pdf, rect, image_path=None, color=(255, 255, 255)):
try:
doc = fitz.open(input_pdf)
for page_num in range(len(doc)):
page = doc.load_page(page_num)
shape = page.new_shape()
if image_path:
# 插入图片,并调整大小以适应指定的矩形区域
img = fitz.open(image_path)
img_rect = fitz.Rect(rect) # 创建一个与矩形区域大小相同的 Rect 对象
page.insert_image(img_rect, filename=image_path, keep_proportion=False)
else:
# 否则覆盖区域颜色
if shape is None:
raise ValueError("Shape object creation failed")
shape.draw_rect(rect)
color_converted = convert_color_to_range(color)
shape.finish(color=color_converted, fill=color_converted)
shape.commit()
doc.save(output_pdf, deflate=True)
logging.info(f"Processed {input_pdf} and saved to {output_pdf}")
except Exception as e:
logging.error(f"Failed to process {input_pdf}: {e}")
def process_pdfs_in_folder(input_folder, output_folder, rect, image_path=None, color=(255, 255, 255)):
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for filename in os.listdir(input_folder):
if filename.lower().endswith('.pdf'):
input_pdf = os.path.join(input_folder, filename)
output_pdf = os.path.join(output_folder, f"processed_{filename}")
logging.info(f"Processing {input_pdf}...")
remove_watermark_from_pdf(input_pdf, output_pdf, rect, image_path, color)
logging.info(f"Saved to {output_pdf}")
def get_rect_from_user():
root = tk.Tk()
root.withdraw() # 隐藏主窗口
# 通过弹窗获取用户输入
x0 = simpledialog.askinteger("输入", "请输入左上角 x 坐标:")
y0 = simpledialog.askinteger("输入", "请输入左上角 y 坐标:")
x1 = simpledialog.askinteger("输入", "请输入右下角 x 坐标:")
y1 = simpledialog.askinteger("输入", "请输入右下角 y 坐标:")
return (x0, y0, x1, y1)
def ask_for_image_replacement():
root = tk.Tk()
root.withdraw() # 隐藏主窗口
# 弹窗询问是否要替换成其他图片
replace = messagebox.askyesno("替换图片", "是否要替换为其他图片?")
if replace:
# 选择图片文件
image_path = filedialog.askopenfilename(title="选择图片", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
if image_path:
# 使用 tkinter 的 PhotoImage 检查图片大小
img = PhotoImage(file=image_path)
if img.width() <= 1024 and img.height() <= 1024:
return image_path
else:
messagebox.showerror("错误", "选择的图片尺寸必须在 1024x1024 像素内。")
return None
return None
if __name__ == "__main__":
input_folder = os.path.abspath("需要加工的pdf")
output_folder = os.path.abspath("完成加工")
logging.info(f"Input folder: {input_folder}")
logging.info(f"Output folder: {output_folder}")
if not os.path.exists(input_folder):
logging.error(f"Input folder '{input_folder}' does not exist.")
if not os.path.exists(output_folder):
logging.error(f"Output folder '{output_folder}' does not exist.")
# 通过弹窗获取用户输入的矩形区域
rect = get_rect_from_user()
# 询问用户是否要替换为其他图片
image_path = ask_for_image_replacement()
process_pdfs_in_folder(input_folder, output_folder, rect, image_path)
logging.info("Processing completed.")
input("Press Enter to exit...")
使用介绍
此代码需要打包成.exe文件才可使用
将需要加工的pdf放进对应文件夹,运行.exe即可
pdf图片坐标信息:例如100*100的图片,左上角就是(0,0),右下角就是(100,100),如果需要替换成其他图片,源代码有1k分辨率的限制,不需要就直接替换成白色。
代码逻辑
库:
fitz是用于处理PDF文件
logging是记录修改日志
tkinter创建修改用户界面的弹窗
PhotoImage是用作图像文件处理
颜色转换函数
def convert_color_to_range(color):
return tuple(c / 255.0 for c in color)
功能:将RGB颜色值从[0,255]范围转换为[0,1]范围,以便PYMuPDF使用。
从PDF中覆盖指定位置的图片
def remove_watermark_from_pdf(input_pdf, output_pdf, rect, image_path=None, color=(255, 255, 255)):
try:
doc = fitz.open(input_pdf)
for page_num in range(len(doc)):
page = doc.load_page(page_num)
shape = page.new_shape()
if image_path:
img = fitz.open(image_path)
img_rect = fitz.Rect(rect)
page.insert_image(img_rect, filename=image_path, keep_proportion=False)
else:
if shape is None:
raise ValueError("Shape object creation failed")
shape.draw_rect(rect)
color_converted = convert_color_to_range(color)
shape.finish(color=color_converted, fill=color_converted)
shape.commit()
doc.save(output_pdf, deflate=True)
logging.info(f"Processed {input_pdf} and saved to {output_pdf}")
except Exception as e:
logging.error(f"Failed to process {input_pdf}: {e}")
功能:加工输入的pdf
参数:input_pdf :输入PDF路径
output_pdf :输出PDF路径
rect : 要覆盖的区域,格式为(x0,y0,x1,y1)。
image_path : 用于替换的图片路径(如果有需要替换图片)
color : 用于填充矩形的区域颜色(默认白色)
逻辑
打开 PDF 文件并遍历每一页。
如果提供了图片路径,则插入图片并调整大小以适应指定区域。
如果没有提供图片,则用指定颜色填充矩形区域。
保存处理后的 PDF 文件。
记录处理状态。
处理文件夹中的PDF文件
def process_pdfs_in_folder(input_folder, output_folder, rect, image_path=None, color=(255, 255, 255)):
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for filename in os.listdir(input_folder):
if filename.lower().endswith('.pdf'):
input_pdf = os.path.join(input_folder, filename)
output_pdf = os.path.join(output_folder, f"processed_{filename}")
logging.info(f"Processing {input_pdf}...")
remove_watermark_from_pdf(input_pdf, output_pdf, rect, image_path, color)
logging.info(f"Saved to {output_pdf}")
功能就是处理文件夹下的所有pdf文件,并将处理好的文件全部保存到另一个文件夹中。
参数:
input_folder : 待处理DPF文件夹路径(需要加工的pdf)
output_folder : 处理后的PDF保存路径
rect :需要覆盖的位置区域。
image_path : 图片路径
color : 用于填充矩形的颜色
获取用户输入的矩形区域:
def get_rect_from_user():
root = tk.Tk()
root.withdraw() # 隐藏主窗口
# 通过弹窗获取用户输入
x0 = simpledialog.askinteger("输入", "请输入左上角 x 坐标:")
y0 = simpledialog.askinteger("输入", "请输入左上角 y 坐标:")
x1 = simpledialog.askinteger("输入", "请输入右下角 x 坐标:")
y1 = simpledialog.askinteger("输入", "请输入右下角 y 坐标:")
return (x0, y0, x1, y1)
作用供用户输入矩形坐标。
替换图片
def ask_for_image_replacement():
root = tk.Tk()
root.withdraw() # 隐藏主窗口
# 弹窗询问是否要替换成其他图片
replace = messagebox.askyesno("替换图片", "是否要替换为其他图片?")
if replace:
# 选择图片文件
image_path = filedialog.askopenfilename(title="选择图片", filetypes=[("Image Files", "*.png;*.jpg;*.jpeg")])
if image_path:
# 使用 tkinter 的 PhotoImage 检查图片大小
img = PhotoImage(file=image_path)
if img.width() <= 1024 and img.height() <= 1024:
return image_path
else:
messagebox.showerror("错误", "选择的图片尺寸必须在 1024x1024 像素内。")
return None
return None
功能:是否要用图片替换,当然这里的图片大小可以自己改
主要执行程序:
if __name__ == "__main__":
input_folder = os.path.abspath("需要加工的pdf")
output_folder = os.path.abspath("完成加工")
logging.info(f"Input folder: {input_folder}")
logging.info(f"Output folder: {output_folder}")
if not os.path.exists(input_folder):
logging.error(f"Input folder '{input_folder}' does not exist.")
if not os.path.exists(output_folder):
logging.error(f"Output folder '{output_folder}' does not exist.")
# 通过弹窗获取用户输入的矩形区域
rect = get_rect_from_user()
# 询问用户是否要替换为其他图片
image_path = ask_for_image_replacement()
process_pdfs_in_folder(input_folder, output_folder, rect, image_path)
logging.info("Processing completed.")
input("Press Enter to exit...")
逻辑:设置输入和输出文件夹绝对路径,记录输入和输出文件夹的路径,通过弹窗获取矩形区域坐标,是否需要用图片替换,处理文件夹下的所有PDF文件,最后记录结果日志。