前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何将PDF按页进行拆分,然后提取PDF区域内容改名或保存表格?基于iText.Kernel.Pdf 解决方案

如何将PDF按页进行拆分,然后提取PDF区域内容改名或保存表格?基于iText.Kernel.Pdf 解决方案

原创
作者头像
不负众望
发布于 2025-03-26 07:46:38
发布于 2025-03-26 07:46:38
19700
代码可运行
举报
运行总次数:0
代码可运行

一、项目背景

随着数字化办公的普及,PDF文件因其固定格式和跨平台兼容性被广泛应用于文档传输和存档。然而,多页PDF文件在管理和处理时可能带来不便,特别是需要提取特定区域的内容进行进一步的分析或存档。

本项目旨在开发一个基于WPF(Windows Presentation Foundation)的桌面应用程序,帮助用户将PDF文件按页拆分成多个单独的PDF文件,并提取每页中的指定区域内容进行重命名或保存为表格,以提高文档处理的效率和准确性。

二、界面设计

WPF提供了丰富的UI组件和灵活的布局方式,适合构建功能强大且用户友好的桌面应用。以下是该应用的主要界面设计元素:

1. 主窗口布局

  • 菜单栏
    • 文件:打开PDF文件、退出应用
    • 帮助:关于、帮助文档
  • 工具栏
    • 打开PDF按钮
    • 拆分并提取按钮
  • 主内容区
    • PDF文件信息显示:显示所选PDF的总页数、文件名等信息
    • 区域选择区:用户可以通过输入或拖拽方式选择要提取的区域(如指定坐标、页面区域等)
    • 进度条:显示当前操作进度
    • 日志输出区:实时显示操作日志和错误信息
  • 结果展示区
    • 保存路径选择:让用户选择拆分后PDF和提取内容的保存目录
    • 表格预览​(可选):对提取的内容进行简单预览,支持导出为Excel或CSV

2. 用户流程

  1. 用户通过菜单或工具栏打开一个PDF文件。
  2. 在区域选择区设置需要提取的区域。
  3. 选择保存路径。
  4. 点击“拆分并提取”按钮,程序开始处理:
    • 按页拆分PDF。
    • 提取每页指定区域的内容。
    • 将每一页另存为单独的PDF文件。
    • 根据提取的内容对文件进行重命名或保存为表格。

三、详细代码

1. 项目结构

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PDFSplitterExtractor/
├── PDFSplitterExtractor/
│   ├── MainWindow.xaml
│   ├── MainWindow.xaml.cs
│   ├── PdfHandler.cs
│   ├── RegionExtractor.cs
│   └── SaveManager.cs
├── Resources/
│   └── styles.xaml
└── App.xaml

2. 主要代码实现

2.1 MainWindow.xaml
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
xml<Window x:Class="PDFSplitterExtractor.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:PDFSplitterExtractor"
        Title="PDF拆分与内容提取器" Height="600" Width="800">
    <Grid>
        <!-- 菜单栏 -->
        <Menu Grid.Row="0">
            <MenuItem Header="文件">
                <MenuItem Header="打开PDF" Click="OpenFile_Click"/>
                <MenuItem Header="退出" Click="Exit_Click"/>
            </MenuItem>
            <MenuItem Header="帮助">
                <MenuItem Header="关于"/>
                <MenuItem Header="帮助文档"/>
            </MenuItem>
        </Menu>

        <!-- 工具栏 -->
        <ToolBarTray Grid.Row="1">
            <ToolBar>
                <Button Content="打开PDF" Click="OpenFile_Click"/>
                <Button Content="拆分并提取" Click="SplitAndExtract_Click"/>
            </ToolBar>
        </ToolBarTray>

        <!-- 主内容区 -->
        <Grid Grid.Row="2">
            <!-- PDF信息显示 -->
            <TextBlock x:Name="PdfInfo" Margin="10"/>

            <!-- 区域选择区 -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Margin="10,50,10,10">
                <Label Content="区域选择(X,Y,Width,Height):"/>
                <TextBox x:Name="RegionTextBox" Width="200"/>
            </StackPanel>

            <!-- 保存路径选择 -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="10,0,10,10">
                <Label Content="保存路径:"/>
                <TextBox x:Name="SavePathTextBox" Width="500"/>
                <Button Content="浏览" Click="Browse_Click"/>
            </StackPanel>

            <!-- 进度条 -->
            <ProgressBar x:Name="ProgressBar" Height="20" Margin="10" VerticalAlignment="Bottom" Height="25" />

            <!-- 日志输出 -->
            <TextBox x:Name="LogTextBox" Margin="10" 
                     IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Auto"
                     Height="100" VerticalAlignment="Bottom"/>
        </Grid>
    </Grid>
</Window>
2.2 MainWindow.xaml.cs
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
csharpusing Microsoft.Win32;
using System.Windows;

namespace PDFSplitterExtractor
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void OpenFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog
            {
                Filter = "PDF Files|*.pdf"
            };
            if (openFileDialog.ShowDialog() == true)
            {
                string filePath = openFileDialog.FileName;
                PdfHandler pdfHandler = new PdfHandler(filePath);
                PdfInfo.Text = $"已加载PDF: {pdfHandler.GetPageCount()} 页";
                // 这里可以进一步加载PDF信息显示
            }
        }

        private void SplitAndExtract_Click(object sender, RoutedEventArgs e)
        {
            // 获取区域信息
            string regionInput = RegionTextBox.Text;
            // 获取保存路径
            string savePath = SavePathTextBox.Text;
            if (string.IsNullOrEmpty(savePath))
            {
                MessageBox.Show("请选择保存路径!");
                return;
            }
            // 开始拆分和提取
            PdfHandler pdfHandler = new PdfHandler(/* 传入PDF路径 */);
            pdfHandler.SplitAndExtractRegions(regionInput, savePath, (progress) =>
            {
                // 更新进度条
                ProgressBar.Dispatcher.Invoke(() => ProgressBar.Value = progress);
            }, (log) =>
            {
                // 更新日志
                LogTextBox.Dispatcher.Invoke(() => LogTextBox.AppendText(log + "
"));
            });
        }

        private void Browse_Click(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.FolderBrowserDialog fbd = new System.Windows.Forms.FolderBrowserDialog();
            if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SavePathTextBox.Text = fbd.SelectedPath;
            }
        }

        private void Exit_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}
2.3 PdfHandler.cs
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
csharpusing iText.Kernel.Pdf;
using iText.Layout;
using System;
using System.IO;
using System.Threading.Tasks;

namespace PDFSplitterExtractor
{
    public class PdfHandler
    {
        private string _pdfPath;
        private PdfDocument _pdfDoc;

        public PdfHandler(string pdfPath)
        {
            _pdfPath = pdfPath;
            _pdfDoc = new PdfDocument(new PdfReader(_pdfPath));
        }

        public int GetPageCount()
        {
            return _pdfDoc.GetNumberOfPages();
        }

        public void SplitAndExtractRegions(string regionInput, string savePath, Action<int> progressCallback, Action<string> logCallback)
        {
            string[] regions = regionInput.Split(',');
            if (regions.Length != 4)
            {
                logCallback("区域输入格式错误,应为 X,Y,Width,Height");
                return;
            }

            float x = float.Parse(regions[0]);
            float y = float.Parse(regions[1]);
            float width = float.Parse(regions[2]);
            float height = float.Parse(regions[3]);

            int totalPages = GetPageCount();
            for (int i = 1; i <= totalPages; i++) // iText页码从1开始
            {
                logCallback($"处理第 {i} 页");
                PdfPage page = _pdfDoc.GetPage(i);

                using (MemoryStream ms = new MemoryStream())
                {
                    PdfWriter writer = new PdfWriter(ms);
                    PdfDocument newPdfDoc = new PdfDocument(writer);
                    PdfPage newPage = newPdfDoc.AddNewPage(i);

                    // 这里需要更复杂的逻辑来提取指定区域并生成新PDF,简化处理为复制页面
                    // 实际项目中应使用PdfCanvas或RenderContext提取特定区域内容

                    newPdfDoc.Close();
                    string newFileName = Path.Combine(savePath, $"Page_{i}.pdf");
                    File.WriteAllBytes(newFileName, ms.ToArray());
                }

                // 假设区域内容提取保存到表格
                ExtractRegionContent(page, x, y, width, height, savePath, i);

                progressCallback((i * 100) / totalPages);
            }

            _pdfDoc.Close();
            logCallback("拆分和提取完成!");
        }

        private void ExtractRegionContent(PdfPage page, float x, float y, float width, float height, string savePath, int pageIndex)
        {
            // 使用iText的PdfCanvasProcessor或相关方法提取区域内容
            // 此处简化处理
            // 例:提取文本并保存为CSV
            // 需要集成文本提取逻辑,例如使用iText的LocationTextExtractionStrategy
            // 并根据坐标过滤文本

            // 简化示例:保存空内容
            string content = $"第 {pageIndex} 页区域内容";
            string csvPath = Path.Combine(savePath, $"Page_{pageIndex}_Content.csv");
            File.WriteAllText(csvPath, content);
        }
    }
}

注意:以上代码仅为示例,实际提取区域内容需要更复杂的实现,可能需要结合文本坐标或图像处理技术。

2.4 SaveManager.cs

(上述代码中已整合相关功能,可根据需要单独拆分保存逻辑)

四、项目总结

本项目基于WPF开发了一个PDF拆分与区域内容提取的工具,主要实现了以下功能:

  1. PDF文件加载与信息显示:用户可以加载PDF文件,界面会显示PDF的总页数等基本信息。
  2. 区域选择与内容提取:用户可以通过输入区域坐标来指定需要提取的内容区域,程序根据输入提取每页的指定区域内容。
  3. PDF按页拆分:将PDF文件按页拆分成多个单独的PDF文件,便于管理和查看。
  4. 内容保存与重命名:将提取的区域内容保存为表格(如CSV)或根据内容重命名拆分后的PDF文件。

技术实现方面

  • 使用了iText.Kernel.Pdf库来处理PDF的拆分和页面操作。
  • WPF提供了丰富的UI组件,用于构建用户友好的界面。
  • 采用异步回调机制更新进度条和日志输出,提升用户体验。

项目优化方向

  1. 高效区域提取:优化区域内容的提取算法,提高提取的准确性和效率,特别是在处理复杂PDF布局时。
  2. 多线程处理:引入多线程或并行处理技术,以加快大规模PDF文件的处理速度。
  3. 错误处理与日志记录:增强错误处理机制,提供详细的日志记录,方便用户和开发者排查问题。
  4. 用户界面增强:优化界面设计,提供更多交互功能,如拖拽选择区域、自动检测内容区域等。

总结

本项目通过结合WPF的强大数据展示能力和iText等PDF处理库,成功实现了一个功能完备的PDF拆分与内容提取工具。未来,可以通过进一步的技术优化和功能扩展,提升工具的实用性,满足更多复杂的PDF处理需求。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
暂无评论
推荐阅读
编辑精选文章
换一批
java Runtime.exec()执行shell/cmd命令:常见的几种陷阱与一种完善实现
我们项目要java执行命令“dmidecode -s system-uuid”获取结果,然而碰到问题,当项目一直执行好久后,Runtime.getRuntime().exec()获取结果为空,但也不报错,重启项目就又可以了,所以猜测属于陷阱2,并进行记录。
刘大猫
2024/11/17
8460
java 执行shell命令及日志收集避坑指南
有时候我们需要调用系统命令执行一些东西,可能是为了方便,也可能是没有办法必须要调用。涉及执行系统命令的东西,则就不能做跨平台了,这和java语言的初衷是相背的。
烂猪皮
2021/01/14
2.7K0
【转】Java中Runtime.exec的一些事 
Runtime类是一个与JVM运行时环境有关的Singleton类,有以下几个值得注意的地方:
yiduwangkai
2019/09/17
3.1K0
Java魔法堂:调用外部程序
Java虽然五脏俱全但总有软肋,譬如获取CPU等硬件信息,当然我们可以通过JNI调用C/C++来获取,但对于对C/C++和Windows API不熟的码农是一系列复杂的学习和踩坑过程。那能不能通过简单一些、学习成本低一些的方式呢?答案是肯定的,在功能实现放在首位的情况下,借他山之石是最简洁有力的做法。
^_^肥仔John
2021/02/25
1.7K0
Java魔法堂:调用外部程序
Java 配 Shell 等于美酒加咖啡
技术上又何尝不是如此呢?先假设一个场景:BOSS 让你实现一个服务监控的指挥室,能看到每个服务器的磁盘剩余空间,能看到。。。能看到。。。
一猿小讲
2019/09/17
8590
Java 配 Shell 等于美酒加咖啡
Java调用CMD命令
Windows下复制: copy C:\server\data\ccgavr\1.png C:\server\data\ccgavr\2.png Windows重命名: ren 1.png 3.png ren C:\server\data\ccgavr\1.png C:\server\data\ccgavr\3.png(DOS中提示命令语法不正确,powershell则可以)
JaneYork
2023/10/11
4050
Java调用CMD命令
Linux:java通过Runtime.getRuntime().exec()执行shell,Process.waitFor()返回Required key not available(126)问题
因为看到错误码对应的原因是:Required key not available,所需的Key不可用。查找了很多相关解决办法,发现都不太相关。
鲲志说
2025/04/07
830
Linux:java通过Runtime.getRuntime().exec()执行shell,Process.waitFor()返回Required key not available(126)问题
Process类详解
ProcessBuilder是一个final类,Process是一个抽象类。ProcessBuilder.start() 和 Runtime.exec() 方法都被用来创建一个操作系统进程(执行命令行操作),并返回 Process 子类的一个实例,该实例可用来控制进程状态并获得相关信息。
matt
2022/10/25
1.7K0
聊聊PowerJob的AbstractScriptProcessor
tech/powerjob/official/processors/impl/script/AbstractScriptProcessor.java
code4it
2024/01/04
1100
ProcessBuilder API 指南-Java快速进阶教程
Process API提供了一种在 Java 中执行操作系统命令的强大方法。但是,它有几个选项,可能会使其使用起来很麻烦。
jack.yang
2025/04/05
1090
红队笔记专属-shell备忘录
建议直接复制粘贴到笔记,或点赞收藏,因为时常会用到,这是整理的一些常见的反向shell和特权提升的笔记文档,红队成员必会!
Gamma实验室
2022/04/26
1.1K0
Java程序员的日常 —— 多进程开发
最近再弄进程管理相关的工作,因此必要的就涉及到各种系统下关于进程的管理。 这里简单的介绍下: 如何在Java中执行命令 在windows下肯定是dos命令了,而在linux则为shell命令。执行的方式差不多相同: 方法1:Runtime windows版本: Process process = Runtime.getRuntime().exec("ipconfig /all"); Linux版本: Process process = Runtime.getRuntime().exec("ifcon
用户1154259
2018/01/17
1.2K0
Java程序员的日常 —— 多进程开发IO阻塞问题
本篇仍旧是源于最近的工作,总结一下纪念那些年埋下的坑... 背景故事 需求:“使用进程方式启动另一个程序!” 开发:“OK! Runtime.getRuntime().exec("xxxx")” 需求:“启动以后能看到输出消息不!” 开发:“OK!” Process process = null; try { process = Runtime.getRuntime().exec("ipconfig /all"); } catch (IOException e) { e.printSt
用户1154259
2018/01/17
1.5K0
Process API 指南-Java快速进阶教程
它所指的进程是一个正在执行的应用程序。Process类提供与这些进程交互的方法,包括提取输出、执行输入、监视生命周期、检查退出状态以及销毁(终止)它。
jack.yang
2025/04/05
1270
java:执行linux sudo命令
版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net/10km/article/details/78913746
10km
2019/05/25
6.4K1
java执行和停止Logcat命令及多线程实现
本人在使用UiAutomator的时候,想多写一个自动收集手机log的方法,使用runtime类执行了adb logcat的方法,但是一直找不到好的方法结束这个线程,网上说有kill pid的,但是这个操作起来略微麻烦了。自己也想了一个destroy线程的方法,一直不好用。提示错误信息如下:
FunTester
2019/08/14
1.7K0
Java 使用Runtime在一个Java程序中启动和关闭另一个Java程序
重点是Java启动的process,不能直接执行java、jps等命令,也获取不到环境变量,会报command not found
heasy3
2020/08/02
2.6K0
UiAutomator测试中如何恢复手机输入法
本人在使用UiAutomator测试的时候,需要用到utf7输入法,每次执行之前都会切换到utf7输入法,然后每次执行结束之后再切换到正常输入法,由于测试机器比较多,所以写了一个自动切换到其他任意输入法的方法。分享代码,供大家参考。
FunTester
2019/08/27
9450
Java执行Shell命令的方式
Java可以使用Runtime和ProcessBuilder两种方式执行Shell命令。
很酷的站长
2023/09/24
3.7K0
Java执行Shell命令的方式
RunNiFi.java 源码解读
RunNiFi类是由 nifi.sh脚本执行java命令指定的主类,RunNiFi类主要是干一些 查找文件,接受脚本指令,启动停止NIFI进程(主类 org.apache.nifi.NiFi),自动重启NIFI,发送NIFI通知等等操作;关于代码的详细解读都在注释当中,可以从 main方法下自行跟踪阅读(自己跟着源码逻辑读更好):
@阿诚
2020/09/01
1.3K0
推荐阅读
相关推荐
java Runtime.exec()执行shell/cmd命令:常见的几种陷阱与一种完善实现
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验