iText7定位PDF字符串后,iTextSharp PdfStamper仅盖章一处问题排查
问题根源及修复方案
我仔细看了你的代码,发现几个关键问题,其中最直接导致仅第一个定位位置盖章的原因是过早关闭了PdfStamper,另外还有一些其他问题会影响整体逻辑的正确性:
1. 致命错误:过早调用stamper.Close()
在你处理第一个匹配到的位置时,就执行了stamper.Close(),这会立即关闭PDF stamper并释放资源,后续所有页面的盖章操作都无法生效。你需要把这个调用移到所有页面处理完成之后,也就是外层For page1循环的外面。
2. 重复解析页面内容+策略未重置
- 你在
For Each location循环里又重复调用了parser.ProcessPageContent(pdfDoc.GetPage(page1)),这会重复解析同一页面,导致匹配结果重复累积。 RegexBasedLocationExtractionStrategy是有状态的,如果你不每页重新实例化或重置,它会保留之前页面的匹配结果,导致后续循环处理到的是所有页面的累积结果,逻辑混乱。
解决方法:每页处理前重新创建extractionStrategy和parser,确保每次只处理当前页面的内容。
3. 重复创建PdfReader实例
代码里同时创建了pdfReader和pdfReader2,这不仅浪费资源,还容易导致上下文混乱,你只需要一个PdfReader实例来处理输入PDF即可。
4. Image复用的潜在问题
xmark这个Image实例如果被多次添加,可能因为内部状态的问题无法正确显示在后续位置。建议每次使用前重新获取实例,或者克隆一个新的Image对象来避免这个问题。
修正后的代码示例
Imports iTextSharp.text Imports System.IO Imports System.IO.Path Imports System.Text.RegularExpressions Imports iTextSharp.text.pdf.parser Imports System.Linq Imports iText Imports iText.Kernel.Pdf.Canvas.Parser.Listener Imports iText.Kernel.Pdf.Canvas.Parser Imports iText.Kernel.Pdf Module Module1 Dim signedFolder = "C:\Users\xborja\Desktop\Original PDF's\Signed PDFs\" Sub Main() If Not Directory.Exists(signedFolder) Then Directory.CreateDirectory(signedFolder) End If Dim src = "C:\Users\xborja\Desktop\Original PDF's Before Merge\TP067389.CRUZ.pdf" Dim pattern = "Conrad Noll IV, #6272795" Dim xmarkImagePath = "C:\Users\user\Desktop\xmark.png" Dim finalPDF As String = signedFolder & GetFileNameWithoutExtension(src) & " signed.pdf" ' 只创建一个PdfReader实例,用Using自动管理资源 Using pdfReader = New Pdf.PdfReader(src) Using outputPdf As Stream = New FileStream(finalPDF, FileMode.Create, FileAccess.Write, FileShare.None) Using stamper = New Pdf.PdfStamper(pdfReader, outputPdf) Dim pageCount = pdfReader.NumberOfPages Dim counter = 0 Console.WriteLine(pageCount) For pageNum = 1 To pageCount ' 每页重新创建提取策略和解析器,避免状态累积 Dim extractionStrategy As New RegexBasedLocationExtractionStrategy(pattern) Dim parser As New PdfCanvasProcessor(extractionStrategy) parser.ProcessPageContent(New iText.Kernel.Pdf.PdfDocument(pdfReader).GetPage(pageNum)) Dim locationList = extractionStrategy.GetResultantLocations If locationList IsNot Nothing AndAlso locationList.Count > 0 Then Dim pdfContentByte = stamper.GetOverContent(pageNum) For Each location As IPdfTextLocation In locationList counter += 1 Dim xP = Math.Round(location.GetRectangle.GetX) Dim yP = Math.Round(location.GetRectangle.GetY) ' 每次重新获取Image实例,避免复用问题 Using xmarkStream As New FileStream(xmarkImagePath, FileMode.Open, FileAccess.Read, FileShare.Read) Dim xmark As Image = Image.GetInstance(xmarkStream) xmark.SetAbsolutePosition(xP - 18, yP) pdfContentByte.AddImage(xmark) End Using Console.WriteLine($"{pattern} {xP} {yP} located on page {pageNum} and counter is {counter}") Next location End If Next pageNum ' 所有页面处理完成后再关闭stamper stamper.Close() End Using End Using End Using End Sub End Module
额外说明
我还添加了Using语句来自动管理流和PDF对象的资源,避免内存泄漏。这样修改后,应该能在所有匹配到的位置正确添加X标记,控制台也会输出所有定位到的坐标和页码。
内容的提问来源于stack exchange,提问作者user10349555
相关产品推荐
相关产品推荐

