5

我正在尝试根据其坐标从 PDF 文档中提取文本,因此我在Adob​​e PDF Reference(第 5.3 章)中遇到了两个概念:

  1. 文本定位运算符
  2. 显示运算符的文本

现在我对 Td 和 Tm 定位运算符感兴趣,在使用Td时,你有txty,相对于 PDF 文档中明确指定的当前行的开头: tx ty Td,我已经使用这种方法通过txty坐标。问题是我不知道如何根据 PDF 的位置从 PDF 中提取文本,同时只提供txty

a b c d e f Tm

这是 Tm 使用的“公式”。af 值代表什么?这将是我对 Tm 的输入:

BT
/F1 8.88 Tf
0 0 0 rg
0.9998 0 0 1 401.52 448.08 Tm
[<0014>-11<0015>-11<0013>-11<000F>-19<0014>-11<0019>] TJ
ET

为什么每组四个人都有一个领先的 00 ?这是十六进制的吗?我应该将它从十六进制转换为整数和相应的字符吗?

这将是我对 Td 的输入:

BT 43.20 421.90 Td 0 Tw /C001 10.00 Tf 0.00 Tw <BlablablaTextInHexThatICanProcess>Tj ET

这样就清楚多了,坐标也清楚了。如何根据简单的 X 和 Y 坐标从 Tm 定位的 PDF 文本对象中提取文本?我正在使用 c++ 和 PoDoFo 库

4

2 回答 2

17

首先,当尝试根据其位置从 PDF 中提取文本时,仅提供 tx 和 ty 时,仅考虑文本矩阵(您使用已找到的Tm运算符设置的)是不够的。您还必须考虑当前的转换矩阵!

我假设当您引用默认用户空间坐标中给出的位置时。

为了避免在设备空间中指定对象的设备相关影响,PDF 定义了一个与设备无关的坐标系,该坐标系始终与当前页面具有相同的关系,而与发生打印或显示的输出设备无关。这种与设备无关的坐标系称为用户空间。

用户空间坐标系应初始化为文档每一页的默认状态。页面字典中的 CropBox 条目应指定与预期输出介质(显示窗口或打印页面)的可见区域相对应的用户空间矩形。正 x 轴水平向右延伸,正 y 轴垂直向上

(第 8.3.2.3 节,ISO 32000-1:2008

由于我们只看到 x 和 y 坐标,我们将位置视为 R² 中的向量 (x, y)。然而,在内部,PDF 认为这个平面嵌入在 R³ 中,具有恒定的 z 坐标值 1,即 [x, y, 1]。这是因为 PDF 希望允许多种转换(平移、旋转、缩放、倾斜等),但另一方面又希望尽可能限制所需的数学运算。顺便说一句,在将我们的平面作为 [x, y, 1] 嵌入到 R³ 中之后,所有这些变换都可以通过矩阵乘法来实现:

单次变换

在这里,您已经看到了您询问的数字 a、b、c、d、e 和 f。

现在,在考虑文本特定转换之前,您必须考虑当前(与文本无关)转换矩阵的操作。该矩阵由cm运算符操作:

abcdef cm通过连接指定的矩阵来修改当前的变换矩阵(CTM)(见 8.3.2,“坐标空间”)。尽管操作数指定了一个矩阵,但它们应写为六个单独的数字,而不是一个数组。

(第 8.4.4 节,ISO 32000-1:2008

顺便说一句,这意味着您必须考虑当前正在运行的所有cm运算符,即自页面内容开始以来所有呈现的,除了通过恢复以前的图形状态而撤销的那些(参见运算符qQ推送和恢复图形状态,第 8.4.2 节,ISO 32000-1:2008)。

只有现在您可以考虑文本特定的转换矩阵:

在文本对象的开头,Tm应为单位矩阵;因此,文本空间的原点最初应与用户空间的原点相同。表 108 中描述的文本定位操作符会改变Tm,从而控制随后绘制的字形的位置。此外,表 109 中描述的文本显示操作符会更新Tm(通过更改其 e 和 f 转换组件)以考虑每个绘制的字形的水平或垂直位移以及任何字符或单词间距参数文本状态。

此外,在文本对象中,符合标准的阅读器应跟踪文本行矩阵Tlm,该矩阵捕获文本行开头的 Tm 值。文本定位和文本显示操作符应在表 108 和 109 中提到的特定场合读取和设置 Tlm

(第 9.4.2 节,ISO 32000-1:2008

因此,在文本对象内部,您必须跟踪文本矩阵,该矩阵主要使用您找到的Tm运算符设置,操作数如上所示排列在矩阵中,但也作为其他文本定位和文本的效果进行操作显示运算符。

并且还有额外的参数决定了文本的最终位置,文本状态参数Tfs(文本字体大小)、Th(水平缩放)和Trise(文本上升),cf. ISO 32000-1:2008第 9.3.1 节。

从概念上讲,从文本空间到设备空间[或在您的情况下到默认用户空间]的整个转换可以由文本渲染矩阵Trm 表示

文本渲染矩阵

Trm是一个临时矩阵;从概念上讲,它是在文本显示操作期间绘制每个字形之前重新计算的。

(第 9.4.2 节,ISO 32000-1:2008

因此,您的坐标 (x, y) 在概念上由文本空间坐标乘以Trm 得出:

[x, y, 1] = [xts, yts, 1] x Trm

其中 (xts, yts) 在字形原点是 (0, 0)。对于每个打印的字形,您都有一个字形位移来到达下一个字形原点的位置:

字形位移

文本矩阵应由这些字形位移值更新,如下所示:

通过字形置换更新文本矩阵

(第 9.4.4 节,ISO 32000-1:2008

我引用了当前 PDF 规范ISO 32000-1:2008中的一些段落。我认为这比使用非常古老的 PDF 参考 1.4 更可取;此外,它被 Adob​​e 个人称为“本质上不规范”。

编辑 回答评论的一些澄清

设备空间和用户空间,它们有什么区别,设备空间不是指打印机/视频显示吗?和用户空间来克服每个设备的特殊性?就像用户页面是我看到的文档页面?

是的,设备空间是一个固定的坐标系,基本上由手头设备的属性决定。是的,用户空间是一个独立于目标设备的坐标系。但是不,它不是“您看到的文档页面”,因为您在某些设备上看到它(或在被某些设备处理之后)。

用户空间坐标系是一个独立的坐标系,其一点的坐标可以通过与当前变换矩阵(CTM)的矩阵乘法转换为设备坐标。

UserCoords x CTM = DeviceCoords

用户空间坐标系被初始化为页面字典中的CropBox条目通过相应地初始化CTM来指定与可见区域(见上文)对应的用户空间矩形的状态。

但是正如单词的选择已经表明(“当前变换矩阵”,“坐标系被初始化”),用户空间坐标系是一个动态的、不断变化的坐标系。

无论使用何种输出设备,默认用户空间都为 PDF 页面描述提供了一致、可靠的起点。如有必要,PDF 内容流可以通过应用坐标变换运算符cm修改用户空间以更适合其需要(参见 8.4.4,“图形状态运算符”)。因此,内容流中看似绝对坐标的内容相对于当前页面并不是绝对的,因为它们是在一个坐标系中表示的,该坐标系可以左右滑动、缩小或扩大。坐标系变换不仅增强了设备独立性,而且本身就是一个有用的工具。

(第 8.3.2.3 节,ISO 32000-1:2008

因此,当 aPdfReader偶然发现一个cm运算符,其参数表示某个矩阵 M,CTM 会发生变化:

CTMnew = M x CTMold

以下运算符中存在的坐标和坐标根据这个新矩阵 CTMnew 进行解释:

UserCoords x CTMnew = DeviceCoords

所以现在用户空间坐标系可能与其以前的状态非常不同,缩放、旋转、倾斜等等。

您最感兴趣的坐标很可能是用户空间被初始化为的坐标系中的坐标,即CTM 被初始化为单位矩阵的虚拟设备的设备坐标系。

文本空间和字形空间在哪里开始和结束。

文本的坐标在文本空间中指定。从文本空间到用户空间的转换由文本矩阵结合图形状态下的几个文本相关参数定义(参见 9.4.2,“文本定位操作符”)。

文本矩阵 TM 在文本对象的开头被初始化为单位矩阵,但在执行文本操作期间会发生变化,当您使用Tm运算符时最明显,而当您使用其他运算符时则隐含。该矩阵由包含文本相关参数字体大小、水平缩放和文本上升的矩阵 TR 操作。有关详细信息,请参见上面的文本渲染矩阵 TRM。因此,

DeviceCoords = UserCoords x CTM = TextCoords x TR x TM x CTM

从字形空间到文本空间的转换应由字体矩阵定义。对于大多数类型的字体,该矩阵应预定义为将 1000 个字形空间单位映射到 1 个文本空间单位;对于 Type 3 字体,字体矩阵应在字体字典中明确给出(见 9.6.5,“Type 3 Fonts”)。

因此,这种转换取决于当前字体。字体字典中的字体矩阵 FM 的行为如下:

DeviceCoords = GlyphCoords x FM x TR x TM x CTM

您不想定位字形的单个段的设备坐标,因此这些坐标似乎不感兴趣。但是,字形宽度将在字形空间中解释。但是,除非您正在处理 Type 3 字体,否则这仅意味着您必须将它们除以 1000...

以及在字形绘制过程中参数 w0 和 w1 是如何演变的?他们最初是 (0,0)

w0 和 w1 表示字形的水平和垂直位移。在水平书写模式下,w0 是转换为文本模式的字形宽度(即通常仅除以 1000),w1 为 0。对于垂直书写模式,文本检查ISO 32000-1:2008中的第 9.2.4 和 9.7.4.3 节。

文本空间是否与第一个字形空间具有相同的起源?并使用计算出的 (tx,ty) 进行更新?

由于字形空间坐标仅乘以字体矩阵以产生文本空间坐标,并且在所有情况下字体矩阵,但对于 Type 3 字体仅压缩 1000 倍,见上文,字形原点映射到文本空间起源。

但是 tx 和 ty 用于更新文本矩阵本身。因此,文本规范坐标系会针对每个字形移动,并且对于每个(非类型 3)字形原点映射到原点……的文本空间坐标系略有变化。

于 2013-05-10T13:27:32.547 回答
4

不要低估这项任务的规模。文本矩阵位非常简单明了。难点在于文本本身。

让我们从您的查询开始 - 为什么每组四个都有前导 00?

好吧,PDF 没有标准的文本编码——它有很多很多很多。在解码文本之前,您需要知道字体的编码是什么。

所以在你的例子中:

BT
/F1 8.88 Tf
0 0 0 rg
0.9998 0 0 1 401.52 448.08 Tm
[<0014>-11<0015>-11<0013>-11<000F>-19<0014>-11<0019>] TJ
ET

字体是 /F1 位。这是存在于与字体相关的页面(或父页面)中的名称。您需要查找字体并找出编码是什么。

鉴于您示例中的内容,我怀疑编码是标识一,并且四位十六进制数字是字体中的字形 ID。如果是这种情况,那么字体应该有一个 ToUnicode 条目,这将允许您查找字形 ID 并返回一个 Unicode 字符。

其他字体可能有也可能没有 ToUnicode 条目,如果发生这种情况,有多种方法可以提取 Unicode 文本。不同的方法可能会给出不同的结果,这就是为什么 PDF 规范有一整节题为“文本内容的提取”详细说明了这些尝试的顺序。

希望您的 PoDoFo 库应该具有进行这种转换的方法。如果不是,任务将非常艰巨,我认为您应该考虑其他一些选择。我为我们的 ABCpdf .NET 库编写了文本提取代码,花了几个月的时间编写代码,然后进行了几年的调整。

于 2013-05-13T10:55:46.807 回答