我需要使用Ghostscript在PDF文档的每一页的左下角添加一个白色矩形和一些文本。为此,我创建了以下Postscript脚本:
<<
/EndPage
{
2 eq { pop false }
{
newpath
0 0 moveto
0 20 lineto
200 20 lineto
200 0 lineto
closepath
%%gsave
1 setgray
fill
%%grestore
1 setlinewidth
0 setgray
stroke
gsave
/Times-Roman 9 selectfont
30 5 moveto
(My text) show
grestore
true
} ifelse
} bind
>> setpagedevice
与Ghostscript命令结合使用时,效果很好:
gs -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -sOutputFile=output.pdf my_script.ps input.pdf
但是,如果input.pdf处于横向模式,则白框和文本打印在左上角而不是左下角。我可以通过添加以下内容使其起作用:
90 rotate 0 -595 translate
但是我无法确定页面何时处于横向模式还是纵向模式。我可以获得页面的宽度和高度,但是即使对于横向模式页面,其宽度也小于高度。我尝试了以下操作,但失败了:
/orient currentpagedevice /Orientation get def
我已经坚持了一段时间。任何帮助是极大的赞赏!
(Ghostscript版本为9.25)
[更新]
为了说明如何宽度大于高度,在横向模式下一个页面时,这里是我使用的script.ps:https://gist.github.com/irinkaa/9faadf30b3a5a381a0b621d72b712020
这是input.pdf和output.pdf。如您所见,它612.0 - 792.0
被打印在输出文件中,显示宽度(612)<高度(792)。
当我在输出文件上重新运行相同的命令时,它会打印相同的宽度和高度值,但随后将该框正确放置在左下角。
当我在脚本中添加以下内容时:
/orient currentpagedevice /Orientation get def
我收到一条错误消息,提示未设置方向(如果我理解正确的话):
Error: /undefined in --get--
Operand stack:
orient --dict:212/312(ro)(L)-- Orientation
Execution stack:
%interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- false 1 %stopped_push 1999 1 3 %oparray_pop 1998 1 3 %oparray_pop 1982 1 3 %oparray_pop 1868 1 3 %oparray_pop --nostringval-- %errorexec_pop .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval--
Dictionary stack:
--dict:977/1684(ro)(G)-- --dict:0/20(G)-- --dict:80/200(L)--
Current allocation mode is local
Current file position is 151
GPL Ghostscript 9.25: Unrecoverable error, exit code 1
首先,您应该升级您的Ghostscript版本。9.25很旧,并且具有安全漏洞。
其次,您需要查看页面设备字典中的/ Orientation和/ PageSize条目。不仅如此,您还应该使用PageSize来确定用于“调整”的翻译。除非您处于固定的工作流程中(如果您正在接收混合的方向文件,这似乎不太可能),那么您不应假定介质为A4。
Ghostscript PDF解释器查看PDF文件每一页上的MediaBox,并重置页面设备字典中的/ PageSize以匹配该页面的MediaBox。如果PDF页面具有/ Rotate条目,则它将(IIRC)永不设置/ Orientation,然后将其应用于MediaBox和页面的内容。
因此,您实际上只需要查看所请求媒体的宽度和高度,这是由页面设备字典中的/ PageSize数组给出的。
现在这么说...
您说“即使对于横向模式页面,宽度也小于高度”。这对我来说似乎不太可能,但是在没有示例的情况下很难说出来。这也使任何人都很难提供任何建议。
我建议您将示例上传到某个地方,然后在此处发布URL,以便我们查看文件。
哦,我真的建议您不要将输出文件发送到stdout。这可能对您来说很方便,但是pdfwrite设备已经具有某些功能,如果您这样做就根本无法使用(它们要求输出文件可搜索),并且将来可能还会有更多情况。
[编辑]
您的问题是执行顺序。script.ps中的程序在解释PDF文件之前运行,然后解释PDF文件。
当您的程序正在做的所有事情都是在页面设备字典中设置EndPage过程时,这是没有问题的,对页面设备字典的更改是保守的,除非特别是过度改写,否则它们会累积。
因此,在解释PDF文件的过程中页面设备字典发生更改这一事实无关紧要(除非以某种方式更改了EndPage过程)。
但是在程序运行时,页面设备字典/ PageSize键具有关联的值,该值是一个包含默认媒体大小的数组(因为尚未发生任何更改)。在解释PDF文件之前,不会更改PageSize条目。这意味着无论您的PDF文件使用哪种尺寸的介质,您的程序都将始终返回默认的介质尺寸。
您需要在执行EndPage过程时知道实际的PageSize。因此,您需要在EndPage过程中研究当前的PageSize。
就像是:
<<
/EndPage
{
2 eq { pop false }
{
% Get the current page device dictionary and extract the PageSize
currentpagedevice /PageSize get
% Load the values from the array onto the stack
% and discard the array copy returned by the aload operator
aload pop
% If width < height (or equal, square page)
le {
% Handle a portrait page
} {
% Handle a landscape page
} ifelse
}ifelse
} bind
>> setpagedevice
请注意,这避免了创建字典条目来保存页面的宽度和高度。这样做有几个原因;
首先,每个页面的宽度和高度都可以不同(尤其是在PDF文件中)。
其次,您不(在程序中)创建自己的字典来存储这些键/值对,这意味着您正在使用当时处于活动状态的任何字典。尽管这是您当前所接受的方式,但是由于userdict将在程序开始时处于活动状态,因此您无法知道调用EndPage时哪个词典位于词典堆栈的顶部。因此,仅将值戳入碰巧是最重要的字典中是不安全的,您可能最终会覆盖具有相同名称的键,这将导致不可预知的副作用。同样地(按照下面的方向),如果当前字典中不包含这些键,则将得到未定义的错误。因此,您现在正通过运气摆脱困境。
第三,在PostScript中通常认为更好的做法是使用堆栈进行临时存储,而不是在字典中创建键/值对。
由于后两个原因,我强烈建议您不要stringholder
在程序开始时在字典堆栈顶部的任何字典中创建一个称为(如您的程序当前那样)的键,并假设它在EndPage过程,您应该改为使用10 string
来简单地创建一个临时字符串。
例如:
/Times-Roman 9 selectfont
30 5 moveto
pagewidth
stringHolder cvs
show
会成为:
/Times-Roman 9 selectfont
30 5 moveto
currentpagedevice /PageSize get 0 get
256 string cvs
show
10位数字可能有点小,任何人都应该足够256位,并且字符串将被垃圾回收,因此这不像您正在泄漏内存或其他任何东西。
关于方向;是的,您是正确的,正如我最初所说的,PDF解释器未在页面设备字典中设置“方向”。如果您尝试get
从不包含该键的字典中键入一个键,则会收到未定义的错误。如果不确定字典中是否存在键,则应首先使用known
运算符对其进行检查。
[编辑2]
如以下注释中所述...可以通过使用transform
运算符和单位矢量来测试CTM的方向。如果由此产生的两个坐标中的一个或两个transform
均为负,则CTM中涉及旋转,并且通过检查每个坐标的符号,我们可以确定旋转最终位于哪个象限。
对于PDF中的/ Rotate标志而言,这已足够,因为只能以90度为增量进行指定。这是一个确定旋转的示例函数,以及一个简单的PostScript行使它:
%!PS
/R {
1 1 transform
0 ge {
0 ge {
(no rotation\n) print
} {
(90 degree ccw rotation\n) print
} ifelse
} {
0 ge {
(270 ccw rotation\n) print
} {
(180 ccw rotation\n) print
} ifelse
} ifelse
} bind def
R
gsave
90 rotate R
grestore
gsave
180 rotate R
grestore
gsave
270 rotate R
grestore
gsave
360 rotate R
grestore
可以使用此技术来确定原始文件是否已旋转,然后选择使EndPage过程具有不同的行为。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句