.net GhostScript在特定PDF文档上生成空白PDF文件

.net GhostScript在特定PDF文档上生成空白PDF文件,.net,pdf,ghostscript,.net,Pdf,Ghostscript,我正在使用GhostScript(目前为9.27)在上传到文件服务器之前减小应用程序中PDF文件的大小。 我面临的问题是,一些PDF文件被转换为空白PDF文件,但是,如果我用Adobe Acrobat打开原始PDF文件并保存,然后执行我的GhostScript rutine,它运行正常,PDF将显示并正确“压缩”(质量降低) 我尝试过不同的PDF设置,但是理想的设置是/ebook,所以我想让它与ebook质量一起工作。 我正在使用GhostScript包装器(将在此处发布代码),我正在调用的函数

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

我尝试过不同的PDF设置,但是理想的设置是/ebook,所以我想让它与ebook质量一起工作。 我正在使用GhostScript包装器(将在此处发布代码),我正在调用的函数是:

RunGS("-dQUIET", "-dBATCH", "-dNOPAUSE", "-dNOGC", "-dPDFSETTINGS=/ebook", , "-sDEVICE=pdfwrite", "-sOutputFile=" & OUTPUT_FILE, INPUT_FILE)
当最终结果为空白PDF文件且返回此错误时,所需时间比通常情况下长:


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

GhostScriptUnrecoverable错误,退出代码-100

这是非工作文件(原件):

这是使用Acrobat开始保存后的文件,它工作正常:

这里是包装器,以防万一:

模块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
私有声明函数gsapi\u new\u实例库“gsdll32.dll”_
(ByRef实例作为IntPtr_
ByVal调用者(作为IntPtr的句柄)作为整数
专用声明函数gsapi_set_stdio Lib“gsdll32.dll”_
(ByVal实例作为IntPtr_
ByVal gsdll_stdin作为标准回调_
ByVal GSDLLu stdout作为标准回调_
ByVal gsdll_stderr作为StdIOCallBack)作为整数
带有参数库“gsdll32.dll”的私有声明函数gsapi_init__
(ByVal实例作为IntPtr_
ByVal argc作为整数_
_
ByVal argv()作为字符串)作为整数
私有声明函数gsapi_exit Lib“gsdll32.dll”_
(作为IntPtr的ByVal实例)作为整数
私有声明子gsapi_delete_实例库“gsdll32.dll”_
(作为IntPtr的ByVal实例)
“---使用指定的参数运行Ghostscript
作为布尔值的公共函数梯级(ByVal ParamArray Args()作为字符串)
Dim实例HNDL作为IntPtr
作为整数的Dim NumArgs
将StdErrCallback设置为StdIOCallBack
将StdInCallback设置为StdIOCallBack
将StdOutCallback设置为StdIOCallBack
NumArgs=Args.Count
StdInCallback=InOuterCallback的地址
StdOutCallback=InOuterCallback的地址
StdErrCallback=inoutercallback的地址
'---将参数从索引1开始移位(Ghostscript要求)
ReDim保留参数(NumArgs)
System.Array.Copy(Args,0,Args,1,NumArgs)
'---启动一个新的Ghostscript实例
如果gsapi_new_实例(InstanceHndl,0)为0,则
返回错误
退出功能
如果结束
“---设置虚拟回调
gsapi_set_stdio(InstanceHndl、StdInCallback、StdOutCallback、StdErrCallback)
“---使用指定的参数运行Ghostscript
带参数的gsapi_init_(InstanceHndl,NumArgs+1,参数)
'---退出鬼脚本
gsapi_出口(实例HNDL)
'---删除实例
gsapi_delete_实例(InstanceHndl)
返回真值
端函数
'---回调的委托函数
私有委托函数StdIOCallBack(作为IntPtr的ByVal句柄_
ByVal Strz作为IntPtr,ByVal字节作为整数)作为整数
'---标准输入、标准输出和错误的伪回调
InOuterCallback中的私有函数(作为IntPtr的ByVal句柄_
ByVal Strz作为IntPtr,ByVal字节作为整数)作为整数
将对象字符串变暗为字符串
objString=Marshal.PtrToStringAnsi(Strz,字节)
返回0
端函数

有没有办法避免这种情况?我不介意采取快速流程或其他方式。正如我所说,这种情况只发生在某些特定的文件中(我们从客户那里获得),但可能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.
生成的警告较少,因为您已指定-dQUIET。如果您试图调查一个问题,那么抑制警告可能并不理想。您是否看到来自Ghostscript的任何反向通道输出?如果是这样,你也应该把它贴在这里。如果没有,那么您需要实现代码来捕获它,它是重要的信息

注意:不要使用
-dNOGC
,这是一个仅用于调试的开关。我知道,人们一直把它作为命令行的一部分发布,通常是因为他们“研究过”(在谷歌上找到的)。不要用它

不管怎样,通过这个命令行,我得到了一个看起来合理的PDF文件,大小是原始文件的20%

使用您的命令行(或尽可能接近它的命令行)不会为我重现问题(使用当前代码或9.27版本,在32位或64位上),因此我只能推测问题。如果您设置了
-dpdfstophoron
,该错误将在读取文件时立即退出(显示一条很长的错误消息),并将生成一个空的PDF文件。我想不出任何其他的方法,尤其是“没有错误”

默认情况下,FWIW Ghostscript尝试修复无效的PDF文件,或者至少尽可能忽略错误。PDFSTopError开关适用于商业环境,在商业环境中,重要的是标记并检查/拒绝/修复可能无法正确呈现的文件,而不是浪费打印


在哪一个音符上;我注意到您似乎在商业上使用Ghostscript,并且正在链接到DLL。我觉得我应该向您指出提供Ghostscript的许可证(AGPL v3),您可能应该检查您的使用是否在该许可证的条款下有效。

好的,所以您会说“它不会提示任何错误”,但是当我在这里运行您的文件时,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.
生成的警告较少,因为您已指定-dQUIET。如果您试图调查一个问题,那么抑制警告可能并不理想。您是否看到任何反向通道输出