Ghostscript 不转换带有附件的 pdf 文件

Ghostscript does not convert pdf file with attachments

ghostcript(版本 9.21)忽略 pdf 文件中的附件

使用的命令 cmd /c %GHOST_SCRIPT_EXE% -dPDFA=2 -dBATCH -dNOPAUSE -dSubsetFonts=false -dPDFSETTINGS=/printer -sProcessColorModel=DeviceRGB -sDEVICE=pdfwrite -dCompatibilityLevel=1.7 -dOptimize=true -dPDFACompatibilityPolicy=1 -dAutoRotatePages= /None -sOutputFile="out.pdf" "test.pdf"

如您所见,test.pdf 有一个附件 1.pdf。但在转换后的 pdf 中,即 out.pdf 没有 1.pdf。

附上pdf文件test.pdf and out.pdf

这不仅仅是一个附件,它是一个嵌入文件。

由于多种原因,没有复制嵌入的数据。首先是因为我们在 Ghostscript 中根本不支持嵌入式文件(我们不能对它们做任何有用的事情),其次是因为您正在创建一个 PDF/A 文件。

如果嵌入文件也是 PDF/A 文件,则嵌入文件仅在 PDF/A 中有效(您的嵌入文件不是 PDF/A PDF 文件,因此需要转换第一的)。 Ghostscript 无法轻松验证这一点,因此我们(再次)不复制嵌入文件。

您(当然)可以自己增强 Ghostscript 来做到这一点。您将需要处理 /EF(嵌入式文件)密钥并使用 pdfmarks 创建流,然后将其插入到 FileAttachment 注释中的 /FS (FileSpec) 密钥的字典中。

[编辑]

当前的 Ghostscript PDF 解释器是用 PostScript 编写的。如果你查看 /ghostpdl/Resource/Init/pdf_draw.ps 你会看到:

/FileAttachment {mark exch loadannot /ANN pdfmark  false} bdef

这是处理 FileAttachment 注释的地方。可以看到使用loadannot函数将注解字典转化为一系列的字符串存储在操作数栈中,然后加上/Ann并调用pdfmark对字符串进行处理。

您可以在 Adob​​e pdfmark 参考文档中找到 pdfmark 运算符(在 Adob​​e 网站的某处可用,我推荐 Google,他们一直在移动它)。

这是原始文件的样子,您需要创建 pdfmarks 才能重现:

23 0 obj
<<
  /AP <<
    /N 26 0 R
  >>
  /C [ 0.25 0.333328009 1 ]
  /Contents (1.pdf)
  /CreationDate (D:20180402114155+05'30')
  /F 28
  /FS 24 0 R                              
  /NM (55b56d89-a71e-484c-bf64-e4608540304b)
  /Name /Paperclip

  /RC (<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:11.0.21" xfa:spec="2.0.2" ><p>1.pdf</p></body>)
  /Rect [ 200.852997 727.552979 207.852997 744.552979 ]
  /Subj (File Attachment)
  /Subtype /FileAttachment
  /T (ybn9mk)
  /Type /Annot
>>
endobj

24 0 obj
<<
  /EF <<
    /F 25 0 R
  >>
  /F (1.pdf)
  /Type /Filespec
  /UF (1.pdf)
>>
endobj

25 0 obj
<<
  /DL 82637
  /Subtype /application#2Fpdf
  /Length 82637
  /Params <<
    /CheckSum <EC9AED504CB6442F260E1379E21A0873>
    /CreationDate (D:20180402114059+05'30')
    /ModDate (D:20170907123559+05'30')
    /Size 82637
  >>
>>
stream
%PDF-1.5
.....
.... embedded PDF file here
....
....
endstream
endobj

当前的 Ghostscript 实现将重现对象 23,即 FileAttachement 注释,并将正确地扩展 /EF 字典内联到该注释中。但是,它不会写入对象 25,即实际的嵌入式 PDF 文件。

因此您需要添加代码来读取嵌入式文件对象,使用 pdfmark 将其写入命名内容流,然后从 FileSpec 字典中的 /EF 键引用该命名对象流(对象 24 in原始文件,但在 pdfwrite 输出中展开并内联)。

除非您非常熟悉 PostScript,否则这将是一个相当大的挑战。