吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 584|回复: 24
上一主题 下一主题
收起左侧

[Python 原创] A3页面到A4页面转换Python程序

[复制链接]
跳转到指定楼层
楼主
nancune 发表于 2026-7-2 20:04 回帖奖励
本帖最后由 nancune 于 2026-7-2 20:07 编辑

因为需要用A4纸张打印A3幅面的材料(PDF格式),同时保证纸张边缘图文不丢失,图文大小不变,需要分割原A3页面到A4页面。A3页面到A4页面转换Python程序如下:
[Python] 纯文本查看 复制代码
import fitz
import sys

def split_all_facing_pdf(input_pdf: str, output_pdf: str):
    """
    所有对折页面对半拆分:
    1. 原页面左右对半裁切
    2. 左半页整体向左偏移8pt,右半页整体向右偏移8pt
    3. 左在前、右在后输出单页,保留旋转矫正开关
    """
    src_doc = fitz.open(input_pdf)
    new_doc = fitz.open()
    total_page_count = len(src_doc)
    print(f"检测到原PDF总页数:{total_page_count}")

    # 偏移量:4字符宽度对应4pt,可按需修改
    offset_pt = -8

    for page_idx in range(total_page_count):
        page = src_doc[page_idx]
        page_rect = page.rect
        page_w = page_rect.width
        page_h = page_rect.height
        half_w = page_w / 2

        # 原始左右裁切区域
        orig_clip_left = fitz.Rect(0, 0, half_w, page_h)
        orig_clip_right = fitz.Rect(half_w, 0, page_w, page_h)

        # ========== 左半页:向左偏移4pt ==========
        # 裁切区域左移offset_pt,防止页面边缘内容被裁掉
        clip_left_shift = fitz.Rect(
            orig_clip_left.x0 - offset_pt,
            orig_clip_left.y0,
            orig_clip_left.x1 - offset_pt,
            orig_clip_left.y1
        )
        left_single = new_doc.new_page(width=half_w, height=page_h)
        # 内容向右回填offset_pt,实现视觉左移效果
        left_target_rect = fitz.Rect(offset_pt, 0, half_w + offset_pt, page_h)
        left_single.show_pdf_page(left_target_rect, src_doc, page_idx, clip=clip_left_shift)
        # left_single.set_rotation(180)  # 按需开启旋转矫正颠倒

        # ========== 右半页:向右偏移4pt ==========
        # 裁切区域右移offset_pt
        clip_right_shift = fitz.Rect(
            orig_clip_right.x0 + offset_pt,
            orig_clip_right.y0,
            orig_clip_right.x1 + offset_pt,
            orig_clip_right.y1
        )
        right_single = new_doc.new_page(width=half_w, height=page_h)
        # 内容向左回填offset_pt,实现视觉右移效果
        right_target_rect = fitz.Rect(-offset_pt, 0, half_w - offset_pt, page_h)
        right_single.show_pdf_page(right_target_rect, src_doc, page_idx, clip=clip_right_shift)
        # right_single.set_rotation(180)  # 按需开启旋转矫正颠倒

        print(f"已拆分原第{page_idx+1}页 → 生成左(左移4pt)、右(右移4pt)2张单页")

    new_doc.save(output_pdf)
    new_doc.close()
    src_doc.close()
    print(f"\n✅ 分割偏移矫正完成!文件:{output_pdf}")

if __name__ == "__main__":
    if len(sys.argv) != 3:
        print("用法:python split_all_facing.py 输入.pdf 输出.pdf")
        sys.exit(1)
    split_all_facing_pdf(sys.argv[1], sys.argv[2])
    

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
shzjz123 + 2 + 1 实用!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
l12345678qaz 发表于 2026-7-3 12:25
本帖最后由 l12345678qaz 于 2026-7-3 12:29 编辑

将命令行PDF拆分程序转换为图形界面。



[Python] 纯文本查看 复制代码
import fitz
import sys
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
from pathlib import Path
import threading
import os

def split_all_facing_pdf(input_pdf: str, output_pdf: str, log_callback=None):
    """
    所有对折页面对半拆分:
    1. 原页面左右对半裁切
    2. 左半页整体向左偏移8pt,右半页整体向右偏移8pt
    3. 左在前、右在后输出单页,保留旋转矫正开关
    """
    def log(msg):
        if log_callback:
            log_callback(msg)
        else:
            print(msg)
    
    try:
        src_doc = fitz.open(input_pdf)
        new_doc = fitz.open()
        total_page_count = len(src_doc)
        log(f"检测到原PDF总页数:{total_page_count}")
        
        # 偏移量:4字符宽度对应4pt,可按需修改
        offset_pt = -8
        
        for page_idx in range(total_page_count):
            page = src_doc[page_idx]
            page_rect = page.rect
            page_w = page_rect.width
            page_h = page_rect.height
            half_w = page_w / 2
            
            # 原始左右裁切区域
            orig_clip_left = fitz.Rect(0, 0, half_w, page_h)
            orig_clip_right = fitz.Rect(half_w, 0, page_w, page_h)
            
            # ========== 左半页:向左偏移4pt ==========
            # 裁切区域左移offset_pt,防止页面边缘内容被裁掉
            clip_left_shift = fitz.Rect(
                orig_clip_left.x0 - offset_pt,
                orig_clip_left.y0,
                orig_clip_left.x1 - offset_pt,
                orig_clip_left.y1
            )
            left_single = new_doc.new_page(width=half_w, height=page_h)
            # 内容向右回填offset_pt,实现视觉左移效果
            left_target_rect = fitz.Rect(offset_pt, 0, half_w + offset_pt, page_h)
            left_single.show_pdf_page(left_target_rect, src_doc, page_idx, clip=clip_left_shift)
            # left_single.set_rotation(180)  # 按需开启旋转矫正颠倒
            
            # ========== 右半页:向右偏移4pt ==========
            # 裁切区域右移offset_pt
            clip_right_shift = fitz.Rect(
                orig_clip_right.x0 + offset_pt,
                orig_clip_right.y0,
                orig_clip_right.x1 + offset_pt,
                orig_clip_right.y1
            )
            right_single = new_doc.new_page(width=half_w, height=page_h)
            # 内容向左回填offset_pt,实现视觉右移效果
            right_target_rect = fitz.Rect(-offset_pt, 0, half_w - offset_pt, page_h)
            right_single.show_pdf_page(right_target_rect, src_doc, page_idx, clip=clip_right_shift)
            # right_single.set_rotation(180)  # 按需开启旋转矫正颠倒
            
            log(f"已拆分原第{page_idx+1}页 → 生成左(左移4pt)、右(右移4pt)2张单页")
        
        new_doc.save(output_pdf)
        new_doc.close()
        src_doc.close()
        log(f"\n✅ 分割偏移矫正完成!文件:{output_pdf}")
        return True
        
    except Exception as e:
        log(f"❌ 错误:{str(e)}")
        return False


class PDFSplitterGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("PDF对折页面拆分工具")
        self.root.geometry("700x500")
        
        # 设置样式
        style = ttk.Style()
        style.theme_use('clam')
        
        # 主框架
        main_frame = ttk.Frame(root, padding="20")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 配置网格权重
        root.columnconfigure(0, weight=1)
        root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        
        # 标题
        title_label = ttk.Label(main_frame, text="PDF对折页面拆分工具", 
                               font=('Arial', 16, 'bold'))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 输入文件选择
        ttk.Label(main_frame, text="输入PDF文件:").grid(row=1, column=0, sticky=tk.W, pady=5)
        
        self.input_var = tk.StringVar()
        input_entry = ttk.Entry(main_frame, textvariable=self.input_var, width=50)
        input_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), padx=(0, 10), pady=5)
        
        input_btn = ttk.Button(main_frame, text="浏览...", command=self.select_input_file)
        input_btn.grid(row=1, column=2, pady=5)
        
        # 输出文件选择
        ttk.Label(main_frame, text="输出PDF文件:").grid(row=2, column=0, sticky=tk.W, pady=5)
        
        self.output_var = tk.StringVar()
        output_entry = ttk.Entry(main_frame, textvariable=self.output_var, width=50)
        output_entry.grid(row=2, column=1, sticky=(tk.W, tk.E), padx=(0, 10), pady=5)
        
        output_btn = ttk.Button(main_frame, text="浏览...", command=self.select_output_file)
        output_btn.grid(row=2, column=2, pady=5)
        
        # 偏移量设置(可选,保持原功能)
        ttk.Label(main_frame, text="偏移量(pt):").grid(row=3, column=0, sticky=tk.W, pady=5)
        self.offset_var = tk.StringVar(value="-8")
        offset_entry = ttk.Entry(main_frame, textvariable=self.offset_var, width=10)
        offset_entry.grid(row=3, column=1, sticky=tk.W, pady=5)
        ttk.Label(main_frame, text="负值=左偏移,正值=右偏移").grid(row=3, column=1, sticky=tk.W, padx=(120, 0), pady=5)
        
        # 旋转矫正复选框(可选,保持原功能)
        self.rotate_var = tk.BooleanVar(value=False)
        rotate_cb = ttk.Checkbutton(main_frame, text="启用旋转矫正(180度)", 
                                   variable=self.rotate_var)
        rotate_cb.grid(row=4, column=0, columnspan=3, sticky=tk.W, pady=10)
        
        # 执行按钮
        self.process_btn = ttk.Button(main_frame, text="开始拆分", 
                                     command=self.process_pdf, width=20)
        self.process_btn.grid(row=5, column=0, columnspan=3, pady=20)
        
        # 日志区域
        ttk.Label(main_frame, text="处理日志:").grid(row=6, column=0, sticky=tk.W, pady=(10, 5))
        
        self.log_text = scrolledtext.ScrolledText(main_frame, width=70, height=15, 
                                                 font=('Courier', 9))
        self.log_text.grid(row=7, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 添加滚动条
        main_frame.rowconfigure(7, weight=1)
        
        # 底部状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN)
        status_bar.grid(row=1, column=0, sticky=(tk.W, tk.E))
        
        # 绑定回车键到处理函数
        self.root.bind('<Return>', lambda e: self.process_pdf())
    
    def select_input_file(self):
        """选择输入PDF文件"""
        filename = filedialog.askopenfilename(
            title="选择输入PDF文件",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        if filename:
            self.input_var.set(filename)
            # 自动生成输出文件名
            if not self.output_var.get():
                input_path = Path(filename)
                output_path = input_path.parent / f"{input_path.stem}_split.pdf"
                self.output_var.set(str(output_path))
    
    def select_output_file(self):
        """选择输出PDF文件"""
        filename = filedialog.asksaveasfilename(
            title="保存输出PDF文件",
            defaultextension=".pdf",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        if filename:
            self.output_var.set(filename)
    
    def log(self, message):
        """向日志区域添加消息"""
        self.log_text.insert(tk.END, message + "\n")
        self.log_text.see(tk.END)  # 自动滚动到底部
        self.root.update_idletasks()
    
    def process_pdf(self):
        """处理PDF拆分"""
        input_file = self.input_var.get().strip()
        output_file = self.output_var.get().strip()
        
        # 验证输入
        if not input_file:
            messagebox.showerror("错误", "请选择输入PDF文件")
            return
            
        if not output_file:
            messagebox.showerror("错误", "请指定输出PDF文件")
            return
            
        if not os.path.exists(input_file):
            messagebox.showerror("错误", f"输入文件不存在:\n{input_file}")
            return
        
        # 禁用按钮,防止重复点击
        self.process_btn.config(state='disabled')
        self.status_var.set("正在处理...")
        
        # 清空日志
        self.log_text.delete(1.0, tk.END)
        
        # 在新线程中处理PDF,避免界面卡顿
        def process_thread():
            try:
                success = split_all_facing_pdf(input_file, output_file, self.log)
                if success:
                    self.root.after(0, lambda: messagebox.showinfo("完成", 
                        f"PDF拆分完成!\n输出文件:{output_file}"))
                    self.root.after(0, lambda: self.status_var.set("处理完成"))
                else:
                    self.root.after(0, lambda: self.status_var.set("处理失败"))
            except Exception as e:
                self.log(f"&#10060; 处理异常:{str(e)}")
                self.root.after(0, lambda: messagebox.showerror("错误", 
                    f"处理失败:{str(e)}"))
                self.root.after(0, lambda: self.status_var.set("处理失败"))
            finally:
                self.root.after(0, lambda: self.process_btn.config(state='normal'))
        
        # 启动处理线程
        thread = threading.Thread(target=process_thread)
        thread.daemon = True
        thread.start()


def main():
    root = tk.Tk()
    app = PDFSplitterGUI(root)
    
    # 使窗口可调整大小
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)
    
    # 设置窗口图标(可选)
    try:
        root.iconbitmap(default='pdf_icon.ico')  # 如果有图标文件的话
    except:
        pass
    
    root.mainloop()


if __name__ == "__main__":
    main()

屏幕截图 2026-07-03 122855.jpg (30.97 KB, 下载次数: 0)

屏幕截图 2026-07-03 122855.jpg
推荐
miaolei545 发表于 2026-7-3 10:17
本帖最后由 miaolei545 于 2026-7-3 10:23 编辑

把下面代码新建为 PDF分割GUI.py,和你的 Split-A3TOA4-8pt.py 放同一文件夹即可在窗口导入和输出:

[Python] 纯文本查看 复制代码
import fitz
import tkinter as tk
from tkinter import filedialog, messagebox

def split_a3_to_a4(input_pdf_path, output_pdf_path):
    """A3 PDF页面拆分为左右两张A4,兼容你的原脚本逻辑"""
    doc = fitz.open(input_pdf_path)
    new_doc = fitz.open()
    for page in doc:
        rect = page.rect
        # A3页面左右对半分割
        half_width = rect.width / 2
        # 左半页A4
        left_rect = fitz.Rect(0, 0, half_width, rect.height)
        left_page = new_doc.new_page(width=half_width, height=rect.height)
        left_page.show_pdf_page(left_rect, doc, page.number, clip=left_rect)
        # 右半页A4
        right_rect = fitz.Rect(half_width, 0, rect.width, rect.height)
        right_page = new_doc.new_page(width=half_width, height=rect.height)
        right_page.show_pdf_page(fitz.Rect(0,0,half_width,rect.height), doc, page.number, clip=right_rect)
    new_doc.save(output_pdf_path)
    new_doc.close()
    doc.close()

class PDFSplitGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("A3转A4 PDF分割工具")
        self.root.geometry("480x200")

        self.input_path = tk.StringVar()
        self.output_path = tk.StringVar()

        # 输入文件行
        tk.Label(root, text="输入PDF:").grid(row=0, column=0, padx=10, pady=10, sticky="w")
        tk.Entry(root, textvariable=self.input_path, width=32).grid(row=0, column=1)
        tk.Button(root, text="选择", command=self.select_input).grid(row=0, column=2, padx=5)

        # 输出保存行
        tk.Label(root, text="输出PDF:").grid(row=1, column=0, padx=10, pady=10, sticky="w")
        tk.Entry(root, textvariable=self.output_path, width=32).grid(row=1, column=1)
        tk.Button(root, text="另存为", command=self.select_output).grid(row=1, column=2, padx=5)

        # 执行按钮
        tk.Button(root, text="开始分割", command=self.run_split, bg="#4285F4", fg="white", width=12, height=2).grid(row=2, column=1, pady=15)

    def select_input(self):
        path = filedialog.askopenfilename(
            title="选择需要分割的A3 PDF",
            filetypes=[("PDF文件", "*.pdf"), ("所有文件", "*.*")]
        )
        if path:
            self.input_path.set(path)

    def select_output(self):
        path = filedialog.asksaveasfilename(
            title="保存分割后的PDF",
            defaultextension=".pdf",
            filetypes=[("PDF文件", "*.pdf")]
        )
        if path:
            self.output_path.set(path)

    def run_split(self):
        in_path = self.input_path.get().strip()
        out_path = self.output_path.get().strip()
        if not in_path:
            messagebox.showwarning("提示", "请先选择输入PDF文件!")
            return
        if not out_path:
            messagebox.showwarning("提示", "请设置输出保存路径!")
            return
        try:
            split_a3_to_a4(in_path, out_path)
            messagebox.showinfo("完成", f"分割成功!\n文件已保存至:{out_path}")
        except Exception as e:
            messagebox.showerror("失败", f"分割出错:{str(e)}")

if __name__ == "__main__":
    window = tk.Tk()
    app = PDFSplitGUI(window)
    window.mainloop()

11.png (23.88 KB, 下载次数: 0)

11.png

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
lxq8432 + 1 + 1 用心讨论,共获提升!

查看全部评分

沙发
 楼主| nancune 发表于 2026-7-2 20:17 |楼主
为了方便运行,在当前目录新建文本文件Split-A3TOA4-8pt.py(Python程序), 复制粘贴上面的Python程序代码。
在当前目录新建文本文件Split-A3TOA4-8pt.bat(批处理文件),
复制粘贴下面的文本,

[Bash shell] 纯文本查看 复制代码
@echo off
:: 将当前目录设置为批处理文件所在目录
cd /d "%~dp0"
python Split-A3TOA4-8pt.py "需要分割的A3文档.pdf" "生成的A4文档-偏移8pt.pdf"
pause


   # 偏移量:可按需修改 offset_pt = -8
3#
YYBF888 发表于 2026-7-3 05:09
不错的设计
4#
czwuyang 发表于 2026-7-3 05:35
今天遇到的最好的第一件好事:这个代码太实用了
5#
lazychen 发表于 2026-7-3 07:13
封装一下大佬
6#
dxmcf 发表于 2026-7-3 07:30
很实用的,
7#
ggsjz 发表于 2026-7-3 07:42
支持大佬,
8#
tykioy 发表于 2026-7-3 07:47
学习一下,谢谢分享
9#
乱世佳人 发表于 2026-7-3 07:51
封装下,太实用了
10#
loonglee 发表于 2026-7-3 08:11
很实用,支持大佬
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-7-3 14:38

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表