当前位置: 首页 > 知识库问答 >
问题:

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

蒋俊
2023-03-14

我用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;
   }
}

共有1个答案

邹慈
2023-03-14

之所以会得到正确的泰米尔字母和错误的控制序列,是因为它们各自的字体不同

  • 没有ToUnicode映射和
  • 有一个使用非标准名称的编码条目。

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

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

更详细地说:

我将在这里用一个例子来说明这个问题。

在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 

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

此页面的字体R9没有ToUnicode地图。也没有任何实际的文本条目。因此,PDFBox只能使用字体的编码条目:

<<
  /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
>> 

正如您看到的,它首先声明了一个基本编码WinAnSienceODing,可以忽略它,因为字体使用的代码范围内的所有映射或多或少都会在差异数组中被替换。

在差异数组中,您可以找到

  • 一些标准名称,如逗号和两个

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 - ி

导致提取文本的第一行:

顺便说一下,这与实际PDF中的此部分相对应:

PDFBox提供了允许您将名称添加到已知名称映射中的机制。如果这些gXXX名称在文档中经常代表相同的相应字符,因此,您可以调整PDFBox文本提取以满足您的要求。

稳定的PDFBox版本1.8. X使用了与2.0.0版本候选版本不同的机制。因此:

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

A;0041
AE;00C6

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

java -Dglyphlist_ext=/path/to/my/extra/glyphs ...

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

在处理PDFBOX-2379时,如果发现上述系统属性,将引发异常

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

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

在使用PDFBOX-2380时,已将其拆除并更换:

我用getAdobeGlyphList()方法替换了静态默认glyph列表,因为一些PDFBox字体内部要求它是AGL,而不是其他一些额外的glyph列表。附加glyphlist的加载和使用是特定于应用程序的,因此已转移到PDFStreamEngine,在那里可以覆盖getGlyphList()方法,以将自定义glyph列表传递给字体。

不幸的是,PDFStreamEngine不再有getGlyphList方法。

我现在没有心情继续四处搜寻,以再次找到这一特征。阿格。

在评论中,OP问我如何从有问题的PDF文件中检索上述信息。

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

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

这些几乎就是我上面引用的指令。不过,正如你所看到的,不幸的是,字符串不能在这里检查,因为它们的内容大多在Unicode控制字符范围内。因此,我保存了内容流(右键单击,上下文菜单),并检查了这些指令的十六进制视图

使用这些信息,我创建了上面的说明引用。

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

这个我复制和美化了一些,以获得上面的编码引用。

根据这些信息,我手动创建了带有字形id的表(来自指示块中显示操作的文本)、相应的名称(来自编码差异)、假设的Unicode代码点(来自uXXXX名称,对于gXXX名称,再次使用字形id)和字符(来自互联网上许多Unicode表站点之一)。

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

 类似资料:
  • eclipse编译的结果类文件和传统的“javac”命令是不同的。所以我想在eclipse中编译Java源代码来得到它的特殊输出。还有,这个输出只能由eclipse自己打开(至少我不知道其他打开方式)。然而,打开这么多文件并将内容复制到记事本上是一项艰苦的工作。 那么,有没有其他方法可以自动读取eclipse生成的类文件呢?我猜控制台中有一些命令可以使用eclipse并自动输出结果? 谢谢

  • 问题内容: 如何使用该类从控制台读取输入?像这样: 基本上,我只需要让扫描程序读取用户名的输入,然后将输入分配给变量。 问题答案: 一个简单的例子来说明如何从中读取单个整数。这真的很简单。 要检索用户名,我可能会使用。 如果你想对输入进行更多控制,或者仅验证变量,也可以使用。 你可以在API文档中找到有关其实现的更多信息

  • 如何使用类从控制台读取输入?类似这样的事情: 基本上,我想要的只是让扫描器读取用户名的输入,并将输入赋给变量。

  • 问题内容: 当用户在Java中键入单个字符时,是否有一种简单的方法可从控制台读取它?可能吗?我尝试了这些方法,但是它们都在等待用户按Enter键: 我开始认为System.in在按下Enter之前不知道用户输入。 问题答案: 您要做的是将控制台置于“原始”模式(绕过行编辑且无需输入键),而不是“经烹煮”模式(需要输入键进行行编辑)。在UNIX系统上,“ stty”命令可以更改模式。 现在,关于Ja

  • 我已经建立了一个具有3个节点的Cassandra。在客户端,我使用的是Datasatx java驱动程序,我的查询如下 正如我们在上面的查询中看到的,我希望最大的“cluster_column”小于10。我有宽行。所以当数据在行间增长时,读取延迟会增加。 我只使用密钥缓存和级别压缩策略。MemTable大小保持为2048 MB。 我可以调整什么参数来降低服务器级别的读取延迟。 请回复 提前感谢

  • 有没有一种简单的方法可以在用户用Java输入时从控制台读取单个字符?有可能吗?我尝试过这些方法,但它们都要等待用户按enter键: 我开始认为System.in在按下enter之前并不知道用户的输入。