Skip to content
This repository has been archived by the owner on Jul 12, 2024. It is now read-only.

A VB version

东方孤思子 Paris·QianSen edited this page Mar 3, 2017 · 1 revision

I have ported 0.5.7 version to Virtual Basic.

For anyone who may need it, you can take it as a reference.

Imports System.Text
Imports System.IO
Imports System.Threading
Imports System.Configuration

Namespace Codaxy.WkHtmlToPdf
    Public Class PdfConvertException
        Inherits Exception
        Public Sub New(msg As String)
            MyBase.New(msg)
        End Sub
    End Class

    Public Class PdfConvertTimeoutException
        Inherits PdfConvertException
        Public Sub New()
            MyBase.New("HTML to PDF conversion process has not finished in the given period.")
        End Sub
    End Class

    Public Class PdfOutput
        Public Property OutputFilePath() As String
            Get
                Return m_OutputFilePath
            End Get
            Set
                m_OutputFilePath = Value
            End Set
        End Property
        Private m_OutputFilePath As String
        Public Property OutputStream() As Stream
            Get
                Return m_OutputStream
            End Get
            Set
                m_OutputStream = Value
            End Set
        End Property
        Private m_OutputStream As Stream
        Public Property OutputCallback() As Action(Of PdfDocument, Byte())
            Get
                Return m_OutputCallback
            End Get
            Set
                m_OutputCallback = Value
            End Set
        End Property
        Private m_OutputCallback As Action(Of PdfDocument, Byte())
    End Class

    Public Class PdfDocument
        Public Property Url() As String
            Get
                Return m_Url
            End Get
            Set
                m_Url = Value
            End Set
        End Property
        Private m_Url As String
        Public Property Html() As String
            Get
                Return m_Html
            End Get
            Set
                m_Html = Value
            End Set
        End Property
        Private m_Html As String
        Public Property HeaderUrl() As String
            Get
                Return m_HeaderUrl
            End Get
            Set
                m_HeaderUrl = Value
            End Set
        End Property
        Private m_HeaderUrl As String
        Public Property FooterUrl() As String
            Get
                Return m_FooterUrl
            End Get
            Set
                m_FooterUrl = Value
            End Set
        End Property
        Private m_FooterUrl As String
        Public Property HeaderLeft() As String
            Get
                Return m_HeaderLeft
            End Get
            Set
                m_HeaderLeft = Value
            End Set
        End Property
        Private m_HeaderLeft As String
        Public Property HeaderCenter() As String
            Get
                Return m_HeaderCenter
            End Get
            Set
                m_HeaderCenter = Value
            End Set
        End Property
        Private m_HeaderCenter As String
        Public Property HeaderRight() As String
            Get
                Return m_HeaderRight
            End Get
            Set
                m_HeaderRight = Value
            End Set
        End Property
        Private m_HeaderRight As String
        Public Property FooterLeft() As String
            Get
                Return m_FooterLeft
            End Get
            Set
                m_FooterLeft = Value
            End Set
        End Property
        Private m_FooterLeft As String
        Public Property FooterCenter() As String
            Get
                Return m_FooterCenter
            End Get
            Set
                m_FooterCenter = Value
            End Set
        End Property
        Private m_FooterCenter As String
        Public Property FooterRight() As String
            Get
                Return m_FooterRight
            End Get
            Set
                m_FooterRight = Value
            End Set
        End Property
        Private m_FooterRight As String
        Public Property State() As Object
            Get
                Return m_State
            End Get
            Set
                m_State = Value
            End Set
        End Property
        Private m_State As Object
        Public Property Cookies() As Dictionary(Of String, String)
            Get
                Return m_Cookies
            End Get
            Set
                m_Cookies = Value
            End Set
        End Property
        Private m_Cookies As Dictionary(Of String, String)
        Public Property ExtraParams() As Dictionary(Of String, String)
            Get
                Return m_ExtraParams
            End Get
            Set
                m_ExtraParams = Value
            End Set
        End Property
        Private m_ExtraParams As Dictionary(Of String, String)
    End Class

    Public Class PdfConvertEnvironment
        Public Property TempFolderPath() As String
            Get
                Return m_TempFolderPath
            End Get
            Set
                m_TempFolderPath = Value
            End Set
        End Property
        Private m_TempFolderPath As String
        Public Property WkHtmlToPdfPath() As String
            Get
                Return m_WkHtmlToPdfPath
            End Get
            Set
                m_WkHtmlToPdfPath = Value
            End Set
        End Property
        Private m_WkHtmlToPdfPath As String
        Public Property Timeout() As Integer
            Get
                Return m_Timeout
            End Get
            Set
                m_Timeout = Value
            End Set
        End Property
        Private m_Timeout As Integer
        Public Property Debug() As Boolean
            Get
                Return m_Debug
            End Get
            Set
                m_Debug = Value
            End Set
        End Property
        Private m_Debug As Boolean
    End Class

    Public Class PdfConvert
        Shared _e As PdfConvertEnvironment

        Public Shared ReadOnly Property Environment() As PdfConvertEnvironment
            Get
                If _e Is Nothing Then
                    _e = New PdfConvertEnvironment() With {
                        .TempFolderPath = Path.GetTempPath(),
                        .WkHtmlToPdfPath = GetWkhtmlToPdfExeLocation(),
                        .Timeout = 60000
                    }
                End If
                Return _e
            End Get
        End Property

        Private Shared Function GetWkhtmlToPdfExeLocation() As String
            Dim filePath As String, customPath As String = ConfigurationManager.AppSettings("wkhtmltopdf:path")

            If customPath IsNot Nothing Then
                filePath = Path.Combine(customPath, "wkhtmltopdf.exe")

                If File.Exists(filePath) Then
                    Return filePath
                End If
            End If

            Dim programFilesPath As String = System.Environment.GetEnvironmentVariable("ProgramFiles")
            filePath = Path.Combine(programFilesPath, "wkhtmltopdf\wkhtmltopdf.exe")

            If File.Exists(filePath) Then
                Return filePath
            End If

            Dim programFilesx86Path As String = System.Environment.GetEnvironmentVariable("ProgramFiles(x86)")
            filePath = Path.Combine(programFilesx86Path, "wkhtmltopdf\wkhtmltopdf.exe")

            If File.Exists(filePath) Then
                Return filePath
            End If

            filePath = Path.Combine(programFilesPath, "wkhtmltopdf\bin\wkhtmltopdf.exe")
            If File.Exists(filePath) Then
                Return filePath
            End If

            Return Path.Combine(programFilesx86Path, "wkhtmltopdf\bin\wkhtmltopdf.exe")
        End Function

        Public Shared Sub ConvertHtmlToPdf(document As PdfDocument, output As PdfOutput)
            ConvertHtmlToPdf(document, Nothing, output)
        End Sub

        Public Shared Sub ConvertHtmlToPdf(document As PdfDocument, environment As PdfConvertEnvironment, woutput As PdfOutput)
            If environment Is Nothing Then
                environment = PdfConvert.Environment
            End If

            If document.Html IsNot Nothing Then
                document.Url = "-"
            End If

            Dim outputPdfFilePath As String
            Dim delete As Boolean
            If woutput.OutputFilePath IsNot Nothing Then
                outputPdfFilePath = woutput.OutputFilePath
                delete = False
            Else
                outputPdfFilePath = Path.Combine(environment.TempFolderPath, String.Format("{0}.pdf", Guid.NewGuid()))
                delete = True
            End If

            If Not File.Exists(environment.WkHtmlToPdfPath) Then
                Throw New PdfConvertException(String.Format("File '{0}' not found. Check if wkhtmltopdf application is installed.", environment.WkHtmlToPdfPath))
            End If

            Dim paramsBuilder As New StringBuilder()
            paramsBuilder.Append("--page-size A4 ")

            If Not String.IsNullOrEmpty(document.HeaderUrl) Then
                paramsBuilder.AppendFormat("--header-html {0} ", document.HeaderUrl)
                paramsBuilder.Append("--margin-top 25 ")
                paramsBuilder.Append("--header-spacing 5 ")
            End If
            If Not String.IsNullOrEmpty(document.FooterUrl) Then
                paramsBuilder.AppendFormat("--footer-html {0} ", document.FooterUrl)
                paramsBuilder.Append("--margin-bottom 25 ")
                paramsBuilder.Append("--footer-spacing 5 ")
            End If

            If Not String.IsNullOrEmpty(document.HeaderLeft) Then
                paramsBuilder.AppendFormat("--header-left ""{0}"" ", document.HeaderLeft)
            End If

            If Not String.IsNullOrEmpty(document.HeaderCenter) Then
                paramsBuilder.AppendFormat("--header-center ""{0}"" ", document.HeaderCenter)
            End If

            If Not String.IsNullOrEmpty(document.HeaderRight) Then
                paramsBuilder.AppendFormat("--header-right ""{0}"" ", document.HeaderRight)
            End If

            If Not String.IsNullOrEmpty(document.FooterLeft) Then
                paramsBuilder.AppendFormat("--footer-left ""{0}"" ", document.FooterLeft)
            End If

            If Not String.IsNullOrEmpty(document.FooterCenter) Then
                paramsBuilder.AppendFormat("--footer-center ""{0}"" ", document.FooterCenter)
            End If

            If Not String.IsNullOrEmpty(document.FooterRight) Then
                paramsBuilder.AppendFormat("--footer-right ""{0}"" ", document.FooterRight)
            End If

            If document.ExtraParams IsNot Nothing Then
                For Each extraParam In document.ExtraParams
                    paramsBuilder.AppendFormat("--{0} {1} ", extraParam.Key, extraParam.Value)
                Next
            End If

            If document.Cookies IsNot Nothing Then
                For Each cookie In document.Cookies
                    paramsBuilder.AppendFormat("--cookie {0} {1} ", cookie.Key, cookie.Value)
                Next
            End If

            paramsBuilder.AppendFormat("""{0}"" ""{1}""", document.Url, outputPdfFilePath)

            Try
                Dim output As New StringBuilder()
                Dim [error] As New StringBuilder()

                Using process As New Process()
                    process.StartInfo.FileName = environment.WkHtmlToPdfPath
                    process.StartInfo.Arguments = paramsBuilder.ToString()
                    process.StartInfo.UseShellExecute = False
                    process.StartInfo.RedirectStandardOutput = True
                    process.StartInfo.RedirectStandardError = True
                    process.StartInfo.RedirectStandardInput = True

                    Using outputWaitHandle As New AutoResetEvent(False)
                        Using errorWaitHandle As New AutoResetEvent(False)
                            Dim outputHandler As DataReceivedEventHandler = Function(sender, e)
                                                                                If e.Data Is Nothing Then
                                                                                    outputWaitHandle.[Set]()
                                                                                Else
                                                                                    output.AppendLine(e.Data)
                                                                                End If

                                                                            End Function

                            Dim errorHandler As DataReceivedEventHandler = Function(sender, e)
                                                                               If e.Data Is Nothing Then
                                                                                   errorWaitHandle.[Set]()
                                                                               Else
                                                                                   [error].AppendLine(e.Data)
                                                                               End If

                                                                           End Function

                            AddHandler process.OutputDataReceived, outputHandler
                            AddHandler process.ErrorDataReceived, errorHandler

                            Try
                                process.Start()

                                process.BeginOutputReadLine()
                                process.BeginErrorReadLine()

                                If document.Html IsNot Nothing Then
                                    Using stream = process.StandardInput
                                        Dim buffer As Byte() = Encoding.UTF8.GetBytes(document.Html)
                                        stream.BaseStream.Write(buffer, 0, buffer.Length)
                                        stream.WriteLine()
                                    End Using
                                End If

                                If process.WaitForExit(environment.Timeout) AndAlso outputWaitHandle.WaitOne(environment.Timeout) AndAlso errorWaitHandle.WaitOne(environment.Timeout) Then
                                    If process.ExitCode <> 0 AndAlso Not File.Exists(outputPdfFilePath) Then
                                        Throw New PdfConvertException(String.Format("Html to PDF conversion of '{0}' failed. Wkhtmltopdf output: " & vbCr & vbLf & "{1}", document.Url, [error]))
                                    End If
                                Else
                                    If Not process.HasExited Then
                                        process.Kill()
                                    End If

                                    Throw New PdfConvertTimeoutException()
                                End If
                            Finally
                                RemoveHandler process.OutputDataReceived, outputHandler
                                RemoveHandler process.ErrorDataReceived, errorHandler
                            End Try
                        End Using
                    End Using
                End Using


                If woutput.OutputStream IsNot Nothing Then
                    Using fs As Stream = New FileStream(outputPdfFilePath, FileMode.Open)
                        Dim buffer As Byte() = New Byte(32 * 1024 - 1) {}
                        Dim read As Integer

                        While (InlineAssignHelper(read, fs.Read(buffer, 0, buffer.Length))) > 0
                            woutput.OutputStream.Write(buffer, 0, read)
                        End While
                    End Using
                End If

                If woutput.OutputCallback IsNot Nothing Then
                    Dim pdfFileBytes As Byte() = File.ReadAllBytes(outputPdfFilePath)
                    woutput.OutputCallback()(document, pdfFileBytes)

                End If
            Finally
                If delete AndAlso File.Exists(outputPdfFilePath) Then
                    File.Delete(outputPdfFilePath)
                End If
            End Try
        End Sub

        Friend Shared Sub ConvertHtmlToPdf(url As String, outputFilePath As String)
            ConvertHtmlToPdf(New PdfDocument() With {
                .Url = url
            }, New PdfOutput() With {
                .OutputFilePath = outputFilePath
            })
        End Sub
        Private Shared Function InlineAssignHelper(Of T)(ByRef target As T, value As T) As T
            target = value
            Return value
        End Function
    End Class
End Namespace
Clone this wiki locally