From a0ce609b94f0c951c5bd5821bced602d6e64723e Mon Sep 17 00:00:00 2001 From: xingzi Date: Mon, 16 Oct 2023 10:22:08 +0800 Subject: [PATCH] pymupdf --- .gitignore | 5 +- index.py | 129 ----------------------------- stamptool.py => main.py | 176 +++++++++++++++++++++++----------------- requirements.txt | Bin 148 -> 171 bytes test.py | 26 ++++-- 5 files changed, 124 insertions(+), 212 deletions(-) delete mode 100644 index.py rename stamptool.py => main.py (63%) diff --git a/.gitignore b/.gitignore index 4c8f697..d9c92fb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ .vscode + +.venv + build dist -*.spec \ No newline at end of file +*.spec diff --git a/index.py b/index.py deleted file mode 100644 index 813189a..0000000 --- a/index.py +++ /dev/null @@ -1,129 +0,0 @@ -import os -import fitz - -from PIL import Image -from tkinter import filedialog -from tkinter import Tk, Button, Label, messagebox, Toplevel -from tkinter.filedialog import askopenfilename - - -def add_image_watermark(input_image_path, watermark_image_path, output_image_path): - water_width = 100 - water_height = 100 - water_right = 50 - water_bottom = 100 - # 打开原始图片和要添加的水印图片 - original_img = Image.open(input_image_path).convert("RGBA") - watermark_img = Image.open(watermark_image_path).convert("RGBA") - - # 获取原始图片和水印图片的尺寸 - original_width, original_height = original_img.size - - # 将水印图片缩放到与原始图片相同的大小 - watermark_img = watermark_img.resize((water_width, water_height)) - - # 合并原始图片和水印图片,并将结果转换为RGB模式 - # watermarked_img = Image.alpha_composite(original_img, watermark_img).convert("RGB") - original_img.paste(watermark_img, (original_width - (water_width+water_right), - original_height-(water_height+water_bottom)), watermark_img) - - # 保存水印后的图片为JPEG格式 - original_img.save(output_image_path) - - -class CustomMessageBox(Toplevel): - def __init__(self, master, text, width=400, height=100): - super().__init__(master) - self.transient(master) - self.title("Error") - - self.label = Label(self, text=text) - self.label.pack(padx=20, pady=20) - - # 设置了宽和高 - self.width = width - self.height = height - self.geometry( - f'{width}x{height}+{master.winfo_x()}+{master.winfo_y()}') - - self.grab_set() # 使得对话框不会在点击窗口之外的地方时关闭 - self.wait_window(self) # 等待对话框关闭 - - -if __name__ == "__main__": - # items = os.listdir(pdfs) - # for f in items: - # name, suffix = os.path.splitext(f) - # if suffix == '.pdf': - # out = outPath + '/' + name + '_watered' + suffix - # input_file = os.path.join(pdfs, f) - # # img2pdf(water_path_png) - # # add_watermark(input_file,water_path_pdf,out) - # add_watermask_fitz(input_file, water_path_pdf, out) - - # 获取当前目录 - current_dir = os.getcwd() - # 获取脚本自身的路径 - script_path = os.path.dirname(os.path.abspath(__file__)) - - water_path_png = os.path.join(current_dir, 'waters/logo.png') - water_path_pdf = os.path.join(current_dir, 'waters/logo.pdf') - - outPath = os.path.join(current_dir, 'output') - pdfs = os.path.join(current_dir, 'pdfs') - - def on_closing(): - root.destroy() - root.quit() - exit() - - def select_file(label, extensions=['pdf', 'png', 'jpeg', 'jpg']): - Tk().withdraw() - file_path = filedialog.askopenfilename() - if file_path: - file_extension = file_path.split('.')[-1].lower() - if file_extension in extensions: - label.config(text=file_path) - else: - CustomMessageBox(root, "无效的文件类型。请选择PDF、PNG、JPEG或JPG文件。") - select_file() - - def add_watermask(): - file_path = lable_file.cget("text") - water_path = lable_stamp.cget("text") - print(file_path, water_path) - baseaname = os.path.basename(file_path) - name, suffix = os.path.splitext(baseaname) - out_path = os.path.join(os.path.dirname( - file_path), name + '_watered' + suffix) - pdf_file = fitz.open(file_path) - page = pdf_file[0] - page.insert_image(page.bound(), filename=water_path) - pdf_file.save(out_path) - lable_water.config(text=out_path) - - root = Tk() - root.protocol("WM_DELETE_WINDOW", on_closing) - root.geometry("600x400") - - # 选择文件 - lable_file = Label(root, text="请选择PDF或图片") - lable_file.grid(row=0, column=1) - button_file = Button(root, text="选择PDF", - command=lambda: select_file(lable_file)) - button_file.grid(row=0, column=0) - - # 选择公章 - lable_stamp = Label(root, text="请选择选择公章") - lable_stamp.grid(row=1, column=1) - button_stamp = Button(root, text="选择公章", command=lambda: select_file(lable_stamp, - extensions=['png', 'jpeg', 'jpg'])) - button_stamp.grid(row=1, column=0) - - # 添加水印 - button_water = Button(root, text="添加水印", command=add_watermask) - button_water.grid(row=2, column=0) - lable_water = Label(root, text="") - lable_water.grid(row=2, column=1) - - root.mainloop() diff --git a/stamptool.py b/main.py similarity index 63% rename from stamptool.py rename to main.py index ffe0d1b..62787b8 100644 --- a/stamptool.py +++ b/main.py @@ -1,5 +1,6 @@ import os import sys +import platform from fpdf import FPDF from PIL import Image @@ -9,6 +10,11 @@ from tkinter.filedialog import askdirectory, askopenfiles from pypdf import PdfWriter, PdfReader, Transformation import math import random +import subprocess + + +def get_os(): + return platform.system() def check_output(path): @@ -19,22 +25,22 @@ def check_output(path): os.mkdir(dir_name) -def img_to_pdf(img_path, out_path='', x=0, y=0, w=100, h=100): - ''' 图片转PDF''' - if out_path == '': +def img_to_pdf(img_path, out_path="", x=0, y=0, w=100, h=100): + """图片转PDF""" + if out_path == "": dir_name = os.path.dirname(img_path) basename = os.path.basename(img_path) name, _ = os.path.splitext(basename) - out_path = os.path.join(dir_name, name+'.pdf') + out_path = os.path.join(dir_name, name + ".pdf") pdf = FPDF() pdf.add_page() pdf.image(img_path, x=x, y=y, w=w, h=h) - pdf.output(out_path, 'F') + pdf.output(out_path, "F") return out_path def add_image_watermark(input_path, watermark_path, output_path): - ''' 图片添加印章 ''' + """图片添加印章""" # 打开原始图片和要添加的水印图片 original_img = Image.open(input_path).convert("RGBA") watermark_img = Image.open(watermark_path).convert("RGBA") @@ -47,20 +53,27 @@ def add_image_watermark(input_path, watermark_path, output_path): watermark_img = watermark_img.rotate(random.uniform(-180, 180)) # 合并原始图片和水印图片,并将结果转换为RGB模式 - original_img.paste(watermark_img, (math.ceil(original_width - original_width/2.6), - math.ceil(original_height-original_height/2.6)), watermark_img) + original_img.paste( + watermark_img, + ( + math.ceil(original_width - original_width / 2.6), + math.ceil(original_height - original_height / 2.6), + ), + watermark_img, + ) # 保存水印后的图片 original_img.save(output_path) def add_pdf_watermark(intput_file, watermark_path, output_path): - ''' PDF添加印章 ''' + """PDF添加印章""" stamp = PdfReader(watermark_path).pages[0] writer = PdfWriter(clone_from=intput_file) for page in writer.pages: page.merge_transformed_page( - stamp, Transformation().translate(980, 60).scale(0.37)) + stamp, Transformation().translate(980, 60).scale(0.37) + ) writer.write(output_path) @@ -76,8 +89,7 @@ class CustomMessageBox(Toplevel): # 设置了宽和高 self.width = width self.height = height - self.geometry( - f'{width}x{height}+{master.winfo_x()}+{master.winfo_y()}') + self.geometry(f"{width}x{height}+{master.winfo_x()}+{master.winfo_y()}") self.grab_set() # 使得对话框不会在点击窗口之外的地方时关闭 self.wait_window(self) # 等待对话框关闭 @@ -86,21 +98,23 @@ class CustomMessageBox(Toplevel): if __name__ == "__main__": multi_files = [] # 多选的文件 dir_files = [] # 文件夹中的文件 - water_path = '' # 印章路径 - tmp_water = '' # 当为图片时,删除临时生成的PDF印章 - last_stamped = '' # 最后一个添加印章后的文件 + water_path = "" # 印章路径 + tmp_water = "" # 当为图片时,删除临时生成的PDF印章 + last_stamped = "" # 最后一个添加印章后的文件 + + print(print(get_os())) def reset(): global multi_files, dir_files, water_path, tmp_water multi_files = [] dir_files = [] - water_path = '' - tmp_water = '' - lable_dir.config(text='') - lable_files.config(text='') - lable_stamp.config(text='') - label_create.config(text='') - button_create.config(state='disabled') + water_path = "" + tmp_water = "" + lable_dir.config(text="") + lable_files.config(text="") + lable_stamp.config(text="") + label_create.config(text="") + button_create.config(state="disabled") button_opendir.place_forget() button_openfile.place_forget() @@ -111,17 +125,19 @@ if __name__ == "__main__": def check_status(): # 如果文件和水印都选择便启用水印生成按钮,否则禁用 - if ((lable_files.cget('text') != '' or lable_dir.cget('text') != '') and lable_stamp.cget('text') != ''): - button_create.config(state='normal') + if ( + lable_files.cget("text") != "" or lable_dir.cget("text") != "" + ) and lable_stamp.cget("text") != "": + button_create.config(state="normal") else: - button_create.config(state='disabled') + button_create.config(state="disabled") - def select_files(extensions=['pdf', 'png', 'jpeg', 'jpg']): + def select_files(extensions=["pdf", "png", "jpeg", "jpg"]): Tk().withdraw() files = askopenfiles() # 检测文件类型 for item in files: - file_extension = item.name.split('.')[-1].lower() + file_extension = item.name.split(".")[-1].lower() if file_extension not in extensions: CustomMessageBox(root, "无效的文件类型。") select_files() @@ -129,9 +145,9 @@ if __name__ == "__main__": paths = [(item.name) for item in files] global multi_files multi_files = paths - str = ','.join(paths) + str = ",".join(paths) if len(str) >= 50: - str = str[:50] + '...' + str = str[:50] + "..." lable_files.config(text=str) check_status() @@ -143,21 +159,21 @@ if __name__ == "__main__": global dir_files dir_files = items if len(folder_path) >= 50: - folder_path = str[:50] + '...' + folder_path = str[:50] + "..." lable_dir.config(text=folder_path) check_status() - def select_file(label, extensions=['png', 'jpeg', 'jpg']): + def select_file(label, extensions=["png", "jpeg", "jpg"]): Tk().withdraw() file_path = filedialog.askopenfilename() if file_path: - file_extension = file_path.split('.')[-1].lower() + file_extension = file_path.split(".")[-1].lower() if file_extension in extensions: # 隐藏操作按钮 button_opendir.place_forget() button_openfile.place_forget() if len(file_path) >= 50: - file_path = str[:50] + '...' + file_path = str[:50] + "..." label.config(text=file_path) # 检查水印生成按键可用状态 check_status() @@ -171,7 +187,12 @@ if __name__ == "__main__": for root, dirs, files in os.walk(dir_path): for file in files: # 检查文件是否是PDF或图片 - if file.endswith('.pdf') or file.endswith('.png') or file.endswith('.jpg') or file.endswith('.jpeg'): + if ( + file.endswith(".pdf") + or file.endswith(".png") + or file.endswith(".jpg") + or file.endswith(".jpeg") + ): # 如果是,则将其完整路径添加到列表中 file_list.append(os.path.join(root, file)) return file_list @@ -181,31 +202,30 @@ if __name__ == "__main__": name, suffix = os.path.splitext(baseaname) dir_path = os.path.dirname(file_path) # # 判断目标文件是图片还是PDF - if suffix.lower() == '.pdf': + if suffix.lower() == ".pdf": global tmp_water # 如果水印是图片,先转成PDF - if tmp_water == '': - if water_path.split('.')[-1].lower() != 'pdf': + if tmp_water == "": + if water_path.split(".")[-1].lower() != "pdf": tmp_water = img_to_pdf(water_path) - out_path = os.path.join( - dir_path, 'output', name + '_watered' + suffix) + out_path = os.path.join(dir_path, "output", name + "_watered" + suffix) check_output(out_path) add_pdf_watermark(file_path, tmp_water, out_path) else: - out_path = os.path.join( - dir_path, 'output', name + '_watered' + '.png') + out_path = os.path.join(dir_path, "output", name + "_watered" + ".png") check_output(out_path) add_image_watermark(file_path, water_path, out_path) # 显示操作按钮 global last_stamped last_stamped = out_path - label_create.config(text='生成成功:') - label_create.place(x=120, y=4*padding_y, - width=80, height=lable_height) - button_openfile.place(x=200, y=4*padding_y, - width=button_width, height=button_height) - button_opendir.place(x=280, y=4*padding_y, - width=button_width, height=button_height) + label_create.config(text="生成成功:") + label_create.place(x=120, y=4 * padding_y, width=80, height=lable_height) + button_openfile.place( + x=200, y=4 * padding_y, width=button_width, height=button_height + ) + button_opendir.place( + x=280, y=4 * padding_y, width=button_width, height=button_height + ) def multi_watermask(): global multi_files, dir_files, tmp_water @@ -214,18 +234,24 @@ if __name__ == "__main__": for item in selected_files: add_watermask(item, water_path) # 删除临时PDF印章 - if tmp_water != '': + if tmp_water != "": os.remove(tmp_water) - tmp_water = '' + tmp_water = "" def open_dirname(): global last_stamped dir_name = os.path.dirname(last_stamped) - os.startfile(dir_name) + if get_os == "Windows": + os.startfile(dir_name) + else: + subprocess.run(["open", dir_name]) def open_file(): global last_stamped - os.startfile(last_stamped) + if get_os == "Windows": + os.startfile(last_stamped) + else: + subprocess.run(["open", last_stamped]) def get_path(relative_path): try: @@ -257,38 +283,42 @@ if __name__ == "__main__": root.geometry("{}x{}+{}+{}".format(500, 300, x_pos, y_pos)) # 选择文件-多选 button_files = Button(root, text="选择文件", command=select_files) - button_files.place(x=button_x, y=padding_y, width=button_width, - height=button_height) + button_files.place( + x=button_x, y=padding_y, width=button_width, height=button_height + ) lable_files = Label(root, text="") - lable_files.place(x=label_x, y=padding_y, - width=label_width, height=lable_height) + lable_files.place(x=label_x, y=padding_y, width=label_width, height=lable_height) # 选择目录 button_dir = Button(root, text="选择目录", command=select_dir) - button_dir.place(x=button_x, y=2*padding_y, - width=button_width, height=button_height) + button_dir.place( + x=button_x, y=2 * padding_y, width=button_width, height=button_height + ) lable_dir = Label(root, text="") - lable_dir.place(x=label_x, y=2*padding_y, - width=label_width, height=lable_height) + lable_dir.place(x=label_x, y=2 * padding_y, width=label_width, height=lable_height) # 选择公章 - button_stamp = Button(root, text="选择公章", command=lambda: select_file(lable_stamp, - extensions=['png', 'jpeg', 'jpg'])) - button_stamp.place(x=button_x, y=3*padding_y, - width=button_width, height=button_height) - lable_stamp = Label(root, text=get_path('waters/stamp.png')) - lable_stamp.place(x=label_x, y=3*padding_y, - width=label_width, height=lable_height) + button_stamp = Button( + root, + text="选择公章", + command=lambda: select_file(lable_stamp, extensions=["png", "jpeg", "jpg"]), + ) + button_stamp.place( + x=button_x, y=3 * padding_y, width=button_width, height=button_height + ) + lable_stamp = Label(root, text=get_path("waters/stamp.png")) + lable_stamp.place( + x=label_x, y=3 * padding_y, width=label_width, height=lable_height + ) # 预览 label_create = Label(root, text="") button_opendir = Button(root, text="目录", command=open_dirname) button_openfile = Button(root, text="预览", command=open_file) # 添加水印 - button_create = Button( - root, text="生成", command=multi_watermask, state='disabled') - button_create.place(x=120, y=6*padding_y, - width=button_width, height=button_height) + button_create = Button(root, text="生成", command=multi_watermask, state="disabled") + button_create.place( + x=120, y=6 * padding_y, width=button_width, height=button_height + ) # 重置 button_reset = Button(root, text="重置", command=reset) - button_reset.place(x=320, y=6*padding_y, - width=button_width, height=button_height) + button_reset.place(x=320, y=6 * padding_y, width=button_width, height=button_height) root.mainloop() diff --git a/requirements.txt b/requirements.txt index 0e20c2284e39d543833eaa8c710c81cd74ccdbdd..5d3f83b2e73063090e9b76d3cd745a32bdda7c30 100644 GIT binary patch literal 171 zcmZ9G!4AS85Jd0%OE*xpJ?+hSGvODu)lve14aFG#-fg27k2CW!GZd>U#4Dl(Gs0Od z{8$hTjL<8lIgs^NFAdp0%8;H97U|H!rPjY6qo)Xux>_a7B;6{!FK diff --git a/test.py b/test.py index 18acccf..0ba94d7 100644 --- a/test.py +++ b/test.py @@ -1,13 +1,21 @@ -from PIL import Image +import os +import fitz -img = Image.open('首营资料.jpg').convert("RGBA") +def add_watermask(): + file_path = './pdfs/girl.pdf' + water_path = './waters/logo.png' + baseaname = os.path.basename(file_path) + name, suffix = os.path.splitext(baseaname) + out_path = os.path.join(os.path.dirname(file_path), + name + '_watered' + suffix) + pdf_file = fitz.open(file_path) + page = pdf_file[0] + print(page.bound()) + # page.insert_image(page.bound(), filename=water_path) + rect = (800, -100, 900, 0) + page.insert_image(rect, filename=water_path) + pdf_file.save(out_path) -pdi = img.info.get('dpi')[0] -img_width, img_heigth = img.size -a4_width = 210 -stamp_width = 44 - -x = stamp_width/a4_width * img_width -print(x) +add_watermask()