Java 为什么我的PDF中有不可见的字符?我如何用PDFBox过滤掉它们?

Java 为什么我的PDF中有不可见的字符?我如何用PDFBox过滤掉它们?,java,pdfbox,Java,Pdfbox,我使用PDFBox通过扩展从文档中提取文本。我注意到其中一些文档包含正在提取的不可见字符。我想过滤掉这些看不见的字符 我看到在这方面已经有一些stackoverflow帖子,例如: 我尝试对PDFVisibleTextStripper类进行子类化,发现如下: 然而,我发现这个过滤掉的文本实际上是可见的。我用它来代替PDFTextStripper package com.example.foo; 导入org.apache.pdfbox.pdmodel.PDDocument; 导入or

我使用PDFBox通过扩展从文档中提取文本。我注意到其中一些文档包含正在提取的不可见字符。我想过滤掉这些看不见的字符

我看到在这方面已经有一些stackoverflow帖子,例如:

我尝试对
PDFVisibleTextStripper
类进行子类化,发现如下:

然而,我发现这个过滤掉的文本实际上是可见的。我用它来代替
PDFTextStripper

package com.example.foo;
导入org.apache.pdfbox.pdmodel.PDDocument;
导入org.apache.pdfbox.text.PDFTextStripper;
导入org.apache.pdfbox.text.TextPosition;
导入java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.io.OutputStreamWriter;
导入java.io.Writer;
导入java.util.List;
公共类ExtractChars扩展PDFVisibleTextStripper{
处理器;
公共静态无效提取(PDDocument文档、处理器)引发IOException{
ExtractChars实例=新建ExtractChars();
instance.processor=处理器;
实例.setSortByPosition(true);
实例.setStartPage(0);
setEndPage(document.getNumberOfPages());
ByteArrayOutputStream=新建ByteArrayOutputStream();
Writer streamWriter=新的OutputStreamWriter(流);
writeText(文档,streamWriter);
}
ExtractChars()引发IOException{}
受保护的void writeString(String _String,List textPositions)引发IOException{
用于(文本位置文本:文本位置){
浮动高度=text.getHeightDir();
String character=text.getUnicode();
int pageIndex=getCurrentPageNo()-1;
float left=text.getXDirAdj();
float right=left+text.getWidthDirAdj();
float bottom=text.getYDirAdj();
浮动顶部=底部-高度;
BoundingBox=新的边界框(页面索引、左、右、上、下);
此.processor.process(字符、方框);
}
}
公共接口处理器{
作废处理(字符串、边框);
}
}
我不知道在我的子类中是否有什么需要修改的地方,以使其正确工作。如果有帮助的话,我可以提供一个展示这种行为的PDF,尽管它包含敏感内容,所以我需要先删除它

相反,我创建了一个最小的示例(如下),展示了我所看到的“看不见的文本”行为。项目符号列表在'24'末尾包含一个项目。a、 '可以在PDF查看器(如macOS预览和复制粘贴)中突出显示

此“a.”当前正由
PDFTextStripper
提取,我不希望这样。我真的不明白为什么会这样。我的猜测可能与剪辑有关,但如果有人能解释发生了什么,我将不胜感激

我的最终目标是过滤掉这些字符,因此如果您对我如何以最简单的方式处理这个具体案例有任何建议,我们将不胜感激。我不认为我需要
PDFVisibleTextStripper
中的所有常规方法

非常感谢

%PDF-1.3

1 0 obj
<<
  /Type /Catalog
  /Pages 2 0 R
>>
endobj

2 0 obj
<<
  /Type /Pages
  /Kids [3 0 R]
  /Count 1
  /MediaBox [0 0 612 792]
>>
endobj

3 0 obj
<<
  /Type /Page
  /Parent 2 0 R
  /Resources 4 0 R
  /Contents 6 0 R
  /MediaBox [0 0 612 792]
>>
endobj

4 0 obj
<<
  /Font <<
    /TT2 5 0 R
  >>
>>
endobj

5 0 obj
<<
  /BaseFont
  /OXRDVC+Helvetica
  /Subtype /TrueType
  /Type /Font
>>
endobj

6 0 obj
<<
>>
stream
q 0 54 612 648 re W n /Cs1 cs 0 0 0 sc
q 1 0 0 0.8181818 0 54 cm Q
q 48 93.30545 516 569.4218 re W n /Cs1 cs 1 1 1 sc 48 93.30545 516 569.4218 re f 0 0 0 sc
q 1 0 0 0.8181818 0 54 cm BT 7.99 0 0 7.99 66.86 589.28 Tm /TT2 1 Tf (24.  ) Tj ET Q
q 1 0 0 0.8181818 0 54 cm BT 7.99 0 0 7.99 96.86 40.39 Tm /TT2 1 Tf (a.  ) Tj ET Q 
endstream
endobj

trailer
<<
  /Root 1 0 R
>>

%%EOF
%PDF-1.3
10 obj
>
endobj
20 obj
>
endobj
30 obj
>
endobj
40 obj
>>
endobj
50 obj
>
endobj
60 obj
>
流动
q 0 54 612 648 re W n/Cs1 cs 0 0 sc
q 1 0 0.81818 0 54厘米q
q 48 93.30545 516 569.4218 re W n/Cs1 cs 1 1 sc 48 93.30545 516 569.4218 re f 0 0 sc
q 1 0 0 0.81818 0 54厘米BT 7.99 0 7.99 66.86 589.28 Tm/TT2 1 Tf(24.)Tj ET q
q 1 0 0 0.81818 0 54厘米BT 7.99 0 7.99 96.86 40.39 Tm/TT2 1 Tf(a.)Tj ET q
尾流
endobj
拖车
>
%%EOF

我知道发生了什么。PDF包含不包含“a”的剪切矩形。我试着使用
PDFVisibleTextStripper
,但它在其他文档的其他地方剥离了实际上可见的文本

最后,我编写了一个继承自
PageDrawer
的类,并实现了
showGlyph
方法来访问页面上绘制的字符。此方法检查字符的边界框是否在
getGraphicsState().getCurrentClippingPath().getBounds2D()
之外

不幸的是,这意味着我不再使用
PDFTextStripper
,因此我必须重新实现它的一些行为,例如按位置对字符进行排序(我使用的是
setSortByPosition(true)
)。根据字体大小和位移计算字符的正确边界框也有点棘手

ExtractChars.java

package com.example.foo;
导入org.apache.pdfbox.pdmodel.*;
导入org.apache.pdfbox.pdmodel.font.*;
导入org.apache.pdfbox.rendering.*;
导入org.apache.pdfbox.util.*;
导入org.apache.pdfbox.util.Vector;
导入java.awt.geom.*;
导入java.io.*;
//此类有效地呈现PDF文档以提取其内容
//文本。它截取PageDrawer提供的showGlyph函数。我们过去
//使用PDFTextStripper,但无法排除剪裁字符。
公共类ExtractChars扩展PageDrawerRhelper{
//跳过小于此高度的错误字符。这可能永远不会发生
//但是代码中有些地方是按高度划分的,所以要小心。
静态最终浮动最小字符高度=0.01f;
处理器;
ExtractChars(PageDroperParameters参数、浮点pageHeight、int pageIndex、处理器)引发IOException{
超级(参数、页面高度、页面索引);
this.processor=处理器;
}
//我们无法将此方法向上移动到超类,因为渲染器是
//每次都不同。它需要构建当前类的实例。
公共静态无效提取(PDDocument文档、处理器)引发IOException{
渲染器=新的渲染器(文档);
proc.proc