【问题标题】:GhostScript generates a blank PDF file on a specific PDF documentGhostScript 在特定 PDF 文档上生成空白 PDF 文件
【发布时间】:2019-08-29 09:35:03
【问题描述】:

在将 PDF 文件上传到文件服务器之前,我正在使用 GhostScript(当前为 9.27)来减小应用程序中 PDF 文件的大小。 我面临的问题是某些 PDF 文件被转换为空白 PDF 文件,但是,如果我使用 Adob​​e Acrobat 打开原始 PDF 文件并保存它,然后执行我的 GhostScript 程序,它运行良好,PDF 显示并且是正确“压缩”(降低质量)。

我尝试了不同的 PDF 设置,但所需的是 /ebook,所以我想让它与电子书质量一起使用。 我正在使用 GhostScript Wrapper(将在此处发布代码),我正在调用的函数是:

RunGS("-dQUIET", "-dBATCH", "-dNOPAUSE", "-dNOGC", "-dPDFSETTINGS=/ebook", , "-sDEVICE=pdfwrite", "-sOutputFile=" & OUTPUT_FILE, INPUT_FILE)

当最终结果为空白 PDF 文件并返回此错误时,它比平时花费更长的时间:

我刚刚注意到我收到了一个错误回调...它说:

GhostScriptUnrecoverable 错误,退出代码 -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% 的文件大小正确减小。

【问题讨论】:

  • 您必须提供一个完整 PDF文件来显示问题,它不必在这里,您可以将它放在其他地方并发布链接. PDF 文件的“标题”只是第一行(可选的第二行注释二进制文件),在您的情况下是 %PDF-1.3 行。其余部分是 PDF 文件的正文。如果你有问题,那么你真的应该打开一个错误报告(bugs.ghostscript.com)。您可以使用 Ghostscript 命令行可执行文件重现此问题吗?如果不是,那么它可能是你正在做的事情。如果是,那么您最好打开一个错误。
  • 感谢您的建议。我编辑了帖子,添加了 2 个链接。我将尝试学习如何使用命令行执行它并在此处通知。

标签: .net pdf ghostscript


【解决方案1】:

好的,所以你说“它不会提示任何错误”,但是当我在这里运行你的文件时,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),您可能应该检查您的使用是否根据该许可证的条款有效。

【讨论】:

  • 非常感谢!那里有很多好信息。当我说我没有错误时,我指的是 .net 包装器,但可能它没有给我必要的信息,正如你所说,我需要以某种方式捕获它,因为我没有任何反馈权现在。使用控制台会提示您提到的错误(包括文件可能无法读取),但是,正如您所说,它可以正确打开(质量相当好,从 2.5MB 减少到 400KB)。我尝试了 PDFSTOPONERROR 参数,但似乎没有影响。我可能需要实施新的包装器或进一步调查。
  • 我刚刚注意到我收到了一个错误回调...它说:GhostScriptGPL Ghostscript GhostScript9.27 GhostScript: GhostScriptUnrecoverable error, exit code -100
  • -100 是 gs_error_Fatal,它只是意味着“发生了非常糟糕的事情,不知道是什么,但它的终端”。如果您想查看反向通道信息(这在出现问题时实际上很有用,所以我推荐它)您需要实现 stdout 和 stderr 回调。对我来说 -dPDFSTOPONERROR 会引发一个正常的 PostScript 错误并退出。我想不出你的包装器是如何以一个空文件结束的,但是错误 -100 是一个不错的选择,当出现错误时,pdfwrite 设备将关闭输出文件,如果还没有发生任何事情,那么它将是空的(如 -dPDFSTOPONERROR)
  • 由于这是一个非常偶然的错误,我已经通过评估 StdIOCallBack 结束,如果它提示错误,我只是跳过“压缩”并将原始文件放入数据库。保持文件的完整性而不是获得一些空间要好得多。感谢您的知识和帮助!
猜你喜欢
  • 2021-07-11
  • 1970-01-01
  • 2016-10-31
  • 2019-05-24
  • 2013-12-22
  • 2011-07-22
  • 2020-12-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多