Overlay a PS file on top of PDF file

Viewed 408

I found similar question that was answered Overlay two postscript files (command line approach)?, However, that solution does not work for me and my requirements are bit different (one of my files is multi-page file)

I have a PDF File (DrawingSheet.pdf) that is generated outside my control. I have a PostScript file (Table.ps) that I generate by converting XML file using XSLFO and Apache FOP. Table.ps contains one table.

The DrawingSheet.pdf has multiple pages. Table.ps has only one page. Both DrawingSheet.pdf and Table.ps has same paper size - A size, Landscape. I want to place that table from the Table.ps on top of the last page of the DrawingSheet.pdf. I don't want to "append" table page as additional page at the end of the DrawingSheet.pdf. I am using command-line GhostScript (v9.27).

Per the suggestion from that post, I wrote following Overlay.ps file:

/origshowpage /showpage load def
/showpage {} def
gsave
    (DrawingSheet.pdf) run
grestore
    (Table.ps) run
origshowpage

That does not work. What I get is the table page "appended" to the DrawingSheet.pdf rather than overlaying on top of the last page.

What am I doing wrong? How can I achieve what I want?

Edited-1:

If it helps to have same number of pages in both files to simplify logic, then I can generate Table.ps to have same number of pages as DrawingSheet.pdf file and have the table appear only on the last page of the Table.ps.

Edited-2:

Alternatively, I tried following approach (similar to adding image watermark to PDF file). Net result of this is that I as many blank pages as number of pages in DrawingSheet.pdf. Interestingly though, when I load that blank resulting PDF, I can see that the Acrobat Reader flashes the table across the screen, but when the entire file is loaded all I see in the end are blank pages.

Any help in solving this much appreciated.

<<
    /EndPage
    {
        2 eq
        {
            pop false
        }
        {
            gsave
                1 dict begin
                    /showpage {} def
                    (Table.ps) run
                end
            grestore
            pop true
        } ifelse
    } bind
>> setpagedevice

Edited-2 - Additional Notes: If I comment out gsave and grestore from above code, then I don't get blank pages but instead every page is now "replaced" (no overlay) with the table from Table.ps.

Edited-3 - Partial Success:

After coming across this post: Edit (every page of a) Postscript file manually, I tried that approach. I converted the DrawingSheet.pdf to DrawingSheet.ps, identified the last %%EndPageSetup line, and inserted following code after that line:

% BUNCH OF LINES NOT SHOWN %
%%BeginPageSetup
4 0 obj
<</Type/Page/MediaBox [0 0 792 612]
/Parent 3 0 R
/Resources<</ProcSet[/PDF]
/Font 10 0 R
>>
/Contents 5 0 R
/CropBox 
[0 0 792.0 612.0]
/BleedBox 
[0 0 792.0 612.0]
/TrimBox 
[0 0 792.0 612.0]
>>
endobj
%%EndPageSetup
%gsave                           % <== My Edits
    1 dict begin                 % <== My Edits
        /showpage {} def         % <== My Edits
        (Table.ps) run           % <== My Edits
    end                          % <== My Edits
%grestore                        % <== My Edits
5 0 obj
<</Length 30050>>stream
% BUNCH OF LINES NOT SHOWN %

With this edits (gsave and grestore commented out - if I uncomment them then this does not work), I get my table super imposed on the last page. Table appears fine, however the original last page from the pdf appears as flipped over the center on X axis after super imposing. The screenshot of the page is:

enter image description here

Text that you can read is from the Table.ps, while the text that is flipped is the original text from the last page of the DrawingSheet.pdf (of course that page in original pdf is not flipped).

Not sure what I am doing wrong to get that flipped image?

Edited-4:

Added additional notes to "Edited-2"

2 Answers

I tried your endpage and finally got this approach to work. The EndPage puts the reason code 0 or 1 and the page count on the stack (unreliably for some pdfs) so an alternative is the /PageCount variable and I show both. These count the number of pages and are incremented at the end of the page.

You need to know the number of pages to put the overlay on the page before the page is finished. The "finalpage" variable can also be defined on the ghostscript command line instead of in the file. Run ghostscript with both your endpage.ps and DrawingSheet.ps files as arguments. More work would be needed to adapt this to a DrawingSheet.pdf except that should be possible.

See if this works after changing the finalpage number. The table.ps should be placed on top of the original last page before the showpage is executed.

%!
/finalpage 9 def
<<
/EndPage {
       2 ne {
       1 add finalpage eq {(found last page\n)print (Table.ps)run} if
       currentpagedevice /PageCount get ==
       true
       } if
     }
>> setpagedevice

EDIT: The Postscript Language Reference Manual 3 page 176 says this:

The PostScript interpreter maintains an implicit current page that accumulates the marks made by the painting operators. When a program begins, the current page is completely blank. As each painting operator executes, it places marks on the current page. Each new mark completely obscures any marks it may overlay. This method is known as a painting model: no matter what color a mark has—white, black, gray, or color—it is put onto the current page as if it were applied with opaque paint. Once the page has been completely composed, invoking the showpage operator renders the accumulated marks on the output media and then clears the page to white again.

After many trials and errors and of course suggestions/comments from fellow SO users like @beginner6789 and @luserdroog (my thanks to both of them), I finally got something that works for my case. I am going to summarize my experiments and findings for benefits of others.

For this discussion, let's say you want to superimpose a page from Overlay.* (.ps or .pdf) on top of one particular page from Base.* (.ps or .pdf). There does not appear to be one solution fit all scenarios. It depends on:

  • If the you have Overlay.ps or Overlay.pdf. Although converting them is quite easy.
  • If the you have Base.ps or Base.pdf. Although converting them is quite easy.
  • If the Overlay.ps or Base.ps is auto-generated from corresponding pdf file or if they are handwritten. I found that the handwritten PostScript files are much cleaner, precise, and optimized compared to auto-generated PostScript files.
  • Logic becomes more complex depending upon which page/s of Overlay file you want super imposed on top of which page/s of Base file. You may have to do some extra work to identify those pages.

Following are 3 solutions that I tried. To summarize: Solution-3 worked for me as described by the last row of the corresponding results table.


Solution-1:

Create following Merge.ps and run it through your GhostScript to generate PDF output:

1 dict begin
    /showpage {} def
    (Base.ps) run     % or Base.pdf
    (Overlay.ps) run  % or Overlay.pdf
end
showpage

Results:

Base File Overlay File Results/Notes
Base.pdf Overlay.ps (Handwritten) Overlay file is appended at the end of the Base file
Base.pdf Overlay.ps (Converted from PDF) Overlay file is appended at the end of the Base file
Base.pdf Overlay.pdf Overlay file and a blank page is appended at the end of the Base file
Base.ps (Converted from PDF) Overlay.ps (Handwritten) Single page PDF with all pages from Base file and Overlay file are superimposed on top of each other
Base.ps (Converted from PDF) Overlay.ps (Converted from PDF) Single page PDF with page from Overlay file only
Base.ps (Converted from PDF) Overlay.pdf Same as Overlay file with blank page appended at the end

Does not appear to be a suitable option if Base file is multi-page file.


Solution-2:

Create following Merge.ps and run it through your GhostScript along with Base file to generate PDF output:

<<
    /EndPage
    {
        2 eq
        {
            pop false
        }
        {
            1 dict begin
                /showpage {} def
                (Overlay.ps) run  % or Overlay.pdf
            end
            pop true
        } ifelse
    } bind
>> setpagedevice

Additional logic is required if you want Overlay on only certain pages of the Base file.

Results:

Base File Overlay File Results/Notes
Base.pdf Overlay.ps (Handwritten) Overlay file is superimposed on top of every page of the Base file
Base.pdf Overlay.ps (Converted from PDF) Each page from Base file is replaced by the page from Overlay file
Base.pdf Overlay.pdf GhostScript crash after stack-overflow (no pun intended)
Base.ps (Converted from PDF) Overlay.ps (Handwritten) Overlay file is superimposed on top of every page of the Base file
Base.ps (Converted from PDF) Overlay.ps (Converted from PDF) Each page from Base file is replaced by the page from Overlay file
Base.ps (Converted from PDF) Overlay.pdf GhostScript crash

Solution-3:

Edit the Base.ps file that was converted from Base.pdf. Find the entry %%EndPageSetup corresponding to the page/s that you want overlay, and insert following code after that. Run it through your GhostScript to generate PDF output. In the example below I am editing it for the third page:

% BUNCH OF CODE NOT SHOWN HERE %
%%Page: 3 3
%%PageBoundingBox: 0 0 792 612
%%BeginPageSetup
8 0 obj
<</Type/Page/MediaBox [0 0 792 612]
/Parent 3 0 R
/Resources<</ProcSet[/PDF]
>>
/Contents 9 0 R
/CropBox 
[0 0 792.0 612.0]
>>
endobj
%%EndPageSetup
    1 dict begin                    % <== My Edits
        /showpage {} def            % <== My Edits
        (Overlay.ps) run            % <== My Edits
        % [1 0 0 -1 0 612] concat   % <== My Edits. See Notes below.
    end                             % <== My Edits
9 0 obj
% BUNCH OF CODE NOT SHOWN HERE %

Results:

Base File Overlay File Results/Notes
Base.ps (Converted from PDF & Edited) Overlay.ps (Handwritten) Overlay page is superimposed on top of the third page of the Base file
Base.ps (Converted from PDF & Edited) Overlay.ps (Converted from PDF) Overlay page is superimposed on top of the third page of the Base file, but the third page of the base file appears as a X-axis mirror of the original third page
Base.ps (Converted from PDF & Edited) Overlay.pdf Four page output of the Base file with Overlay page inserted as the third page.
Base.ps (Converted from PDF & Edited) Overlay.ps (Converted from PDF with the transformation matrix concatenation uncommented from code above) Overlay page is superimposed on top of the third page of the Base file as I wanted. This scenario works for me

In my case:

  • I had no control over how the Base.pdf file was generated, but I could convert it to Base.ps using GhostScript.
  • I had partial control over Overlay file generation. I had XML data, which I converted to table format using XSLFO, and then converted to PDF and PostScript file using Apache FOP.
  • I really had no option of manually writing Base.ps or Overlay.ps.

Considering, results of all these trials and errors, at this time the Solution-3 (with transformation matrix concatenated after the run command, the last row from that results table) is working for me. I don't particularly like this option, because it involves editing the auto-generated PostScript file.

NOTE: For all those cases where I saw that the page from Base file is being replaced by Overlay page, I think the original page from the Base file is being printed outside the output page size hence it is clipped and does not show and appears as being replaced. Maybe proper manipulation of the transformation matrix would fix those cases. I am yet to experiment with that scenario but don't know how to verify.

Related