基于C#与Pdftk实现PDF合并时自动补空白页的技术问询
用C#结合Pdftk实现带空白页补全的PDF合并工具修改方案
核心逻辑
要实现适配双面打印的PDF合并,核心是给每个奇数页的PDF追加空白页,确保每个子PDF的页数为偶数。流程如下:
- 遍历所有待合并的PDF文件,通过Pdftk获取每个文件的页数
- 对奇数页的PDF,将其与单页空白PDF合并成偶数页的临时文件;偶数页的PDF直接复制为临时文件
- 用Pdftk将所有处理后的临时文件合并为最终PDF
- 清理临时文件,避免残留
关键实现步骤及代码修改
1. 添加获取PDF页数的方法
通过调用Pdftk的dump_data命令解析页数:
private static int GetPdfPageCount(string pdfPath) { var processStartInfo = new ProcessStartInfo { FileName = "pdftk", Arguments = $"\"{pdfPath}\" dump_data", RedirectStandardOutput = true, UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processStartInfo); var output = process.StandardOutput.ReadToEnd(); process.WaitForExit(); var pageCountLine = output.Split(Environment.NewLine) .FirstOrDefault(line => line.StartsWith("NumberOfPages:")); if (pageCountLine == null) throw new InvalidOperationException($"无法获取PDF {pdfPath} 的页数"); return int.Parse(pageCountLine.Split(':')[1].Trim()); }
2. 生成空白页PDF
你可以选择两种方式获取空白页PDF:
- 方式一:预先准备空白PDF:创建一个单页空白PDF文件(比如
blank.pdf),放在工具可访问的路径下 - 方式二:动态生成:通过Pdftk命令生成临时空白页(适合不想依赖外部文件的场景):
private static string GenerateBlankPdf(string tempDir) { var blankPdfPath = Path.Combine(tempDir, $"blank_{Guid.NewGuid()}.pdf"); var processStartInfo = new ProcessStartInfo { FileName = "pdftk", Arguments = $"A=- cat A1 output \"{blankPdfPath}\"", UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processStartInfo); process.WaitForExit(); return blankPdfPath; }
3. 修改合并流程,处理每个PDF文件
假设原代码有一个待合并文件列表inputPdfPaths和输出路径outputPdfPath,修改后的流程如下:
public static void MergePdfsForDuplexPrint(string[] inputPdfPaths, string outputPdfPath) { var tempDir = Path.Combine(Path.GetTempPath(), $"pdf_merge_temp_{Guid.NewGuid()}"); Directory.CreateDirectory(tempDir); var processedTempPaths = new List<string>(); string blankPdfPath = null; try { // 生成或获取空白页PDF blankPdfPath = GenerateBlankPdf(tempDir); // 或者使用预先准备的文件:blankPdfPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "blank.pdf"); foreach (var pdfPath in inputPdfPaths) { var pageCount = GetPdfPageCount(pdfPath); var tempPath = Path.Combine(tempDir, $"processed_{Path.GetFileName(pdfPath)}"); if (pageCount % 2 != 0) { // 奇数页,合并原PDF和空白页 var processStartInfo = new ProcessStartInfo { FileName = "pdftk", Arguments = $"\"{pdfPath}\" \"{blankPdfPath}\" cat output \"{tempPath}\"", UseShellExecute = false, CreateNoWindow = true }; using var process = Process.Start(processStartInfo); process.WaitForExit(); } else { // 偶数页,直接复制 File.Copy(pdfPath, tempPath, true); } processedTempPaths.Add(tempPath); } // 合并所有处理后的临时PDF var mergeArgs = string.Join(" ", processedTempPaths.Select(p => $"\"{p}\"")) + $" cat output \"{outputPdfPath}\""; var mergeProcessStartInfo = new ProcessStartInfo { FileName = "pdftk", Arguments = mergeArgs, UseShellExecute = false, CreateNoWindow = true }; using var mergeProcess = Process.Start(mergeProcessStartInfo); mergeProcess.WaitForExit(); } finally { // 清理临时文件 if (Directory.Exists(tempDir)) { try { Directory.Delete(tempDir, true); } catch { // 忽略清理失败的情况,避免程序崩溃 } } } }
4. 命令行入口修改
解析命令行参数,调用上述合并方法:
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("用法:PdfMergeTool <输出路径> <输入PDF1> <输入PDF2> ..."); return; } var outputPath = args[0]; var inputPaths = args.Skip(1).ToArray(); MergePdfsForDuplexPrint(inputPaths, outputPath); Console.WriteLine("合并完成!"); }
注意事项
- 确保Pdftk已添加到系统环境变量,或者在代码中指定Pdftk的完整路径(比如
FileName = @"C:\Program Files\Pdftk\pdftk.exe") - 处理大文件时,临时目录要确保有足够的磁盘空间
- 可根据实际需求增强异常处理,比如捕获Pdftk执行失败的情况
内容的提问来源于stack exchange,提问作者aljoscha
相关产品推荐
相关产品推荐

