Wednesday, January 11, 2006

1988.aspx

How to merge multiple PDF files in ASP.NET with pdftk

There are many PDF Toolkits on the market that can merge PDF files. Most of them are expensive systems like ActivePDF but in the end I found several free alternatives that allows me to merge PDF files on the fly in ASP.NET.


The first tool I found was PDF Merge. It is a Bash command line script that uses GhostScript. I never looked into the solution in detail as I found the great pdftk toolkit.


Pdftk is a standalone executable file that you call with different command line arguments. No installation or registration, just copy the file somewhere and call it.


A DLL would have been simpler, but calling pdftk from ASP.NET only takes a few lines of code. It is a command line tool so System.Diagnostics.Process can be used to launch it with the arguments we need to merge PDFs.  The list of files and the various paths are hard coded to keep the source code short and easy to read. The list of files to merge should be passed in the request and the paths should be stored in Web.Config. One last note: the runAndWait() function below waits forever for the toolkit to return. Use a configurable timeout if you plan to use it in production code


Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    'Hard coded list of files to convert
    Dim aFiles As String() = {"c:\temp\1.pdf", "c:\temp\2.pdf", "c:\temp\3.pdf"}
    'Use a temporary output file
    Dim outputFileName = System.IO.Path.GetTempFileName()
    'Construct the command line: pdftk 1.pdf 2.pdf 3.pdf cat output 123.pdf
    Dim fileName As String
    Dim buildCommand As System.Text.StringBuilder = New System.Text.StringBuilder
    For Each fileName In aFiles
        buildCommand.AppendFormat(" ""{0}"" ", fileName)
    Next
    buildCommand.AppendFormat(" cat output ""{0}"" dont_ask", outputFileName)
    'Run PDFTK and wait for it to complete, then send the output to the user
    If runAndWait("c:\tools\pdftk.exe", buildCommand.ToString()) Then
        Response.ContentType = "application/pdf"
        Response.BinaryWrite(getFileData(outputFileName))
    Else
        'TO DO: show error message
    End If
    System.IO.File.Delete(outputFileName)
    Response.End()
End Sub
Private Function runAndWait(ByVal command As String, ByVal commandLine As String) As Boolean
    Dim runProcess As System.Diagnostics.Process
    Try
        runProcess = New System.Diagnostics.Process
        With runProcess.StartInfo
            .FileName = command
            .Arguments = commandLine
            .WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal
        End With
        runProcess.Start()
        'Wait until the process passes back an exit code 
        runProcess.WaitForExit()
 
        'Free resources associated with this process
        runProcess.Close()
        runAndWait = True
    Catch ex As Exception           
        runAndWait = False
    End Try
End Function 
Private Function getFileData(ByVal fileName As String) As Byte()
    Dim stream As System.IO.FileStream = System.IO.File.OpenRead(fileName)
 
    Dim data As Byte()
    ReDim data(stream.Length)
    stream.Read(data, 0, stream.Length)
    stream.Close()
    getFileData = data
End Function

No comments:

Post a Comment