如何使用 Ghostscript Wrapper VB.NET 将 PDF 页面转换为 PNG?

How to convert PDF pages to PNG using Ghostscript Wrapper VB.NET?

我正在尝试使用以下解决方案将数字签名的 PDF 转换为 PNG:Simple VB.Net Wrapper for Ghostscript Dll。它对我也不起作用。我正在使用 Ghostscript 9.18 32 位。

首先,这部分源码转到InOutErrCallBack方法:

gsapi_init_with_args(InstanceHndl, NumArgs + 1, Args)

发生这种情况时,执行冻结。发生这种情况后,接下来调用 RunGS 方法 returns false 在这部分:

If gsapi_new_instance(InstanceHndl, IntPtr.Zero) <> 0 Then
    Return False
    Exit Function
End If

gsapi_new_instance的return值为-100: Ghostscript API - Return codes

gswin32.dll 在 C:\Windows\System32 和 BIN 项目文件夹中。

我的参数序列:

Dim outputImgPath As String
outputImgPath = "C:\Download\DocumentosV2\Protocolo\Pronunciamento\" + Guid.NewGuid.ToString("N") + ".png"

Dim args() As String = { _
    "-dNOPAUSE", _
    "-dBATCH", _
    "-dSAFER", _
    "-dQUIET", _
    "-sDEVICE=png16m", _
    String.Format("-r{0}", resolucao), _
    "-dTextAlphaBits=2", _
    "-dGraphicsAlphaBits=2", _
    String.Format("-dFirstPage={0}", pageNumber), _
    String.Format("-dLastPage={0}", pageNumber), _
    String.Format("-sOutputFile={0}", outputImgPath), _
    "-f", _
    pdfPath _
    }

更新

@kens 建议我提出一些论点。因此,我将其删除以进行测试。

我的完整代码:

Imports PdfSharp
Imports System
Imports System.Collections
Imports System.IO
Imports System.Text
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports PdfSharp.Pdf
Imports PdfSharp.Pdf.IO
Imports PdfSharp.Drawing

'''
''' http://www.geekscrapbook.com/2009/11/16/c-method-to-add-an-image-to-a-pdf/
'''
Public Class PDF2Image2PDF
    Inherits Simp.Net.Infra.SimpComponent

    Private SyncRoot As New Object

    'Converte cada página do PDF em imagem
    Public Function Pdf2Png(ByVal pdfPath As String, ByVal resolucao As Int32) As Image()

        Dim outputImgPath As String
        Dim pageCount As Integer

        Dim objPdfReader As New iTextSharp.text.pdf.PdfReader(pdfPath)
        pageCount = objPdfReader.NumberOfPages()

        Dim objImages As New ArrayList

        For pageNumber As Int32 = 1 To pageCount
            outputImgPath = "C:/Download/DocumentosV2/Protocolo/Pronunciamento/" + Guid.NewGuid.ToString("N") + ".png"
            Dim objFileStream As FileStream
            Dim objMemoryStream As MemoryStream

            'Dim args() As String = { _
            '    "-dNOPAUSE", _
            '    "-dBATCH", _
            '    "-dSAFER", _
            '    "-dQUIET", _
            '    "-sDEVICE=png16m", _
            '    String.Format("-r{0}", resolucao), _
            '    "-dTextAlphaBits=2", _
            '    "-dGraphicsAlphaBits=2", _
            '    String.Format("-dFirstPage={0}", pageNumber), _
            '    String.Format("-dLastPage={0}", pageNumber), _
            '    String.Format("-sOutputFile={0}", outputImgPath), _
            '    "-f", _
            '    pdfPath _
            '    }

            Dim args() As String = { _
                "-dNOPAUSE", _
                "-dBATCH", _
                "-sDEVICE=png16m", _
                String.Format("-dFirstPage={0}", pageNumber), _
                String.Format("-dLastPage={0}", pageNumber), _
                String.Format("-sOutputFile={0}", outputImgPath), _
                Replace(pdfPath, "\", "/") _
                }

            If GhostscriptDllLib.RunGS(args) Then
                If File.Exists(outputImgPath) Then
                    objFileStream = New FileStream(outputImgPath, FileMode.Open)
                    Dim length As Int32 = objFileStream.Length
                    Dim bytes(length) As Byte
                    objFileStream.Read(bytes, 0, length)
                    objFileStream.Close()

                    objMemoryStream = New MemoryStream(bytes, False)

                    objImages.Add(Image.FromStream(objMemoryStream))
                Else
                    Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
                End If
            Else
                Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
            End If

        Next

        Return CType(objImages.ToArray(GetType(Image)), Image())

    End Function

    'Converte cada imagem do vetor em uma página do PDF
    Public Function Images2PDF(ByVal imagens() As Image) As PdfDocument
        Dim pdf As PdfDocument
        Dim gfx As XGraphics
        Dim ximg As XImage

        pdf = New PdfDocument

        For Each img As Image In imagens
            pdf.AddPage(New PdfPage)
            gfx = XGraphics.FromPdfPage(pdf.Pages.Item(0))
            ximg = XImage.FromGdiPlusImage(img)

            gfx.DrawImage(ximg, 0, 0)

            ximg.Dispose()
            gfx.Dispose()

        Next

        Return pdf
    End Function

End Class

来电号码:

Public Sub DownloadPeticionamento(ByVal sender As System.Object, ByVal e As System.web.UI.ImageClickEventArgs)
    Dim imagem As ImageButton = DirectCast(sender, ImageButton)
    Dim pdfPath As String = imagem.DescriptionUrl

    Dim objPdfPeticionamento As New Simp.Net.Negocio.PDF2Image2PDF

    Dim objImages() As Image
    Dim objPdfDoc As PdfDocument
    objImages = objPdfPeticionamento.Pdf2Png(pdfPath, 600)

    objPdfDoc = objPdfPeticionamento.Images2PDF(objImages)
    objPdfDoc.Save(Me.Page.Response.OutputStream, True)

End Sub

我在命令行中对此进行了测试:

gswin32c -dNOPAUSE -dBATCH -sDEVICE=png16m -sOutputFile=C:/Download/DocumentosV2/Protocolo/Pronunciamento/fb21872746b64f8fb31b3764b5444e2e.png C:/Upload/DocumentosV2/Protocolo/Pronunciamento/3_0_404702190_2016_10081288_230_0_f1f09b4b38ac49a8a3e5576f6041eea3.pdf

通过命令行,pdf被转换。命令行输出:

C:\Documents and Settings\leandro.ferreira>gswin32c -dNOPAUSE -dBATCH -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -sOutputFile=C:/Download/DocumentosV2/Protocolo/Pronunciamento/fb21872746b64f8fb31b3764b5444e2e.png C:/Upload/DocumentosV2/Protocolo/Pronunciamento/3_0_404702190_2016_10081288_230_0_f1f09b4b38ac49a8a3e5576f6041eea3.pdf
GPL Ghostscript 9.16 (2015-03-30)
Copyright (C) 2015 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
Processing pages 1 through 1.
Page 1
Can't find (or can't open) font file %rom%Resource/Font/Arial-BoldMT.
Can't find (or can't open) font file Arial-BoldMT.
Can't find (or can't open) font file %rom%Resource/Font/Arial-BoldMT.
Can't find (or can't open) font file Arial-BoldMT.
Querying operating system for font files...
Didn't find this font on the system!
Substituting font Helvetica-Bold for Arial-BoldMT.
Loading NimbusSan-Bol font from %rom%Resource/Font/NimbusSan-Bol... 4047240 2487522 8937716 7603550 3 done.
Can't find (or can't open) font file %rom%Resource/Font/ArialMT.
Can't find (or can't open) font file ArialMT.
Can't find (or can't open) font file %rom%Resource/Font/ArialMT.
Can't find (or can't open) font file ArialMT.
Didn't find this font on the system!
Substituting font Helvetica for ArialMT.
Loading NimbusSan-Reg font from %rom%Resource/Font/NimbusSan-Reg... 4080352 2580805 9014744 7662839 3 done.

C:\Documents and Settings\leandro.ferreira>

-100 就是 'fatal error',即发生了非常糟糕的事情。更多信息通常打印到 stdout 或 stderr,当然设置 -dQUIET 会抑制其中的大部分内容....

因为你得到 -100 返回几乎可以肯定你对 Ghostscript 的参数在某些方面是不正确的。

调试问题时绝对应该做的第一件事就是尝试简化问题,因此请删除您毫无疑问需要的所有开关。

所以要做的第一件事就是删除 -dQUIET,捕获所有 stdout/stderr 输出并告诉我们它说的是什么。

除此之外,请注意以下事项:

您不需要“-f”,因为该开关的唯一目的是终止您未使用的 -c。

您尚未提供 'resolucao'、'pageNumber' 或 'pdfPath' 的值,因此无法知道这些值是否有效(或合理)。您为 outputImgPath 指定的路径很长,并且包含反斜杠字符。我建议改用正斜杠“/”,因为反斜杠用于开始转义并可能产生您可能意想不到的结果。

您也使用过 -dSAFER,您了解指定此选项的含义吗?如果不是,请将其删除并重试。

创建字符串后 'args' 将其打印出来。至少这会给你一些你可以从命令行尝试的东西,并且可能意味着其他人有机会重现你的问题。

最后;请注意,Ghostscript 是根据 Affero General Public 许可证分发的,请务必阅读许可证并确保您遵守其中包含的条款。

为了完成这项工作,我修改了 Simple VB.Net Wrapper for Ghostscript Dll 回调:

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)

    System.Diagnostics.Debug.WriteLine(objString)

    Return Bytes

End Function

这会将 Ghostscript 输出写入 Output window 的 Visual Studio 2003。我删除了 Ghostscript 的额外 "needless" 参数,喜欢 -dGraphicsAlphaBits。 asp.net 用户无法访问 Path.GetTempDir,因此,我需要一个不同的 "temp" 目录。

'Converte cada página do PDF em imagem
Public Function Pdf2Png(ByVal pdfPath As String, ByVal tempDirPath As String, ByVal resolucao As Int32) As Image()

    Dim outputImgPath As String
    Dim pageCount As Integer

    Dim objPdfReader As New iTextSharp.text.pdf.PdfReader(pdfPath)
    pageCount = objPdfReader.NumberOfPages()

    Dim objImages As New ArrayList

    For pageNumber As Int32 = 1 To pageCount
        outputImgPath = tempDirPath + Guid.NewGuid.ToString("N") + ".png"

        Dim objFileStream As FileStream
        Dim objMemoryStream As MemoryStream

        'Dim args() As String = { _
        '    "-dNOPAUSE", _
        '    "-dBATCH", _
        '    "-dSAFER", _
        '    "-dQUIET", _
        '    "-sDEVICE=png16m", _
        '    String.Format("-r{0}", resolucao), _
        '    "-dTextAlphaBits=2", _
        '    "-dGraphicsAlphaBits=2", _
        '    String.Format("-dFirstPage={0}", pageNumber), _
        '    String.Format("-dLastPage={0}", pageNumber), _
        '    String.Format("-sOutputFile={0}", outputImgPath), _
        '    "-f", _
        '    pdfPath _
        '    }

        Dim args() As String = { _
            "-dNOPAUSE", _
            "-dBATCH", _
            "-sDEVICE=png16m", _
            String.Format("-dFirstPage={0}", pageNumber), _
            String.Format("-dLastPage={0}", pageNumber), _
            String.Format("-sOutputFile={0}", outputImgPath), _
            Replace(pdfPath, "\", "/") _
            }

        If GhostscriptDllLib.RunGS(args) Then
            If File.Exists(outputImgPath) Then
                objFileStream = New FileStream(outputImgPath, FileMode.Open)
                Dim length As Int32 = objFileStream.Length
                Dim bytes(length) As Byte
                objFileStream.Read(bytes, 0, length)
                objFileStream.Close()

                objMemoryStream = New MemoryStream(bytes, False)
                objImages.Add(Image.FromStream(objMemoryStream))

                File.Delete(outputImgPath)
            Else
                Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
            End If
        Else
            Throw New InvalidOperationException("Erro ao converter páginas do PDF em imagens PNG")
        End If

    Next

    Return CType(objImages.ToArray(GetType(Image)), Image())

End Function