我正在使用 GhostScript(当前为 9.27)来减小应用程序中 PDF 文件的大小,然后再将其上传到文件服务器。 我面临的问题是,某些 PDF 文件被转换为空白 PDF 文件,但是,如果我使用 Adobe Acrobat 打开原始 PDF 文件并保存它,然后执行我的 GhostScript 程序,它运行正常,PDF 将显示并显示正确“压缩”(质量降低)。
我尝试了不同的 PDF 设置,但所需的设置是 /ebook,所以我想让它以电子书质量工作。 我正在使用 GhostScript 包装器(将在此处发布代码),我调用的函数是:
RunGS("-dQUIET", "-dBATCH", "-dNOPAUSE", "-dNOGC", "-dPDFSETTINGS=/ebook", , "-sDEVICE=pdfwrite", "-sOutputFile=" & OUTPUT_FILE, INPUT_FILE)
当最终结果是空白 PDF 文件时,需要比平时更长的时间,并且返回此错误:
我刚刚注意到我收到了错误回调......它说:
GhostScript不可恢复错误,退出代码-100
这是非工作文件(原始):https://docdro.id/YuZslRm
这是使用 Acrobat 开始保存后的文件,效果很好:https://docdro.id/cAoUCS5
这是包装纸,以防万一:
模块 GhostscriptDllLib
Private Declare Function gsapi_new_instance Lib "gsdll32.dll" _
(ByRef instance As IntPtr, _
ByVal caller_handle As IntPtr) As Integer
Private Declare Function gsapi_set_stdio Lib "gsdll32.dll" _
(ByVal instance As IntPtr, _
ByVal gsdll_stdin As StdIOCallBack, _
ByVal gsdll_stdout As StdIOCallBack, _
ByVal gsdll_stderr As StdIOCallBack) As Integer
Private Declare Function gsapi_init_with_args Lib "gsdll32.dll" _
(ByVal instance As IntPtr, _
ByVal argc As Integer, _
<MarshalAs(UnmanagedType.LPArray, ArraySubType:=UnmanagedType.LPStr)> _
ByVal argv() As String) As Integer
Private Declare Function gsapi_exit Lib "gsdll32.dll" _
(ByVal instance As IntPtr) As Integer
Private Declare Sub gsapi_delete_instance Lib "gsdll32.dll" _
(ByVal instance As IntPtr)
'--- Run Ghostscript with specified arguments
Public Function RunGS(ByVal ParamArray Args() As String) As Boolean
Dim InstanceHndl As IntPtr
Dim NumArgs As Integer
Dim StdErrCallback As StdIOCallBack
Dim StdInCallback As StdIOCallBack
Dim StdOutCallback As StdIOCallBack
NumArgs = Args.Count
StdInCallback = AddressOf InOutErrCallBack
StdOutCallback = AddressOf InOutErrCallBack
StdErrCallback = AddressOf InOutErrCallBack
'--- Shift arguments to begin at index 1 (Ghostscript requirement)
ReDim Preserve Args(NumArgs)
System.Array.Copy(Args, 0, Args, 1, NumArgs)
'--- Start a new Ghostscript instance
If gsapi_new_instance(InstanceHndl, 0) <> 0 Then
Return False
Exit Function
End If
'--- Set up dummy callbacks
gsapi_set_stdio(InstanceHndl, StdInCallback, StdOutCallback, StdErrCallback)
'--- Run Ghostscript using specified arguments
gsapi_init_with_args(InstanceHndl, NumArgs + 1, Args)
'--- Exit Ghostscript
gsapi_exit(InstanceHndl)
'--- Delete instance
gsapi_delete_instance(InstanceHndl)
Return True
End Function
'--- Delegate function for callbacks
Private Delegate Function StdIOCallBack(ByVal handle As IntPtr, _
ByVal Strz As IntPtr, ByVal Bytes As Integer) As Integer
'--- Dummy callback for standard input, standard output, and errors
Private Function InOutErrCallBack(ByVal handle As IntPtr, _
ByVal Strz As IntPtr, ByVal Bytes As Integer) As Integer
Dim objString As String
objString = Marshal.PtrToStringAnsi(Strz, Bytes)
Return 0
End Function
关于如何避免这种情况有什么想法吗?我不介意采取快速流程或其他方式。正如我所说,这种情况仅发生在某些特定文件(我们从客户那里获取)中,但其中 98% 的文件大小可能已正确减小。
好吧,你说“它不会提示任何错误”,但是当我在这里运行你的文件时,Ghostscript 首先说:
**** Warning: Discovered more entries in xref than declared in trailer /Size
**** Warning: File has an invalid xref entry: 2. Rebuilding xref table.
然后在每一页上都写着:
**** Error: stream operator isn't terminated by valid EOL.
Output may be incorrect.
**** Error: stream operator isn't terminated by valid EOL.
Output may be incorrect.
最终结果是:
**** This file had errors that were repaired or ignored.
**** The file was produced by:
**** >>>> <<<<
**** Please notify the author of the software that produced this
**** file that it does not conform to Adobe's published PDF
**** specification.
**** The rendered output from this file may be incorrect.
我会说这是相当多的错误。请注意,当您从 Acrobat 保存文件时,它自然会修复这些语法问题,因此 Ghostscript 当然不会抱怨,因为保存的文件是有效的。
也就是说,使用基于您的命令行:
"c:\program files\gs\gs9.27\bin\gswin64c" -sDEVICE=pdfwrite -sOutputFile=out.pdf -dBATCH -dNOPAUSE -dNOGC -dPDFSETTINGS=/ebook 20194114_EXPORT_DOCS_Original.pdf
产生的警告较少,因为您已指定
-dQUIET
。如果您正在尝试调查问题,那么抑制警告可能并不理想。您是否看到 Ghostscript 的任何反向通道输出?如果是这样,您也应该将其发布在这里。如果没有,那么您需要实现代码来捕获它,这是重要的信息。
注意不要使用
-dNOGC
,那是一个仅调试开关。我知道,人们不断将其发布为命令行的一部分,通常是因为他们“研究了它”(在 Google 上找到了它)。不要使用它。
无论如何,通过该命令行,我得到了一个 PDF 文件,该文件看起来很合理,并且大小是原始文件的 20%。
使用你的命令行(或尽可能接近它的东西)不会为我重现问题(无论是在 32 位还是 64 位,使用当前代码或 9.27 版本),所以我只能推测问题。如果您设置了
-dPDFSTOPONERROR
,则会在读取文件时立即退出(带有冗长的错误消息),并会生成一个空的 PDF 文件。我想不出任何其他方法可以做到这一点,尤其是“没有错误”。
FWIW 默认情况下 Ghostscript 会尝试修复无效的 PDF 文件,或者至少尽可能忽略错误。
PDFSTOPONERROR
开关旨在用于商业环境,在商业环境中,重要的是对那些 可能 无法正确渲染的文件进行标记和检查/拒绝/修复,而不是浪费地打印。
在哪张纸条上;我注意到您似乎在商业上使用 Ghostscript,并且正在链接到 DLL。我觉得我应该向您指出提供 Ghostscript 的许可证 (AGPL v3),您可能应该检查您的使用在该许可证的条款下是否有效。