我正在尝试从PDF文件中提取矢量图形并创建相应的SVG文件。为此,我使用带有xpdf库的SVGOutputDev (https://github.com/immateriel/pdf2svg/blob/master/SVGOutputDev.cc)。现在SVGOutputDev还没有实现剪辑路径提取,我正试图实现同样的。虽然我能够提取剪辑路径定义本身,但我无法确定哪些定义适用于正常描边或填充区域。例如,请参阅http://pastebin.com/jTdzv3YZ获取我从PDF页面中提取的SVG,以及在提取过程中看到的PDF图形命令序列的相应转储。从该SVG中可以看到,有多个剪辑路径和一个矩形填充区域。尽管在填充矩形定义之前定义了多个剪辑路径,但是只有在矩形定义之前定义的圆形剪辑路径才会与矩形相关联(根据PDF页面在各种PDF阅读器上的呈现方式,它们在白色背景中只显示两个黑色填充的圆圈)。问题是如何知道哪些剪辑路径与PDF中定义的常规填充/描边区域相关联?仅供参考,我浏览了PDF规范文档的相关部分,但对我来说不是很清楚("剪切路径操作可能出现在最后一个路径构建操作符之后,并在路径绘制操作符之前终止路径对象。虽然剪辑路径操作符出现在绘制操作符之前,但它不会在剪辑路径出现时改变剪辑路径。相反,它修改了后续绘制操作符的效果。有人能解释一下如何识别相关的剪辑路径以应用于任何正常路径吗?
问题是如何知道哪些剪辑路径与PDF中定义的常规填充/描边区域相关联?
简而言之:在执行填充或笔画操作时定义的所有剪辑路径区域的交集,适用于Q(恢复状态)操作期间无效的那些区域。
因此,您对示例文件
的分析尽管在填充矩形定义之前定义了多个剪辑路径,只有在矩形定义之前定义的圆形剪辑路径才会与矩形相关联(根据PDF页面在各种PDF阅读器上的呈现方式,它们在白色背景中只显示两个黑色填充的圆圈)
是错误的:不是最后一个剪辑区域,而是在矩形定义定义当前剪辑区域之前所有剪辑区域的交集。由于每个剪辑区域都包含在前一个剪辑区域中,因此相交的结果确实由这两个圆组成。
文档中:
图形状态应包含当前的剪切路径,该路径限制了受绘制操作符影响的页面区域。此路径的封闭子路径应定义可以绘制的区域。
初始剪切路径应包括整个页面。
[剪辑路径算子]通过与当前路径相交来修改当前剪辑路径,使用[非零圈数规则/偶奇规则]来确定哪些区域位于剪辑路径内。
无法放大当前剪辑路径,也无法在不参考当前剪辑路径的情况下设置新的剪辑路径。然而,由于剪切路径是图形状态的一部分,它的效果可以通过在一对q和q操作符之间封装剪切路径的修改和这些对象的绘制来定位到特定的图形对象(参见8.4.2,"图形状态堆栈")。执行Q操作符会使剪切路径恢复到修改剪切路径之前Q操作符保存的值。
(当前PDF规范ISO 32000-1第8.5.4节)
实际操作:让我们看看你的文档页面的内容流(它有一个Mediabox [0,0,595, 842]):
q
q
两次推送图形状态。
0 842 m
0 0 l
595 0 l
595 842 l
h
W
n
定义与整个媒体框等效的剪辑路径。
1 w
2 J
0 j
10 M
[]0 d
定义一般图形状态属性(线宽、线帽样式、线连接样式、斜接限制和破折号图案)。
q
再次推送图形状态,这次使用显式设置的剪辑路径和其他图形属性。
0 718.5 m
595 718.5 l
595 123.5 l
0 123.5 l
0 718.5 l
h
W
n
定义一个剪辑路径,它包含一个与整个媒体盒一样宽的矩形,但切断了124用户空间单位高度的上下条纹。由于这个剪辑路径完全包含在之前设置的剪辑路径中,所以交集等于这里的剪辑路径。因此,当前有效的剪辑区域是这个较小的矩形。
0 718.5 m
595 718.5 l
595 123.5 l
0 123.5 l
0 718.5 l
h
W
n
定义一个与前一个相同的剪辑路径。因此,将它们相交不会改变任何东西。
148.75 668.92 m
93.98 668.92 49.58 624.52 49.58 569.75 c
49.58 514.98 93.98 470.58 148.75 470.58 c
203.52 470.58 247.92 514.98 247.92 569.75 c
247.92 624.52 203.52 668.92 148.75 668.92 c
h
347.08 470.58 m
292.32 470.58 247.92 426.18 247.92 371.42 c
247.92 316.65 292.32 272.25 347.08 272.25 c
401.85 272.25 446.25 316.65 446.25 371.42 c
446.25 426.18 401.85 470.58 347.08 470.58 c
h
W
n
定义由两个圆子路径组成的剪辑路径。这两个圆不相交;因此,我们不必处理"非零圈数规则"与"非零圈数规则"之间的差异。以及"单双规则"。此外,圆圈包含在当前剪辑区域内。因此,新的剪辑区域由这两个圆组成。
0 0 0 rg
49.58 668.92 m
545.42 668.92 l
545.42 173.08 l
49.58 173.08 l
49.58 668.92 l
h
f
这将绘制一个填充的黑色矩形,其中包含当前的剪切区域。因此,整个裁剪区域(即两个圆)被涂成黑色。
Q
q
将图形状态恢复到上次推送的状态。即,任何后续操作的剪切路径都是第一个包含整个媒体盒的路径。此图形状态将再次被推送。
0 718.5 m
0 123.5 l
595 123.5 l
595 718.5 l
h
W
n
再次定义了顶部和底部的剪辑路径。
Q
q
…并立即按恢复状态掉落操作;状态再次被推送。
0 718.5 m
0 123.5 l
595 123.5 l
595 718.5 l
h
W
n
Q
q
0 718.5 m
0 123.5 l
595 123.5 l
595 718.5 l
h
W
n
Q
q
…一次又一次。
0 842 m
0 0 l
595 0 l
595 842 l
h
W
n
这再次定义了一个绕过整个媒体框的剪辑路径。因为这是当前的剪辑路径,相交不会改变任何东西。
Q
Q
Q