/**
* Write a Java string to the output stream. The default implementation will ignore the <code>textPositions</code>
* and just calls {@link #writeString(String)}.
*
* @param text The text to write to the stream.
* @param textPositions The TextPositions belonging to the text.
* @throws IOException If there is an error when writing the text.
*/
protected void writeString(String text, List<TextPosition> textPositions) throws IOException
{
writeString(text);
}
然后你的覆盖应该使用 List<TextPosition> textPositions 而不是 String text ;每个 TextPosition 本质上代表一个单个字母,并且在绘制该字母时活动图形状态的信息 .
不幸的是 textPositions 列表确实 not 包含当前版本1.8.3中的正确内容 . 例如 . 对于PDF中的行"This is normal text.",方法 writeString 被调用四次,每次为字符串"This"," is"," normal"和" text."不幸 textPositions 列表每次都包含 TextPosition 实例,用于最后一个字符串" text."的字母
public class CustomPDFTextStripper extends PDFTextStripper
{
public CustomPDFTextStripper() throws IOException {
super();
}
public Vector<List<TextPosition>> getCharactersByArticle(){
return charactersByArticle;
}
}
String [x:168.24,y:64.15997,身高:6.061287,空间:8.9664,宽度:3.4879303,yScale:8.9664] J String [x:171.69745,y:64.15997,身高:6.061287,空间:8.9664,宽度:2.2416077, yScale:8.9664] N String [x:176.25777,y:64.15997,身高:6.0343876,空间:8.9664,宽度:6.4737396,yScale:8.9664] N String [x:182.73778,y:64.15997,身高:4.214208,空间:8.9664,宽度:3.981079,yScale:8.9664] e .....
2 回答
一般程序和PDFBox问题
理论上,我们应该从
PDFTextStripper
派生一个类并重写它的方法来开始:然后你的覆盖应该使用
List<TextPosition> textPositions
而不是String text
;每个TextPosition
本质上代表一个单个字母,并且在绘制该字母时活动图形状态的信息 .不幸的是
textPositions
列表确实 not 包含当前版本1.8.3中的正确内容 . 例如 . 对于PDF中的行"This is normal text.",方法writeString
被调用四次,每次为字符串"This"," is"," normal"和" text."不幸textPositions
列表每次都包含TextPosition
实例,用于最后一个字符串" text."的字母事实证明,这已经被认为是PDFBox问题PDFBOX-1804,同时已经解决为1.8.4和2.0.0版本的固定问题 .
有人说,只要你有一个固定的PDFBox版本,你可以检查一些人工样式,如下所示:
人工斜体文字
此文本样式在页面内容中创建如下:
相关部分发生在设置文本矩阵 Tm 中 . 5.10137是剪切文本的一个因素 .
当您检查
TextPosition textPosition
时,如上所示,您可以使用查询此值如果此值大于0.0,则表示人为斜体 . 如果它相关地小于0.0,则会有人为的倒退斜体 .
人工粗体或大纲文字
这些人工样式使用不同的渲染模式使用双重打印字母;例如首都'T',如果是粗体:
(即首先以常规模式绘制字母,填充字母区域,然后以轮廓模式绘制,沿着字母边框绘制一条线,均为黑色,CMYK 0,0,0,1;这留下了印象更粗的字母 . )
如果是大纲:
(即首先以常规模式白色绘制字母,CMYK 0,0,0,0,填充字母区域,然后以轮廓模式绘制,沿字母边框绘制一条线,黑色,CMYK 0,0,0 ,1;这会在白色字母上留下轮廓黑色的印象 . )
不幸的是,PDFBox
PDFTextStripper
没有跟踪文本渲染模式 . 此外,它明确地在大致相同的位置丢弃重复的字符出现 . 因此,它不能承认识别这些人造风格 .如果你真的需要这样做,你必须更改
TextPosition
以包含渲染模式,PDFStreamEngine
将其添加到生成的TextPosition
实例,并且PDFTextStripper
不要删除processTextPosition
中的重复字形 .更正
我写
这不完全正确,您可以使用
getGraphicsState().getTextState().getRenderingMode()
找到当前的渲染模式 . 这意味着在processTextPosition
期间,您确实可以使用渲染模式,并且可以尝试在某处给出给定TextPosition
的渲染模式(和颜色!)信息,例如在某些Map<TextPosition, ...>
中,供以后使用 .您可以通过调用
setSuppressDuplicateOverlappingText(false)
来禁用此功能 .通过这两个更改,您应该能够进行必要的测试以检查人工粗体和轮廓 .
如果您在
processTextPosition
早期存储和检查样式,则甚至可能不需要后一种更改 .如何检索渲染模式和颜色
正如在更正中所提到的,通过在
processTextPosition
覆盖中收集该信息,确实可以检索渲染模式和颜色信息 .对此,OP评论说
这开始有点令人惊讶,但在看了
PDFTextStripper.properties
之后在文本提取期间支持的运算符被初始化),原因变得清晰:因此,在此上下文中忽略颜色设置操作符(尤其是如本文档中的CMYK颜色的操作符)!幸运的是,
PageDrawer
的这些运算符的实现也可以在这种情况下使用 .因此,以下概念验证显示了如何检索所有必需的信息 .
使用此功能,您可以获得周期' . '在正常文本中:
你会得到人工粗体文字;
在人造斜体:
在人工轮廓中:
所以,你有,识别这些人工风格所需的所有信息 . 现在你只需要分析数据 .
顺便说一句,看看人工大胆的情况:坐标可能并不总是相同,而是仅仅非常相似 . 因此,测试是否需要一些宽容来确定两个文本位置对象是否描述相同的位置 .
我解决这个问题的方法是创建一个扩展PDFTextStripper类的新类并覆盖该函数:
注意:PDFBox版本1.8.5
CustomPDFTextStripper class
这样我就可以解析pdf文档,然后从自定义提取函数中获取TextPosition:
TextPositions包含有关pdf文档字符的大量信息 .
OUTPUT: