How to add page numbers with their own overlay background to PDF using Ghostscript?

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.

See:

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.

See: enter image description here

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

(37701C3770037701D3770037701E37700Page )
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:

(37701C3770037701D3770037701E37700Page )
MyPageCount =string
       cvs concatstrings

37701C37700 becomes ₤, 37701D37700 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:
enter image description here

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.

PS

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.

Leave a Comment