如何使用java读取pdf中的控制字符

Bha*_*abu 0 java control-characters pdfbox

我正在使用PDFBox来阅读PDF文件.但有些字符打印效果不佳,打印效果与控制字符类似.有人帮助从控制字符中读取值.我附上了图片请看看那个图片示例PDF:

截图:

在此输入图像描述 示例代码

class PDFManager {

   private PDFParser parser;
   private PDFTextStripper pdfStripper;
   private PDDocument pdDoc ;
   private COSDocument cosDoc ;

   private String Text ;
   private String filePath;
   private File file;

   public PDFManager() {

   }

   public String ToText() throws IOException {
       this.pdfStripper = null;
       this.pdDoc = null;
       this.cosDoc = null;
       file = new File(filePath);
       parser = new PDFParser(new FileInputStream(file));

       parser.parse();
       cosDoc = parser.getDocument();
       pdfStripper = new PDFTextStripper(); 
       pdDoc = new PDDocument(cosDoc);  
       pdDoc.getNumberOfPages();
       pdfStripper.setStartPage(3);
       pdfStripper.setEndPage(4); 
       Text = pdfStripper.getText(pdDoc);

       return Text;
   }

   public void setFilePath(String filePath) {
       this.filePath = filePath;
   }
}
Run Code Online (Sandbox Code Playgroud)

mkl*_*mkl 6

你得到正确的泰米尔语字母和不正确的控制序列的原因是相应的字体

  • 没有ToUnicode地图和
  • 有一些编码条目使用非标准名称的某些字形.

在这种情况下,PDFBox无法在没有帮助的情况下正确提取关联字符.

为了帮助PDFBox,您必须检查每个非标准名称的所有文档(或至少在一个足够大的子集中),绘制的字形是否相同.如果是这种情况,您可以告诉PDFBox将这些名称中的每一个的映射添加到分别绘制到其已知字形映射库的字母的Unicode值.

更详细:

问题

我将通过一个例子来说明这个问题.

在OP提到的第3页上,第一个文本是使用相当于这些的指令绘制的:

/R9 8.04 Tf
0.999418 0 0 1 519.6 791.721 Tm
[<01>6.75242<0C>-0.371893<0D>4.89295<07>3.77727<14>-6.13989<35>-4.51376<02>-5.00233<0F>187.988]TJ 
Run Code Online (Sandbox Code Playgroud)

(我只是将字符串的表示形式更改为十六进制,因为单个代码大部分位于控制字符范围内,因此在此处无法正确显示.)

此页面的字体R9没有ToUnicode地图.也没有任何ActualText条目.因此,PDFBox只能使用字体的Encoding条目:

<<
  /BaseEncoding/WinAnsiEncoding
  /Differences[1
    /u0BC6/u0B9A/g125/u0BC8/u0BA9/g121/u0B9F/u0BAE
    /u0BB1/g123/space/u0BA4/u0BBE/g148/u0BBF/u0B8E
    /g122/u0BAA/u0BAF/g129/g130/g178/g127/u0B92
    /g162/g116/u0B95/u0BC0/g158/u0BA8/u0BB2/colon
    /u0B85/g117/g173/g132/u0BB3/g182/g142/one
    /period/g175/u0BB5/u0BB0/g126/u0B86/u0BC7/g186
    /g156/g131/g143/two/g118/g133/g190/hyphen
    /zero/five/g171/g120/g146/g169/g152/parenleft
    /seven/parenright/three/g180/u0BA3/eight/g136/u0BB4
    /u0B9C/four/six/g124/nine/g135/slash/g172
    /comma/u0B87/numbersign/g128/g147/g160/u0B9E/u0B89
    /u0BB7/g119/g157/g167/g191/g188/g170/g145
    /g181/u0BB8/u0B90/uni25CC/u0BCD/u0BB9/u0BC1/u0B88
    /g163/u0BD7/g184/u0B8F/g174/g153/g138/g185
    /g134/g149/g176]
  /Type/Encoding
>> 
Run Code Online (Sandbox Code Playgroud)

如你所见,它首先声称一个编码WinAnsiEncoding的基本编码,可以忽略它,因为在差异数组中,或多或少地取代了字体使用的代码范围内的所有映射.

差异数组中,您可以找到

  • 一些标准名称,如逗号两个 ;
  • 许多使用该uXXXX方案表示unicode代码点的名称,如u0BC6u0B9A ;
  • 一个名称代表使用该uniXXXX方案的unicode代码点:uni25CC ; 和
  • 许多使用g121g176gXXX等方案的完全非标准名称.

PDFBox支持标准名称(显然),另外还使用了unicode代码点命名变体(通常可以找到并且解释非常简单).

它不支持开箱即用的其他名称.

因此,为第一个文本绘制指令提取的文本是:

<01> - /u0BC6 - 0BC6 - ?
<0C> - /u0BA4 - 0BA4 - ?
<0D> - /u0BBE - 0BBE - ?
<07> - /u0B9F - 0B9F - ?
<14> - /g129 ?? 0014 - <DEVICE CONTROL FOUR>
<35> - /g118 ?? 0035 - 5
<02> - /u0B9A - 0B9A - ?
<0F> - /u0BBF - 0BBF - ?
Run Code Online (Sandbox Code Playgroud)

导致您的第一行提取文本:

提取文本的第一行

顺便说一句,这对应于实际PDF中的这一部分:

匹配PDF内容

一种允许适当提取的可能方法

PDFBox提供了允许您向其已知名称的地图添加名称的机制.因此,如果这些gXXX名称在文档中定期表示相同的字符,则可以调整PDFBox文本提取以满足您的要求.

稳定的PDFBox版本1.8.X使用与2.0.0版本候选版本不同的机制.从而:

对于PDFBox 1.8.X,您必须创建一个字形列表文本文件.对于每个字形,它包含一行,带有2个以分号分隔的字段,字形名称和Unicode标量值,例如

A;0041
AE;00C6
Run Code Online (Sandbox Code Playgroud)

然后定义glyphlist_ext指向该列表的系统属性,例如在启动程序时

java -Dglyphlist_ext=/path/to/my/extra/glyphs ...
Run Code Online (Sandbox Code Playgroud)

对于PDFBox 2.0.0,这个机制已经被多次替换和移动,我不知道哪个是当前的.

在处理PDFBOX-2379时,如果找到上述系统属性,则会引入异常:

throw new UnsupportedOperationException("glyphlist_ext is no longer supported, "
    + "use GlyphList.DEFAULT.addGlyphs(Properties) instead");
Run Code Online (Sandbox Code Playgroud)

不幸的是GlyphList,不再有那种方法addGlyphs了.

在处理PDFBOX-2380时,它已被删除并替换:

我已经用getAdobeGlyphList()方法替换了静态DEFAULT字形列表,因为一些PDFBox字体内部要求它是AGL而不是其他一些额外的字形列表.附加字形表的加载和使用是特定于应用程序的,因此已移至PDFStreamEngine,其中可以重写getGlyphList()方法以将自定义字形列表传递给字体.

不幸的是,PDFStreamEngine没有那种getGlyphList方法了.

而且我目前还没有心情继续追寻高低再次找到这个功能.精氨酸.

制作

在评论中,OP询问我如何从相关PDF文件中检索上述信息.

首先,我使用PDF内部浏览应用程序,例如iText RUPSPDFBox PDFDebugger,来检查PDF和PDF规范ISO 32000-1,以了解我正在检查的内容.

OP特别指出了他的文档的第3页,因此我在内容流(参见ISO 32000-1第7.8.2节)中查找了第一个显示运算符的文本(参见ISO 32000-1第9.4.3节).那页(参见ISO 32000-1第7.7.3.3节):

RUPS第3页内容

这几乎是我上面引用的说明.但是,正如您所看到的,遗憾的是,字符串在此处无法检查,因为它们的内容主要位于Unicode控制字符范围内.因此,我保存了内容流(右键单击,上下文菜单)并检查了这些指令的十六进制视图

Hex第3页内容

使用这些信息,我创建了上面的说明报价.

在这些说明中选择的字体(参见ISO 32000-1第9.6节)是R9(参见ISO 32000-1第9.3.1节),所以我继续查看字体资源(参见ISO 32000-1第7.8节). 3)在第3页上使用该名称,首先搜索ToUnicode条目失败(参见ISO 32000-1第9.10.3节),然后成功找到编码(参见ISO 32000-1第9.6.6节):

RUPS第3页字体R9编码

这个我复制并且在某种程度上可以获得上面的编码引用.

根据这些信息,我手动创建了带有字形id的表(来自显示指令块中操作的文本),相应的名称(来自编码差异),假定的unicode代码点(源自uXXXX名称,gXXX命名字形)再次id)和角色(来自互联网上许多Unicode表站点之一).

为了从实际的PDF页面中找到相应的部分,我采用了Tm文本矩阵设置操作的最后两个参数(参见ISO 32000-1第9.4.2节),采用聚合变换矩阵的变化(参见ISO 32000-1第8.4节)考虑到.这些是由显示指令的以下文本绘制的文本基线起点的坐标.