上下文
目前,我有一个解决方案,我通过一个pdf循环,并绘制黑色矩形贯穿其中。
所以我已经有了一个pdrectangle列表,它代表了我需要在pdf上填充/覆盖的正确区域,隐藏了我想要的所有文本。
问题
问题1:黑色矩形下面的文本很容易被其他工具复制、搜索或提取。
我解决了这个问题,我把我的pdf(转换成一个图像,使它成为一个单层文件和黑色矩形不再被欺骗)。与这里描述的解决方案相同:使用pdfbox禁用pdf文本搜索
这不是一个真正的修订,它更像是一个变通办法。这让我想到
问题2:
我最后的pdf变成了一个图像文档,在那里我失去了所有的pdf属性,包括搜索,复制。。。而且这个过程要慢得多。我想保留所有的pdf属性,而被编辑的区域无论如何都不可读。
我想要完成的
也就是说,我想知道是否有可能,我如何可以做一个实际的编校,涂黑矩形区域,因为我已经有了所有的位置,我需要,与pdfbox,保持pdf属性,不允许编辑区域被读取。
注意:我知道pdfbox在使用旧的replacetext函数时遇到的问题,但是在这里我有我需要的位置来确保我精确地清空了我需要的区域。
另外,我还接受其他免费图书馆的建议。
技术规格:
pdfbox 2.0.21版
java 11.0.6+10,采用OpenJDK
macos catalina 10.15.4,16gb,x86\U 64
我的代码
我是这样画黑色矩形的:
private void draw(PDPage page, PDRectangle hitPdRectangle) throws IOException {
PDPageContentStream content = new PDPageContentStream(pdDocument, page,
PDPageContentStream.AppendMode.APPEND, false, false);
content.setNonStrokingColor(0f);
content.addRect(hitPdRectangle.getLowerLeftX(),
hitPdRectangle.getLowerLeftY() -0.5f,
hitPdRectangle.getUpperRightX() - hitPdRectangle.getLowerLeftX(),
hitPdRectangle.getUpperRightY() - hitPdRectangle.getLowerLeftY());
content.fill();
content.close();
}
以下是我如何将其转换为图像pdf:
private PDDocument createNewRedactedPdf() throws IOException {
PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
PDDocument redactedDocument = new PDDocument();
for (int pageIndex = 0; pageIndex < pdDocument.getNumberOfPages(); pageIndex++) {
BufferedImage image = pdfRenderer.renderImageWithDPI(pageIndex, 200);
String formatName = "jpg";
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, formatName, baos);
byte[] bimg = baos.toByteArray();
PDPage page = pdDocument.getPage(pageIndex);
float pageWidth = page.getMediaBox().getWidth();
float pageHeight = page.getMediaBox().getHeight();
PDPage pageDraw = new PDPage(new PDRectangle(pageWidth, pageHeight));
redactedDocument.addPage(pageDraw);
String imgSuffixName = pageIndex + "." + formatName;
PDImageXObject img = PDImageXObject.createFromByteArray(redactedDocument, bimg,
pdDocument.getDocument().getDocumentID() + imgSuffixName);
try (PDPageContentStream contentStream
= new PDPageContentStream(redactedDocument, pageDraw, PDPageContentStream.AppendMode.OVERWRITE, false)) {
contentStream.drawImage(img, 0, 0, pageWidth, pageHeight);
}
}
return redactedDocument;
}
有什么想法吗?
1条答案
按热度按时间vql8enpb1#
你想要的,一个真正的编校功能,是可以基于pdfbox实现的,但是它需要在它之上进行大量的编码(类似于在itext之上实现的pdfsweep插件)。
特别是你已经发现,仅仅在要编辑的区域上画黑色矩形是不够的,因为从查看器中提取文本或复制粘贴文本通常完全忽略文本是可见的还是被某些内容覆盖的。
因此,在代码中,您必须找到实际的指令来绘制要编辑和删除的文本。但是您不能简单地删除它们而不进行替换,否则同一行上的其他文本可能会被您的密文移动。
但是,不能简单地用相同的空格数替换它们,也不能将它们向右移动删除的文本的宽度:只需考虑一个表的情况,即您只想用“yes”和“no”两个条目对列进行修订。如果在编辑后,文本提取器返回三个空格,其中有一个“是”和两个空格,其中有一个“否”,任何人看到这些结果都知道在编辑区域有什么。
您还必须清理围绕实际文本绘制说明的说明。再看一次用“yes”/“no”信息编辑的列的例子,但是为了更清楚起见,“yes”用绿色绘制,“no”用红色绘制。如果只替换文本绘制说明,则具有同样提取颜色等属性的提取器的人将立即知道已编辑的信息。
如果是带标签的PDF,也必须检查标签属性。尤其是有一个属性actualtext,它包含由标记指令表示的实际文本(特别是对于屏幕阅读器)。如果您只删除了文本绘制说明,而保留了标签及其属性,那么使用屏幕阅读器阅读的任何人都可能没有意识到,在屏幕阅读器向他阅读完整的原始文本时,您试图对某个内容进行编校。
因此,为了进行适当的编校,您必须解释所有当前指令,确定它们所绘制的实际内容,并创建一组新的指令,这些指令可以绘制相同的内容,而不需要额外的指令,这些指令可能会泄露编校内容的某些信息。
在这里我们只看了修改文本;在pdf页面上编校矢量和位图图形对于正确编校有着相似的挑战。
...
因此,实际编校所需的代码超出了堆栈溢出答案的范围。尽管如此,上面的项目可以帮助实现编校器的人避免落入编校代码过于幼稚的典型陷阱。