在 PDF 文件之上叠加一个 PS 文件

Overlay a PS file on top of PDF file

我发现有人回答了类似的问题 Overlay two postscript files (command line approach)?,但是,该解决方案对我不起作用,而且我的要求有点不同(我的一个文件是多页文件)

我有一个在我控制之外生成的 PDF 文件 (DrawingSheet.pdf)。我有一个 PostScript 文件 (Table.ps),它是通过使用 XSLFO 和 Apache FOP 转换 XML 文件生成的。 Table.ps 包含一个 table.

DrawingSheet.pdf 有多个页面。 Table.ps 只有一页。 DrawingSheet.pdfTable.ps 具有相同的纸张尺寸 - A 尺寸,横向。我想将 Table.ps 中的 table 放在 DrawingSheet.pdf 最后一页的顶部。我不想在 DrawingSheet.pdf 末尾“追加”table 页面作为附加页面。我正在使用命令行 GhostScript (v9.27)。

根据 post 的建议,我写了以下 Overlay.ps 文件:

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

那是行不通的。我得到的是 table 页面“附加”到 DrawingSheet.pdf 而不是覆盖在最后一页的顶部。

我做错了什么?我怎样才能达到我想要的?

已编辑-1:

如果两个文件中的页数相同有助于简化逻辑,那么我可以生成 Table.ps 以具有与 DrawingSheet.pdf 文件相同的页数并使 table 仅出现在 Table.ps.

的最后一页

已编辑-2:

或者,我尝试了以下方法(类似于向 PDF 文件添加图像水印)。这样做的最终结果是我的空白页数与 DrawingSheet.pdf 中的页数一样多。有趣的是,当我加载生成的空白 PDF 时,我可以看到 Acrobat Reader 在屏幕上闪烁 table,但是当加载整个文件时,我最后看到的都是空白页。

非常感谢任何解决此问题的帮助。

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

Edited-2 - 附加说明:如果我从上面的代码中注释掉 gsavegrestore,那么我不会得到空白页,但是现在每个页面都被 Table.ps.

中的 table“替换”(无覆盖)

Edited-3 - 部分成功:

在遇到这个 post: 之后,我尝试了这种方法。我将 DrawingSheet.pdf 转换为 DrawingSheet.ps,确定了最后的 %%EndPageSetup 行,并在该行之后插入了以下代码:

% 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 %

通过此编辑(gsave 和 grestore 被注释掉了 - 如果我取消注释它们则这不起作用),我将我的 table super 强加在最后一页上。 Table 看起来不错,但是 pdf 中的原始最后一页在叠加后显示为在 X 轴中心翻转。页面截图为:

可以阅读的文字来自Table.ps,而翻转的文字是DrawingSheet.pdf最后一页的原文(当然原始pdf中的那一页不是翻转)。

不确定我做错了什么来获得翻转的图像?

已编辑 4:

为“Edited-2”添加了附加注释

我试过你的尾页,终于让这种方法起作用了。 EndPage 将原因代码 0 或 1 和页面计数放在堆栈上(对于某些 pdf 来说不可靠),因此替代方法是 /PageCount 变量,我将两者都显示。这些计算页数并在页面末尾递增。

在页面完成之前,您需要知道在页面上放置叠加层的页数。 “finalpage”变量也可以在 ghostscript 命令行而不是在文件中定义。 运行 ghostscript 将您的 endpage.ps 和 DrawingSheet.ps 文件作为参数。需要做更多的工作才能使它适应 DrawingSheet.pdf,除非这应该是可能的。

更改最终页码后看看这是否有效。 table.ps 应该在执行显示页面之前放在原始最后一页的顶部。

%!
/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

编辑:后记语言参考手册 3 第 176 页这样说:

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.

经过多次试验和错误,当然还有来自@beginner6789 和@luuserdroog 等 SO 用户的 suggestions/comments(感谢他们),我终于得到了适合我的案例的东西。为了其他人的利益,我将总结我的实验和发现。

对于此讨论,假设您想将来自 Overlay.*(.ps 或 .pdf)的页面叠加在来自 Base.*(.[=)的特定页面之上99=] 或.pdf)。似乎没有一种解决方案适合所有情况。这取决于:

  • 如果您有 Overlay.psOverlay.pdf。虽然转换它们很容易。
  • 如果您有 Base.psBase.pdf。虽然转换它们很容易。
  • 如果 Overlay.psBase.ps 是从相应的 pdf 文件自动生成的,或者它们是手写的。我发现与自动生成的 PostScript 文件相比,手写的 PostScript 文件更加清晰、精确和优化。
  • 逻辑变得更加复杂,具体取决于您要将哪个 page/s 个叠加文件叠加在哪个 page/s 个基础文件之上。您可能需要做一些额外的工作来识别这些页面。

以下是我尝试过的 3 种解决方案。总结一下:正如相应结果的最后一行所描述的那样,Solution-3 对我有用 table.


方案一:

通过 GhostScript 创建以下 Merge.ps 和 运行 以生成 PDF 输出:

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

结果:

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

如果基本文件是多页文件,则似乎不是 suitable 选项。


方案二:

通过您的 GhostScript 创建以下 Merge.ps 和 运行 它以及 Base 文件以生成 PDF 输出:

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

如果您只想在基本文件的某些页面上叠加,则需要额外的逻辑。

结果:

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

方案三:

编辑从 Base.pdf 转换而来的 Base.ps 文件。找到要覆盖的 page/s 对应的条目 %%EndPageSetup ,然后在其后插入以下代码。 运行 它通过您的 GhostScript 生成 PDF 输出。在下面的示例中,我正在为第三页编辑它:

% 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 %

结果:

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

就我而言:

  • 我无法控制 Base.pdf 文件的生成方式,但我可以使用 GhostScript 将其转换为 Base.ps。
  • 我可以部分控制覆盖文件的生成。我有 XML 数据,我使用 XSLFO 将其转换为 table 格式,然后使用 Apache FOP 将其转换为 PDF 和 PostScript 文件。
  • 我真的没有办法手动写 Base.ps 或 Overlay.ps。

考虑到所有这些试验和错误的结果,此时 Solution-3(在 运行 命令后连接转换矩阵,结果的最后一行 table)正在运行为了我。我不是特别喜欢这个选项,因为它涉及编辑自动生成的 PostScript 文件。

注意:对于我看到基本文件中的页面被覆盖页面替换的所有这些情况,我认为基本文件中的原始页面被打印在输出页面大小之外,因此它被剪裁并且确实不显示并显示为被替换。也许对转换矩阵的适当操作可以解决这些问题。我还没有尝试过这种情况,但不知道如何验证。