如何使用 Ghostscript 将具有自己覆盖背景的页码添加到 PDF?
How to add page numbers with their own overlay background to PDF using Ghostscript?
我想找到一种方法如何在具有杂色背景的 PDF 页面上添加叠加页码。
问题是,如果我使用像这样的常规方法:
(pagecount.ps)
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
然后gs -dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -o output.pdf -sDEVICE=pdfwrite -f pagecount.ps input.pdf
它可以工作,但由于页面上的杂色背景,现在几乎看不到以前在空白页面上看到的页码。
所以我想在数字周围绘制一些白色的小基板 以掩盖它们在页面上占据的区域,但数字本身是可见的。
一个想法是使用注释 \Rect
:
(pagecount.ps, 最初取自 How to add page numbers to Postscript/PDF)
globaldict
/MyPageCount 1 put
<<
/EndPage
{
newpath [
/Rect
[ 20 dup moveto (Link on page1) false charpath pathbbox
2 add 4 1 roll 2 add 4 1 roll 2 sub 4 1 roll 2 sub 4 1 roll
newpath ]
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
但它只生成一个白页。
如何使用 Ghostscript 在 PDF 页面上绘制带有自己小背景的页码?
UPD:
我根据建议更新了 pagecount.ps
,现在我在正确的位置有了正确的小背景,但页码停止绘制 (Error: /nocurrentpoint in /--.endpage--
)。
新 pagecount.ps
:
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
pop pop pop pop % remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill
grestore
stroke
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
UPD 2:
我更新了 pagecount.ps
以修复 (Error: /nocurrentpoint in /--.endpage--
)。我还删除了填充矩形后的 stroke
命令。
现在我有 Error: /typecheck in /--.endpage-- Operand stack: 0 true 595 (1)
新 pagecount.ps
:
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
pop pop pop pop % remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill
grestore
% end of new lines
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
终于成功了。
我制作了 2 个脚本变体。第一个只是页码,其中数字背景模糊,因此杂乱无章的 pdf 内容不会降低数字的可读性。
一些说明:
sub 460 sub 710
以下与页码文本框有关,分别代表x和y坐标。
1 0 0 setrgbcolor fill
与文本框覆盖背景颜色(此处为红色)相关。
1 0 0 setrgbcolor 5 setlinewidth
与文本框覆盖轮廓颜色及其宽度相关
0 0 0 setrgbcolor
与数字颜色相关
/MyPageCount 16 put
与起始页码相关
见:
globaldict
/MyPageCount 16 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
% remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill grestore 1 0 0 setrgbcolor
5 setlinewidth stroke
pop pop pop pop
0 0 0 setrgbcolor
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
第二种是编号方案,其中数字有辅助文本,并且都有模糊的背景。
参见:
userdict begin
%%EndProlog
%%BeginSetup
% The following encodes a few useful Unicode glyphs, if only a few are needed.
% Based on
% Usage: /Times-Roman /Times-Roman-Uni UniVec new-font-encoding
/new-font-encoding { <<>> begin
/newcodesandnames exch def
/newfontname exch def
/basefontname exch def
/basefontdict basefontname findfont def % Get the font dictionary on which to base the re-encoded version.
/newfont basefontdict maxlength dict def % Create a dictionary to hold the description for the re-encoded font.
basefontdict
{ exch dup /FID ne % Copy all the entries in the base font dictionary to the new dictionary except for the FID field.
{ dup /Encoding eq
{ exch dup length array copy % Make a copy of the Encoding field.
newfont 3 1 roll put }
{ exch newfont 3 1 roll put }
ifelse
}
{ pop pop } % Ignore the FID pair.
ifelse
} forall
newfont /FontName newfontname put % Install the new name.
newcodesandnames aload pop % Modify the encoding vector. First load the new encoding and name pairs onto the operand stack.
newcodesandnames length 2 idiv
{ newfont /Encoding get 3 1 roll put}
repeat % For each pair on the stack, put the new name into the designated position in the encoding vector.
newfontname newfont definefont pop % Now make the re-encoded font description into a POSTSCRIPT font.
% Ignore the modified dictionary returned on the operand stack by the definefont operator.
end} def
/Helvetica /Helvetica-Uni [
16#43 /afii08941 % ASCII 43 = C
16#44 /club % ASCII 44 = D
16#45 /afii00208 % ASCII 45 = E
] new-font-encoding
/Helv
<<
/FontType 0
/FontMatrix [ 1 0 0 1 0 0 ]
/FDepVector [
/Helvetica findfont % this is Font0
/Helvetica-Uni findfont % this is Font1
]
/Encoding [ 0 1 ]
/FMapType 3
>> definefont pop
globaldict
/MyPageCount 16 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helv 12 selectfont
(7[=11=]1C7[=11=]07[=11=]1D7[=11=]07[=11=]1E7[=11=]0Page )
MyPageCount =string
cvs concatstrings
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
% remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill grestore 1 0 0 setrgbcolor
5 setlinewidth stroke
pop pop pop pop
0 0 0 setrgbcolor
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
如您所见,我可以插入 [₤♣―第 16 页](通过使用 /afii08941、/club、/afii00208),其中 [...16] 在每个页面上按升序自动生成。
我使用了特殊符号,从 userdict begin
到 >> definefont pop
的行就是为了这个目的。如果页码中不需要特殊符号,您可以删除这些行。
这里是 table 符号,用于将一些助记符、拉丁文、希腊文、西里尔文和阿拉伯文符号插入 Postscript 输出(在我的例子中是 PDF)
https://root.cern/doc/v622/AdobeGlyphList_8h_source.html
特殊符号也需要remapping scheme,你得给它写个定义:
/Helvetica /Helvetica-Uni [
16#43 /afii08941 % ASCII 43 = C
16#44 /club % ASCII 44 = D
16#45 /afii00208 % ASCII 45 = E
然后你可以将特殊符号放在 Postscript 堆栈的顶部,并将它们与页码计数器连接起来:
(7[=13=]1C7[=13=]07[=13=]1D7[=13=]07[=13=]1E7[=13=]0Page )
MyPageCount =string
cvs concatstrings
7[=88=]1C7[=89=]0变成₤,7[=88=]1D7[=89=]0变成了♣。 CD 粗体。
注意 gsave/grestore
在这里是如何工作的。
KenS 在评论中问我为什么在脚本中使用 stroke
。
事实证明,我的页码看起来像这样没有笔画:
也就是说,在这种情况下,模糊背景是 close-fitting
并且数字本身和杂色 PDf 之间没有边距,并且数字在某些点上似乎与暗杂色的东西交织在一起。
所以 stroke
在我们的辅助文本和数字周围画了一个边框。在我的例子中,边框与辅助背景具有相同的颜色(红色),因此它们看起来更具可读性。
但是如果去掉gsave/grestore
,stroke
将不会生效,生成的图片看起来和之前的一样。
5 setlinewidth
设置 5 磅的宽度。
P.S.
寻找原始答案脚本错误的关键是使用调试 pstack
运算符。
确定最后一个工作版本然后在其第一行后插入pstack
并修改脚本以检查一些有风险的操作符。如果有效,则将 pstack
移到第 2 行之后并添加另一个有风险的运算符。一旦您的脚本被破坏,比较 pstack
工作版本和 non-workings 脚本版本的输出。
我想找到一种方法如何在具有杂色背景的 PDF 页面上添加叠加页码。 问题是,如果我使用像这样的常规方法:
(pagecount.ps)
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
然后gs -dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -o output.pdf -sDEVICE=pdfwrite -f pagecount.ps input.pdf
它可以工作,但由于页面上的杂色背景,现在几乎看不到以前在空白页面上看到的页码。
所以我想在数字周围绘制一些白色的小基板 以掩盖它们在页面上占据的区域,但数字本身是可见的。
一个想法是使用注释 \Rect
:
(pagecount.ps, 最初取自 How to add page numbers to Postscript/PDF)
globaldict
/MyPageCount 1 put
<<
/EndPage
{
newpath [
/Rect
[ 20 dup moveto (Link on page1) false charpath pathbbox
2 add 4 1 roll 2 add 4 1 roll 2 sub 4 1 roll 2 sub 4 1 roll
newpath ]
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
但它只生成一个白页。
如何使用 Ghostscript 在 PDF 页面上绘制带有自己小背景的页码?
UPD:
我根据建议更新了 pagecount.ps
,现在我在正确的位置有了正确的小背景,但页码停止绘制 (Error: /nocurrentpoint in /--.endpage--
)。
新 pagecount.ps
:
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
pop pop pop pop % remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill
grestore
stroke
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
UPD 2:
我更新了 pagecount.ps
以修复 (Error: /nocurrentpoint in /--.endpage--
)。我还删除了填充矩形后的 stroke
命令。
现在我有 Error: /typecheck in /--.endpage-- Operand stack: 0 true 595 (1)
新 pagecount.ps
:
globaldict
/MyPageCount 1 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
pop pop pop pop % remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill
grestore
% end of new lines
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 810
moveto show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
终于成功了。
我制作了 2 个脚本变体。第一个只是页码,其中数字背景模糊,因此杂乱无章的 pdf 内容不会降低数字的可读性。
一些说明:
sub 460 sub 710
以下与页码文本框有关,分别代表x和y坐标。
1 0 0 setrgbcolor fill
与文本框覆盖背景颜色(此处为红色)相关。
1 0 0 setrgbcolor 5 setlinewidth
与文本框覆盖轮廓颜色及其宽度相关
0 0 0 setrgbcolor
与数字颜色相关
/MyPageCount 16 put
与起始页码相关
见:
globaldict
/MyPageCount 16 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helvetica 12 selectfont
MyPageCount =string
cvs
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
% remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill grestore 1 0 0 setrgbcolor
5 setlinewidth stroke
pop pop pop pop
0 0 0 setrgbcolor
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
第二种是编号方案,其中数字有辅助文本,并且都有模糊的背景。
参见:
userdict begin
%%EndProlog
%%BeginSetup
% The following encodes a few useful Unicode glyphs, if only a few are needed.
% Based on
% Usage: /Times-Roman /Times-Roman-Uni UniVec new-font-encoding
/new-font-encoding { <<>> begin
/newcodesandnames exch def
/newfontname exch def
/basefontname exch def
/basefontdict basefontname findfont def % Get the font dictionary on which to base the re-encoded version.
/newfont basefontdict maxlength dict def % Create a dictionary to hold the description for the re-encoded font.
basefontdict
{ exch dup /FID ne % Copy all the entries in the base font dictionary to the new dictionary except for the FID field.
{ dup /Encoding eq
{ exch dup length array copy % Make a copy of the Encoding field.
newfont 3 1 roll put }
{ exch newfont 3 1 roll put }
ifelse
}
{ pop pop } % Ignore the FID pair.
ifelse
} forall
newfont /FontName newfontname put % Install the new name.
newcodesandnames aload pop % Modify the encoding vector. First load the new encoding and name pairs onto the operand stack.
newcodesandnames length 2 idiv
{ newfont /Encoding get 3 1 roll put}
repeat % For each pair on the stack, put the new name into the designated position in the encoding vector.
newfontname newfont definefont pop % Now make the re-encoded font description into a POSTSCRIPT font.
% Ignore the modified dictionary returned on the operand stack by the definefont operator.
end} def
/Helvetica /Helvetica-Uni [
16#43 /afii08941 % ASCII 43 = C
16#44 /club % ASCII 44 = D
16#45 /afii00208 % ASCII 45 = E
] new-font-encoding
/Helv
<<
/FontType 0
/FontMatrix [ 1 0 0 1 0 0 ]
/FDepVector [
/Helvetica findfont % this is Font0
/Helvetica-Uni findfont % this is Font1
]
/Encoding [ 0 1 ]
/FMapType 3
>> definefont pop
globaldict
/MyPageCount 16 put
<<
/EndPage
{
exch pop 0 eq dup
{
/Helv 12 selectfont
(7[=11=]1C7[=11=]07[=11=]1D7[=11=]07[=11=]1E7[=11=]0Page )
MyPageCount =string
cvs concatstrings
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto % move to text drawing position
% lines new to pagecount.ps
dup % duplicate string on the stack
true charpath flattenpath pathbbox % consume the string and put coordinates of bounding box to stack
newpath % start drawing bounding box
3 index 3 index moveto % copy llx and lly to the top of stack and move to them
3 index 1 index lineto % copy llx and ury to the top of stack and draw line to them
1 index 1 index lineto % copy urx and ury to the top of stack and draw line to them
1 index 3 index lineto % copy urx and lly to the top of stack and draw line to them
3 index 3 index lineto % copy llx and lly to the top of stack and draw line to them
closepath
% remove coordinates of bounding box from stack
gsave
1 0 0 setrgbcolor
fill grestore 1 0 0 setrgbcolor
5 setlinewidth stroke
pop pop pop pop
0 0 0 setrgbcolor
dup stringwidth pop
currentpagedevice
/PageSize get 0 get exch
sub 460 sub 710
moveto
% end of new lines
show
globaldict
/MyPageCount MyPageCount 1 add put
} if
} bind
>> setpagedevice
如您所见,我可以插入 [₤♣―第 16 页](通过使用 /afii08941、/club、/afii00208),其中 [...16] 在每个页面上按升序自动生成。
我使用了特殊符号,从 userdict begin
到 >> definefont pop
的行就是为了这个目的。如果页码中不需要特殊符号,您可以删除这些行。
这里是 table 符号,用于将一些助记符、拉丁文、希腊文、西里尔文和阿拉伯文符号插入 Postscript 输出(在我的例子中是 PDF) https://root.cern/doc/v622/AdobeGlyphList_8h_source.html
特殊符号也需要remapping scheme,你得给它写个定义:
/Helvetica /Helvetica-Uni [
16#43 /afii08941 % ASCII 43 = C
16#44 /club % ASCII 44 = D
16#45 /afii00208 % ASCII 45 = E
然后你可以将特殊符号放在 Postscript 堆栈的顶部,并将它们与页码计数器连接起来:
(7[=13=]1C7[=13=]07[=13=]1D7[=13=]07[=13=]1E7[=13=]0Page )
MyPageCount =string
cvs concatstrings
7[=88=]1C7[=89=]0变成₤,7[=88=]1D7[=89=]0变成了♣。 CD 粗体。
注意 gsave/grestore
在这里是如何工作的。
KenS 在评论中问我为什么在脚本中使用 stroke
。
事实证明,我的页码看起来像这样没有笔画:
也就是说,在这种情况下,模糊背景是 close-fitting
并且数字本身和杂色 PDf 之间没有边距,并且数字在某些点上似乎与暗杂色的东西交织在一起。
所以 stroke
在我们的辅助文本和数字周围画了一个边框。在我的例子中,边框与辅助背景具有相同的颜色(红色),因此它们看起来更具可读性。
但是如果去掉gsave/grestore
,stroke
将不会生效,生成的图片看起来和之前的一样。
5 setlinewidth
设置 5 磅的宽度。
P.S.
寻找原始答案脚本错误的关键是使用调试 pstack
运算符。
确定最后一个工作版本然后在其第一行后插入pstack
并修改脚本以检查一些有风险的操作符。如果有效,则将 pstack
移到第 2 行之后并添加另一个有风险的运算符。一旦您的脚本被破坏,比较 pstack
工作版本和 non-workings 脚本版本的输出。