如何逐行从BT和ET部分提取pdf文本以及如何在pdfbox中将Tj块解码为unicode

时间:2016-06-29 06:23:09

标签: extract cdi pdfbox decoding

作为标题,我有特殊要求逐行或逐块提取文本和BT。 下面是pdf内容,我试过PDFTextstripper类,但它不是我想要的, 所以任何人都有解决问题的方法? 我想解析一下:[ (=\324Z\016) ] TJ.......

enter image description here

这是我的pdf:https://dl.dropboxusercontent.com/u/63353043/docu.pdf

下面是我的代码:

  enter coList<Object> tokens = pages.get(0).getContents().getStream().getStreamTokens();


            tokens.forEach(s->{
                if(s instanceof COSString){
                    System.out.print(s.toString());
                }

但是,我得到了: COSString {&安培; d} COSString {O6} COSString {&安培;³} COSString {P»} COSString {6±} COSString {˛¨} COSString {+ ^} COSString {+·} COSString {˚©} COSString {9} COSString {Ø©} {COSString EN} {COSString}˛¨{COSString敌人} {COSString 0L} {COSString Q} {COSString#”} {COSString}˛¨{COSString + ^} {COSString(I} {COSString˚ ©} COSString {9} COSString {ö©} COSString {烯} COSString {咗} COSString {#°} COSString {〜} COSString {p»} COSString {#S} {COSString 5×} COSString {, } {COSString:É} {COSString(U} {COSString 4Y} COSString {A} {COSString _A} {COSString}˛¨{COSString:É} {COSString P»} {COSStringØ©} {COSString EN} {COSString# p} COSString {/ F} COSString {Ø©} COSString {EN} COSString {F,} COSString {_N} COSString {!} COSString {9»} COSString {]˘} COSString {!¢} COSString {〜} COSString {p»} COSString {#°} COSString {〜} COSString {#P} COSString {&LT;:}!COSString {咗} COSString {1} COSString {A} {COSString˚〜} COSString {F³} COSString {Ø } COSString {] S} COSString {2}COSString{6±}COSString{˛¨}COSString{gî}COSString{+·}COSString{9á}COSString{XS}COSString{hP}COSString{h[}COSString{˜º}COSString{˚.}COSString{p»}COSString{5d}COSString{5×}COSString{]˘}COSString{_ö}COSString{#c}COSString{2˚}COSString{]˜}COSString{+·}COSString{9á}COSString{p»}COSString{@b}COSString{˚.}COSString{eÚ}COSString{; }COSString{!5}COSString{:É}COSString{XS}COSString{hP}COSString{h[}COSString{˜º}COSString{p»}COSString{B!}COSString{&Ø}COSString{,} COSString {/ F} COSString {^ R} COSString {2} COSString {2安培;} COSString {〜} COSString {N} COSString {*ø} COSString {〜} COSString {&安培;¢} COSString {+ B} COSString {+·} COSString {9A} COSString {A} COSString {ZX} COSString {˚} COSString {˛μ} COSString {6«} COSString {0L} COSString {O!} COSString {p»} COSString {Ø©} COSString {EN} COSString {F,} COSString {Q±} COSString {“}} COSString {XS} COSString {&安培; d} COSString {_N} COSString { !} {COSString 9»} {COSString²} COSString {F,} {COSString(I} {COSStringØ©} {COSString EN} {COSString}F³{COSString /?} {COSString˛¨}℃ OSString {=} COSString {˚4} COSString {9} COSString {P»} COSString {;} COSString {5}×{COSString _A} COSString {~³} COSString {@É} COSString {0·} COSString {F, } COSString {Q±} COSString {“}} COSString {p»} COSString {1U} COSString {”}} COSString {˚} COSString {ö©} COSString {烯} COSString {p»} COSString {#°} COSString {〜} COSString {Lê} COSString {5D} COSString {咗} COSString {1} COSString {“G} COSString {˚} COSString {A} COSString {&安培; d} COSString {KA} COSString {Yª} COSString { #°} COSString {#'} COSString {5E} COSString {p»} COSString {(I} COSString {ö©} COSString {烯} COSString {ZR} COSString {PE} COSString {p“} COSString {〜} COSString { G“} {COSString} _U {COSString%v} COSString {PI} COSString {1U} COSString {“}} {COSString}并-1'COSString {F,} COSString {˛μ} COSString {5}×{COSString〜} COSString { 2˚} COSString {]〜} COSString {+}·{COSString 9A} COSString {p»}COSString{O'}COSString{5×}COSString{@b}COSString{˚.}COSString{+·}COSString{9á } COSString {p»} COSString {〜} COSString {] Y} COSString {/ 0} COSString {}COSString{2§}COSString{˚.}COSString{˛¨}COSString{8E}COSString{N}COSString{*ø}COSString{22}COSString{++}COSString{&¢}COSString{+B}COSString{)%}COSString{ä}COSString{&Ð}COSString{!Í}COSString{˚b}COSString{f¨}COSString{Y)}COSString{.}COSString{"Q}COSString{5ê}COSString{p»}COSString{)*}COSString{7D}COSString{˛¨}COSString{˜³}COSString{˚b}COSString{P¥}COSString{&Ð}COSString{!Í}COSString{˚b}COSString{˛µ}COSString{G“}COSString{0m}COSString{F,}COSString{0m}COSString{<i}COSString{˛³}COSString{p»}COSString{;fi}COSString{˛µ}COSString{BÞ}COSString{\}COSString{F,}COSString{BO}COSString{Bˆ}COSString{Q™}COSString{-Ž}COSString{F,}COSString{!Ñ}COSString{Fr}COSString{p»}COSString{$™}COSString{/½}COSString{BO}COSString{Bˆ}COSString{F,}COSString{#™}COSString{5×}COSString{˛¨}COSString{nƒ}COSString{nƒ}COSString{p»}COSString{˚}COSString{5×}COSString{f‰}COSString{P¥}COSString{#Š}COSString{\\}COSString{F,}COSString{p°}COSString{1¹}COSString{<:}COSString{6±}COSString{C®}COSString{DÙ}COSString{˛µ}COSString{Q¯}COSString{_Á}COSString{9Ë}COSString{F,}COSString{˚b}COSString{#°}COSString{˜}COSString{p»}COSString{_Á}COSString{9Ë}COSString{F,}COSString{˚b}COSString{˚}COSString{<:}COSString{6±}COSString{C®}COSString{DÙ}COSString{˛µ}COSString{Cˆ}COSString{/?}COSString{1¸}COSString{"G}COSString{p°}COSString{p“}COSString{/4}COSString{˜.}COSString{p»}COSString{+·}COSString{O©}COSString{en}COSString{F,}COSString{˚3}COSString{9}COSString{7D}COSString{@Þ}COSString{DÙ}COSString{;}COSString{T} {COSString} T` {COSString 5“ } COSStri ng {˛²} COSString {p»} COSString {] 2} COSString {} COSString {] 2} COSString {(Ï} COSString {p°} COSString {:} COSString {6«} COSString {Må} COSString {&amp; d} COSString {˛μ} COSString {M;} COSString {0}·{COSStringë;} COSString {ö«} COSString {AW} COSString {B} COSString {F,} COSString {FC} COSString {ZH} < / p>

1 个答案:

答案 0 :(得分:1)

(如果这不是很长,那么作为对问题的评论而不是答案会更合适。但评论太有限了。)

他的问题中的OP表明他基本上想要解析例如的内容流。页面并提取以清晰易读的形式绘制的字符串。他通过简单地在内容流中获取令牌并查看其中的COSString个实例来尝试此操作:

List<Object> tokens = pages.get(0).getContents().getStream().getStreamTokens();

tokens.forEach(s->{
    if (s instanceof COSString) {
        System.out.print(s.toString());
    }
});

不幸的是输出看起来很乱。

为什么内容流中的字符串值看起来如此混乱?

这样做的原因是那些COSString实例按原样表示PDF字符串对象,并且内容流中没有PDF字符串对象的单一编码,甚至不限制几个标准化的字符串对象。

字符串的编码完全取决于执行相关字符串绘制指令时当前活动字体的定义。

PDF中的字体可以定义为使用某种标准编码或自定义编码,并且特别是在嵌入字体子集的情况下,使用与此类似的构造的自定义编码映射非常常见:

  • 代码1到该字体的字形,首先在页面上使用
  • 页面上该字体的第二个字形的代码2与第一个字体不相同,
  • 页面上此字体的第三个到第三个字形的代码与前两个字体中的任何一个都不相同,
  • 等...

显然,对这种编码推测字符串字节的含义是没有好处的。

因此,在解析内容流时,您必须跟踪当前字体并查找当前字体定义中COSString的每个字节(或多字节序列!)的含义。当前页面的资源字典。

如何使用当前字体定义映射那些杂乱的字节?

PDF字体的编码可能必须以不同的方式确定。

  • 字体定义中可能有一个 ToUnicode 地图,显示要映射到哪个字符的字节。
  • 否则编码可能是标准编码,如 MacRomanEncoding WinAnsiEncoding ,在这种情况下,必须自带一个映射表(它们在PDF规范中打印)
  • 否则编码可能基于这样的标准编码,但是从代码到字形的名称的映射给出了偏差。如果使用某些标准名称,则可以从该名称派生该字符。这些名称列在另一份文件中。
  • 否则,某些 CIDSystemInfo 条目可能指向另一个标准的Registry和Ordering,从中导出其他文档中指定的映射表。
  • 否则,字体程序本身可能包含对Unicode的可用映射。
  • 否则???

任何逃避的陷阱?

当前字体是PDF图形状态属性。因此,人们不仅要记住最近设置的字体,还要考虑改变整个图形状态的操作的效果,特别是将当前图形状态推送到a的save-graphics-state和restore-graphics-state操作。从那里堆叠或弹出它。

PDF库如何为您提供帮助?

支持文本提取的PDF库可以通过为您完成所有繁重工作来实现,

  • 解析内容流
  • 跟踪图形状态,
  • 确定当前字体的编码,
  • 使用该编码翻译任何绘制的PDF字符串,

并且仅向您转发结果字符和一些额外数据(页面上的当前位置,文本绘图方向,字体和字体大小,颜色和其他效果)。

对于PDFBox 2.0.x,这就是PDFTextStreamEngine类为您所做的事情:您只需覆盖其processTextPosition方法,PDFBox会将TextPosition转换为{{1}中的那些丰富字符信息参数。由于您还想知道 BT ... ET 文字对象信封的开头和结尾,您还必须覆盖beginText和{{1} }。

endText基于该类,并收集和排序这些字符信息位以构建包含最终返回的页面文本的字符串。

在PDFBox 1.8.x中有一个非常相似的PDFTextStripper类,但基本方法在基类中没有正确分离,所有内容都有点混合,实现自己的更难提取方式。

(在其他PDF库中,有类似的构造,有时基于事件,如PDFBox,有时候是收集的PDFTextStripper类似对象的序列。)