我正在尝试从PDF文件中提取矢量图形并创建相应的SVG文件。我正在将SVGOutputDev(https://github.com/immateriel/pdf2svg/blob/master/SVGOutputDev.cc)与xpdf库用于此目的。现在SVGOutputDev还没有实现剪辑路径提取,我正在尝试实现相同的。虽然我能够自己提取剪辑路径定义,但我无法确定哪些定义适用于普通笔划或填充区域。例如,请参考http://pastebin.com/jTdzv3YZ我从PDF页面中提取的SVG,以及在提取过程中看到的PDF图形命令序列的相应转储。从该SVG可以看出,存在多个剪辑路径和一个矩形填充区域。即使在定义填充矩形之前定义了多个剪辑路径,但只有在矩形定义之前定义的的圆形剪辑路径应与矩形相关联(通过PDF页面的呈现方式)在各种PDF阅读器上,在白色背景中只显示2个黑色圆圈)。问题是如何知道哪些剪辑路径与PDF中定义的常规填充/描边区域相关联?仅供参考,我浏览了PDF规范文档的相关部分,但对我来说并不是很清楚(“剪切路径操作可能出现在最后一个路径构造操作符之后和路径绘制操作符之前终止路径对象。虽然剪切路径操作符出现在绘制操作符之前,它不会在它出现的位置改变剪切路径。而是修改后续绘制操作符的效果“)。有人可以解释如何识别应用于任何正常路径的相关剪辑路径吗?
答案 0 :(得分:5)
问题是如何知道哪些剪辑路径与PDF中定义的常规填充/描边区域相关联?
简而言之:在执行填充或描边操作时定义的所有剪辑路径区域的交集适用,但在Q期间无效的那些区域除外(恢复状态)运营商。
因此,您对样本文件的分析
即使在定义填充矩形之前定义了多个剪辑路径,只有在矩形定义之前定义的圆形剪辑路径才会与矩形相关联(以PDF格式表示)页面在各种PDF阅读器上呈现,在白色背景中仅显示2个黑色圆圈)
错误:不是最后剪辑区域,而是矩形定义之前的所有剪辑区域的交集定义了当前剪辑区域。由于每个剪辑区域都包含在前一个剪辑区域中,因此交叉点的结果确实由这两个圆圈组成。
在文档中:
图形状态应包含当前剪切路径,该路径限制受绘制操作符影响的页面区域。该路径的封闭子路径应定义可绘制的区域。
初始剪辑路径应包括整个页面。
[剪切路径操作符]通过将当前剪切路径与当前路径相交来修改当前剪切路径,使用[非零绕组编号规则/奇偶规则]来确定哪些区域位于剪切路径内。
无法在不参考当前剪切路径的情况下放大当前剪切路径或设置新的剪切路径。但是,由于剪切路径是图形状态的一部分,因此可以通过封闭剪切路径的修改以及在一对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
以前被推入堆栈的所有图形状态都会被删除。