我有PDF,其中大量页面包含PII数据,如SSN。我需要在共享PDF之前用一些虚拟值替换SSN。我正在探索iText的用法,它是PDFCleanup插件。总的来说,该库在替换文本方面看起来很有希望。然而,我遇到了一个问题:
我可以编辑,即。从PDF的任何页面清除文本。但是,我只能替换第一页上的文本。任何后续页面的文本都不会被替换。
我的示例代码是:
private void replaceTextInDocument(PdfDocument pdfDocument, String textToReplace, String replacementText) throws IOException {
CompositeCleanupStrategy strategy = new CompositeCleanupStrategy();
strategy.add(new RegexBasedCleanupStrategy(textToReplace).setRedactionColor(ColorConstants.WHITE));
PdfCleaner.autoSweepCleanUp(pdfDocument, strategy);
System.out.println("----STRATEGY SIZE: " + strategy.getResultantLocations().size());
for (IPdfTextLocation location : strategy.getResultantLocations()) {
System.out.println("----PAGE #: " + location.getPageNumber() + " TEXT: " + location.getText());
PdfPage page = pdfDocument.getPage(location.getPageNumber() + 1);
PdfCanvas pdfCanvas = new PdfCanvas(page.newContentStreamAfter(), page.getResources(), page.getDocument());
Canvas canvas = new Canvas(pdfCanvas, location.getRectangle());
canvas.add(new Paragraph(replacementText).setFontSize(8).setMarginTop(0f)
.setRotationAngle(Math.toRadians(90))
);
}
}
字符串
调试发现,如果 textToReplace 存在于第一个页面以外的页面上,则 strategy.getResultantLocations() 的大小为0。因此,代码不会进入for循环来替换文本。
可能令人困惑的部分是PDFCleaner能够清理/编辑任何页面上的文本。
我不知道我是否错过了什么,或者这是图书馆的限制。我在网上看到的代码示例只使用一个分页PDF。
感谢和问候
- 编辑**我的问题,以添加更多信息,如@mkl的评论。与添加纯文本注解相比,在此处添加信息将提高可读性。此外,这将导致后续步骤和决议的连续性。
我在PoC阶段,运行一个独立的Java程序。
我探索了基于 RegexBasedLocationExtractionStrategy 创建自定义策略的选项。为了理解这一点,我调试了这个类。请参考RegexBasedLocationExtractionStrategy.getResultantLocations()方法中的代码
public Collection<IPdfTextLocation> getResultantLocations() {
// align characters in "logical" order
Collections.sort(parseResult, new TextChunkLocationBasedComparator(new DefaultTextChunkLocationComparator()));
// process parse results
List<IPdfTextLocation> retval = new ArrayList<>();
CharacterRenderInfo.StringConversionInfo txt = CharacterRenderInfo.mapString(parseResult);
Matcher mat = pattern.matcher(txt.text);
while (mat.find()) {
Integer startIndex = getStartIndex(txt.indexMap, mat.start(), txt.text);
Integer endIndex = getEndIndex(txt.indexMap, mat.end() - 1);
if (startIndex != null && endIndex != null && startIndex <= endIndex) {
for (Rectangle r : toRectangles(parseResult.subList(startIndex.intValue(), endIndex.intValue() + 1))) {
retval.add(new DefaultPdfTextLocation(0, r, mat.group(0)));
}
}
}
/* sort
* even though the return type is Collection<Rectangle>, we apply a sorting algorithm here
* This is to ensure that tests that use this functionality (for instance to generate pdf with
* areas of interest highlighted) will not break when compared.
*/
Collections.sort(retval, new PdfTextLocationComparator());
// ligatures can produces same rectangle
removeDuplicates(retval);
return retval;
}
型
- parseResults* 和随后的 txt.text 始终包含PDF第1页的内容,而不管PDF的哪一页包含 pattern。因此,mat.find() 的计算结果为false,因此不会执行 while() 循环。因此,retVal 中没有添加任何内容,结果 strategy.getResultantLocations() 返回0。
在这个阶段,我不能说 DefaultPdfTextLocation 的硬编码0是否是一个问题。
任何关于为什么会发生以下情况的想法或进一步调试的指针都将是有帮助的:
- 为什么 RegexBasedLocationExtractionStrategy 无法读取或添加第1页以外的页面内容。
1条答案
按热度按时间rkkpypqq1#
调试发现,如果textToReplace存在于第一个页面以外的页面上,strategy.getResultantLocations()的大小为0。因此,代码不会进入for循环来替换文本。
这一观察结果指出了问题的原因:在编校期间,每个页面都需要一个全新的清理策略。因此,调用所使用的清除策略的
reset
方法。您使用的两个策略类CompositeCleanupStrategy
和RegexBasedCleanupStrategy
都通过实际生成一个 new 示例并像初始化原始示例那样初始化它来实现该方法。因此,您在代码中拥有的策略对象只在第一页上使用,因此,只包含第一页上的结果位置。另一个问题是
RegexBasedCleanupStrategy
在其getResultantLocations
中在其生成和返回的所有DefaultPdfTextLocation
中使用恒定的页码'0'。因此,解决这个问题的一种方法是从
RegexBasedCleanupStrategy
中派生出自己的策略,使用一个额外的方法来检索 all 文本位置对象和所有重置示例的集合。在该方法中,所有示例都将被访问,它们的位置将被检索,并且它们各自的页码将被更正,并且在新集合中返回。reset
将用于生成策略类的示例,并管理所有示例的共享列表。