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