I want to find a way how to add overlay page numbers on PDF pages with motley background. The problem is that if I use a usual approach like this:
(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
Then gs -dNOSAFER -dBATCH -dNOPAUSE -sDEVICE=pdfwrite -o output.pdf -sDEVICE=pdfwrite -f pagecount.ps input.pdf
It works but page numbers previously seen on blank pages are hardly visible now due to motley background stuff on pages.
So I want some little white substrate to be drawn around numbers to obscure the area they occupy on a page but with the numbers themselves being visible.
One idea was to use annotations with \Rect
:
(pagecount.ps, originally taken from 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
But it produces only a white page.
How to make page numbers with their own little background be drawn on PDF pages using Ghostscript?
UPD:
I updated pagecount.ps
according to advices and now I have right little background in right place but page numbers stopped to get drawn (Error: /nocurrentpoint in /--.endpage--
).
New 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:
I updated pagecount.ps
to fix (Error: /nocurrentpoint in /--.endpage--
). I also removed stroke
command afted filling the rectangle.
Now I have Error: /typecheck in /--.endpage-- Operand stack: 0 true 595 (1)
New 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
Finally it works.
I've made 2 variants of the script. The 1st one is just page numbering where numbers have obscuring background so that motley pdf stuff could not make the numbers less readable.
Some clarification:
sub 460 sub 710
below are related to page number text box and stand for x and y coordinates, respectively.
1 0 0 setrgbcolor fill
related to textbox overlay background colour (red here).
1 0 0 setrgbcolor 5 setlinewidth
related to textbox overlay contour colour and to its width
0 0 0 setrgbcolor
related to numbers colour
/MyPageCount 16 put
related to start page number
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
The second one is a numbering scheme where numbers have auxilliary text and it all has obscuring background.
userdict begin
%%EndProlog
%%BeginSetup
% The following encodes a few useful Unicode glyphs, if only a few are needed.
% Based on https://stackoverflow.com/questions/54840594/show-unicode-characters-in-postscript
% 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
(\377\001C\377\000\377\001D\377\000\377\001E\377\000Page )
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
As you can see, I could insert [₤♣―Page 16] (by using /afii08941, /club, /afii00208) where [...16] is generated automatically on each page in increasing order.
I used special symbols and the lines from userdict begin
to >> definefont pop
serve for this aim. You may remove these lines if you do not need special symbols in page numbering.
Here is the table of symbols to insert some mnemonics, latin, greek, cyrillic and arabic symbols into Postscript output (PDFs in my case) https://root.cern/doc/v622/AdobeGlyphList_8h_source.html
Special symbols also need remapping scheme, you have to write a definition for it:
/Helvetica /Helvetica-Uni [
16#43 /afii08941 % ASCII 43 = C
16#44 /club % ASCII 44 = D
16#45 /afii00208 % ASCII 45 = E
Then you can put special symbols on the top of Postscript stack and concatenate them with page numbering counter:
(\377\001C\377\000\377\001D\377\000\377\001E\377\000Page )
MyPageCount =string
cvs concatstrings
\377\001C\377\000 becomes ₤, \377\001D\377\000 becomes ♣. CD in bold.
Note how gsave/grestore
work here.
KenS asked me in comments why I had used stroke
in my script.
It turns out that my page numbering looks like this without stroke:
That is, in this case, obsuring background is close-fitting
and there are no margins between the numbers themselves and motley PDf stuff and numbers may seem to be interflowing into dark motley stuff in some points.
So stroke
draws a border around our auxilliary text and numbers. In my case, the border has the same color (red) as the auxilliary background so they look more readable.
But if you remove gsave/grestore
, stroke
will not take effect and the resulting picture will look as the previous one.
5 setlinewidth
sets a width of 5 pt's.
P.S.
The key in finding bugs of the original answer script was to use debugging pstack
operator.
Determine the last working edition then insert pstack
after its 1st line and modify the script to check some risky operators. If it works, then move pstack
after the 2st line and add another risky operator. Once your script is broken, compare pstack
output from working and non-workings editions of your script.