As a part of a project I'm working on, a new requirement has arisen for me to be able to generate multiple PDF files and then merge them together before they are delivered to our client(s). For this, I've started working on a reusable solution that implements the iTextSharp library using code I've taken from the Java example listed on page 187 of the sample chapter from "iText in Action". I've attempted to make it able to handle a number of possible scenarios through overloaded methods, and everything seems to be working correctly, as far as I can tell.
What I'm most concerned about at this point is doing my best to put in appropriate error handling. Since this is my first time working with this library, I'm not sure yet about any of the "gotcha" exceptions that I might be overlooking.
''' <summary>
''' Class for manipulating PDF files
''' </summary>
Public Class PDFManipulator
#Region "PUBLIC PROPERTIES"
Public Property Warnings As List(Of String)
Public Property Errors As List(Of String)
#End Region
''' <summary>
''' The file property to use for sorting the files before merging
''' </summary>
Public Enum PDFMergeSortOrder
Original
FileDate
FileName
FileNameWithDirectory
End Enum
#Region "PUBLIC METHODS"
#Region "OVERLOAD METHODS"
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFilePath, OutputFileName, OverwriteExistingPDF, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
Dim PDFFolder As New System.IO.DirectoryInfo(PDFFilePath)
For Each PDF As System.IO.FileInfo In PDFFolder.GetFiles("*.pdf")
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
If Warnings Is Nothing Then
Warnings = New List(Of String)
End If
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
If RecurseSubFolders Then
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFFolder))
End If
Return Merge(PDFFiles, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, OutputFileName, OverwriteExistingPDF, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDF As System.IO.FileInfo In PDFFileDirectory.GetFiles("*.pdf").OrderBy(Function(f As System.IO.FileInfo) f.LastWriteTime)
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
If Warnings Is Nothing Then
Warnings = New List(Of String)
End If
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
If RecurseSubFolders Then
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFFileDirectory))
End If
Return Merge(PDFFiles, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFileNames, OutputFileName, False, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFileNames, OutputFileName, False, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDFName As String In PDFFileNames
If System.IO.File.Exists(PDFName) Then
Dim PDF As New System.IO.FileInfo(PDFName)
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
If Warnings Is Nothing Then
Warnings = New List(Of String)
End If
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
End If
Next PDFName
Return Merge(PDFFiles, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFiles, OutputFileName, False, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFiles, OutputFileName, False, SortOrder)
End Function
#End Region
#Region "MASTER MERGE METHOD"
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Dim ResultFile As System.IO.FileInfo = Nothing
Dim ContinueMerge As Boolean = True
If OverwriteExistingPDF Then
If System.IO.File.Exists(OutputFileName) Then
Try
System.IO.File.Delete(OutputFileName)
Catch ex As Exception
ContinueMerge = False
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("Could not delete existing output file.")
Throw
End Try
End If
End If
If ContinueMerge Then
Dim OutputPDF As iTextSharp.text.Document = Nothing
Dim Copier As iTextSharp.text.pdf.PdfCopy = Nothing
Dim PDFStream As System.IO.FileStream = Nothing
Dim SortedList As New List(Of System.IO.FileInfo)
Try
Select Case SortOrder
Case PDFMergeSortOrder.Original
SortedList = PDFFiles
Case PDFMergeSortOrder.FileDate
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.LastWriteTime).ToList
Case PDFMergeSortOrder.FileName
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.Name).ToList
Case PDFMergeSortOrder.FileNameWithDirectory
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.FullName).ToList
End Select
If Not IO.Directory.Exists(New IO.FileInfo(OutputFileName).DirectoryName) Then
Try
IO.Directory.CreateDirectory(New IO.FileInfo(OutputFileName).DirectoryName)
Catch ex As Exception
ContinueMerge = False
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("Could not create output directory.")
Throw
End Try
End If
If ContinueMerge Then
OutputPDF = New iTextSharp.text.Document
PDFStream = New System.IO.FileStream(OutputFileName, System.IO.FileMode.OpenOrCreate)
Copier = New iTextSharp.text.pdf.PdfCopy(OutputPDF, PDFStream)
OutputPDF.Open()
For Each PDF As System.IO.FileInfo In SortedList
If ContinueMerge Then
Dim InputReader As iTextSharp.text.pdf.PdfReader = Nothing
Try
InputReader = New iTextSharp.text.pdf.PdfReader(PDF.FullName)
For page As Integer = 1 To InputReader.NumberOfPages
Copier.AddPage(Copier.GetImportedPage(InputReader, page))
Next page
If InputReader.IsRebuilt Then
If Warnings Is Nothing Then
Warnings = New List(Of String)
End If
Warnings.Add("Damaged PDF: " & PDF.FullName & " repaired and successfully merged into output file.")
End If
Catch InvalidEx As iTextSharp.text.exceptions.InvalidPdfException
'Skip this file
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("Invalid PDF: " & PDF.FullName & " not merged into output file.")
Catch FormatEx As iTextSharp.text.pdf.BadPdfFormatException
'Skip this file
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("Bad PDF Format: " & PDF.FullName & " not merged into output file.")
Catch PassworddEx As iTextSharp.text.exceptions.BadPasswordException
'Skip this file
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("Password-protected PDF: " & PDF.FullName & " not merged into output file.")
Catch OtherEx As Exception
ContinueMerge = False
Finally
If Not InputReader Is Nothing Then
InputReader.Close()
InputReader.Dispose()
End If
End Try
End If
Next PDF
End If
Catch ex As iTextSharp.text.pdf.PdfException
ResultFile = Nothing
ContinueMerge = False
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("iTextSharp Error: " & ex.Message)
If System.IO.File.Exists(OutputFileName) Then
If Not OutputPDF Is Nothing Then
OutputPDF.Close()
OutputPDF.Dispose()
End If
If Not PDFStream Is Nothing Then
PDFStream.Close()
PDFStream.Dispose()
End If
If Not Copier Is Nothing Then
Copier.Close()
Copier.Dispose()
End If
System.IO.File.Delete(OutputFileName)
End If
Throw
Catch other As Exception
ResultFile = Nothing
ContinueMerge = False
If Errors Is Nothing Then
Errors = New List(Of String)
End If
Errors.Add("General Error: " & other.Message)
If System.IO.File.Exists(OutputFileName) Then
If Not OutputPDF Is Nothing Then
OutputPDF.Close()
OutputPDF.Dispose()
End If
If Not PDFStream Is Nothing Then
PDFStream.Close()
PDFStream.Dispose()
End If
If Not Copier Is Nothing Then
Copier.Close()
Copier.Dispose()
End If
System.IO.File.Delete(OutputFileName)
End If
Throw
Finally
If Not OutputPDF Is Nothing Then
OutputPDF.Close()
OutputPDF.Dispose()
End If
If Not PDFStream Is Nothing Then
PDFStream.Close()
PDFStream.Dispose()
End If
If Not Copier Is Nothing Then
Copier.Close()
Copier.Dispose()
End If
If System.IO.File.Exists(OutputFileName) Then
If ContinueMerge Then
ResultFile = New System.IO.FileInfo(OutputFileName)
If ResultFile.Length <= 0 Then
ResultFile = Nothing
Try
System.IO.File.Delete(OutputFileName)
Catch ex As Exception
Throw
End Try
End If
Else
ResultFile = Nothing
Try
System.IO.File.Delete(OutputFileName)
Catch ex As Exception
Throw
End Try
End If
Else
ResultFile = Nothing
End If
End Try
End If
Return ResultFile
End Function
#End Region
#End Region
#Region "PRIVATE METHODS"
''' <summary>
''' Recursive method to find all PDF files in subfolders of a given directory and
''' add them to the original list for merging
''' </summary>
''' <param name="RootFolder">The DirectoryInfo object in which to look for sub-directories containing additional PDF files to merge</param>
''' <returns>A list of all the PDF files found in all subfolders of the root</returns>
Private Function GetFilesFromSubFoldersForMerge(ByVal RootFolder As System.IO.DirectoryInfo) As List(Of System.IO.FileInfo)
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDFSubFolder As System.IO.DirectoryInfo In RootFolder.GetDirectories
For Each PDF As System.IO.FileInfo In PDFSubFolder.GetFiles("*.pdf")
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
If Warnings Is Nothing Then
Warnings = New List(Of String)
End If
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFSubFolder))
Next PDFSubFolder
Return PDFFiles
End Function
#End Region
End Class
I'm hoping to add some methods for splitting PDF's, adding watermarks, etc. at some point in the future, but for now, I'm just trying to get the current functionality shored up the best I can. Of course, any comments or suggestions about anything in the code are absolutely welcome, regardless of whether or not it has specifically to do with error handling.
EDIT: I've added a couple of extra Catch
conditions to the "master" Merge
method (in the inner Try
) that I believe may be useful, although I haven't been able to specifically test for those conditions yet. I added the following:
iTextSharp.text.pdf.BadPdfFormatException
iTextSharp.text.exceptions.BadPasswordException
I also added some Dispose
calls in some of the other exception handling in the outer Try...Catch
block before attempting to delete the output PDF file to make sure it isn't in use.
Additionally, I added a small block of code to add a Warning
if the original PDF is repaired before being added to the output file.
2 Answers 2
Only focusing on the "monster" method Merge()
.
The usage of ContinueMerge
seems senseless because this is set only to False
in a Catch
block where later the exception is thrown up the call stack. The only exception from this pattern is for catching the OtherEx
which by the way is named poorly. For the case that ContinueMerge
is False
the loop where you caught the exception just isn't doing anything anymore hence you could Exit For
or just return from the method.
But the biggest improvement would be if you could get rid of the repeated code targeting your List<T>
's
If Errors Is Nothing Then
Errors = New List(Of String)
End If
By newing them in the constructor you could omit a lot of code. You have this pattern 11 times in your code which makes 33 lines of code.
What sense does it have to first apply a SortOrder
and afterwards check if you can create the output directory? A lot of computing time may be lost if you can't create the directory.
Catching an exception which you just Throw
doesn't add anything useful. E.g here
Try
System.IO.File.Delete(OutputFileName)
Catch ex As Exception
Throw
End Try
you could just remove the Try..Catch
which would have the same result.
By using a Using
statement for the objects
Dim OutputPDF As iTextSharp.text.Document = Nothing
Dim Copier As iTextSharp.text.pdf.PdfCopy = Nothing
Dim PDFStream As System.IO.FileStream = Nothing
you could save a lot of code as well. Right now you Close()
and Dispose()
these objects at 3 places which wouldn't be necessary at all by using a Using
statement. A Using
statement basically is just a Try..Finally
where the disposable object will be disposed in the Finally
part. In addition, a call to Dispose()
will, in good coded objects, always close any ressources hence a call to Close()
won't be needed.
-
\$\begingroup\$ Excellent suggestions. Thank you so much for your help. As I said in my other question, I'm entirely self-taught, so, even though I've been programming for several years, I've probably gotten into some habits and patterns (e.g., not using the
Using
statement, etc.). I'll look into revising the method(s) with your suggestions. \$\endgroup\$G_Hosa_Phat– G_Hosa_Phat2018年02月05日 07:50:34 +00:00Commented Feb 5, 2018 at 7:50
I've modified the "master" method to incorporate the suggestions provided by @Heslacher. I had been concerned about the fact that the overloaded methods didn't have their own Try...Catch
blocks around the calls to the "master" method, but after testing with and without them, I now understand that, as long as the original calling method has it, any exceptions will "bubble-up " through the overloads as expected/intended.
Additionally, by testing the exception handling, I found a couple of places in my original code where I was incorrectly passing a "default" value into the "master" method instead of using the value provided by the overload. I've corrected these occurrences, and everything should be "cleaned up". In the spirit of sharing, here is the updated code:
''' <summary>
''' Class for manipulating PDF files
''' </summary>
Public Class PDFManipulator
#Region "PUBLIC PROPERTIES"
Public Property Warnings As List(Of String)
Public Property Errors As List(Of String)
#End Region
#Region "PDF MERGE METHODS"
''' <summary>
''' The file property to use for sorting the files before merging
''' </summary>
Public Enum PDFMergeSortOrder
Original
FileDate
FileName
FileNameWithDirectory
End Enum
#Region "PUBLIC METHODS"
#Region "CONSTRUCTOR"
Public Sub New()
Errors = New List(Of String)
Warnings = New List(Of String)
End Sub
#End Region
#Region "OVERLOAD METHODS"
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFilePath, UseSmartMerge, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFilePath, UseSmartMerge, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, UseSmartMerge, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <c>Nothing</c> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, UseSmartMerge, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFilePath, UseSmartMerge, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFilePath, False, OutputFileName, OverwriteExistingPDF, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFilePath">The path in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified path for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFilePath As String, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
Dim PDFFolder As New System.IO.DirectoryInfo(PDFFilePath)
For Each PDF As System.IO.FileInfo In PDFFolder.GetFiles("*.pdf")
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
If RecurseSubFolders Then
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFFolder))
End If
Return Merge(PDFFiles, UseSmartMerge, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, False, PDFMergeSortOrder.Original, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, False, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, False, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, False, SortOrder, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original, RecurseSubFolders)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, False, OutputFileName, OverwriteExistingPDF, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return MergeAll(PDFFileDirectory, UseSmartMerge, OutputFileName, OverwriteExistingPDF, SortOrder, False)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileDirectory">The Directory in which to search for PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <param name="RecurseSubFolders">Identifies whether or not to look in subfolders of the specified Directory for additional PDF files</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function MergeAll(ByVal PDFFileDirectory As System.IO.DirectoryInfo, ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder, ByVal RecurseSubFolders As Boolean) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDF As System.IO.FileInfo In PDFFileDirectory.GetFiles("*.pdf").OrderBy(Function(f As System.IO.FileInfo) f.LastWriteTime)
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
If RecurseSubFolders Then
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFFileDirectory))
End If
Return Merge(PDFFiles, UseSmartMerge, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFileNames, False, OutputFileName, False, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFileNames, UseSmartMerge, OutputFileName, False, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFileNames, False, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFileNames, UseSmartMerge, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFileNames">A list of specific PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFileNames As List(Of String), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDFName As String In PDFFileNames
If System.IO.File.Exists(PDFName) Then
Dim PDF As New System.IO.FileInfo(PDFName)
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
End If
Next PDFName
Return Merge(PDFFiles, UseSmartMerge, OutputFileName, OverwriteExistingPDF, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFiles, False, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean) As System.IO.FileInfo
Return Merge(PDFFiles, UseSmartMerge, OutputFileName, OverwriteExistingPDF, PDFMergeSortOrder.Original)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFiles, False, OutputFileName, False, SortOrder)
End Function
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="UseSmartMerge">Identifies whether to use a regular <see cref="iTextSharp.text.pdf.PdfCopy"/> or the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> for merging</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Return Merge(PDFFiles, UseSmartMerge, OutputFileName, False, SortOrder)
End Function
#End Region
#Region "MASTER MERGE METHOD"
''' <summary>
''' Merges multiple PDF files into a single PDF file
''' </summary>
''' <param name="PDFFiles">A list of specific PDF files to merge</param>
''' <param name="OutputFileName">The PDF file to create from the merged PDF files</param>
''' <param name="OverwriteExistingPDF">If the specified PDF file already exists, identifies whether or not to overwrite the existing file</param>
''' <param name="SortOrder">Identifies the order in which to add the source PDF files to the output file</param>
''' <returns>A FileInfo object representing the merged PDF if successful. <cref>Nothing</cref> if unsuccessful.</returns>
''' <remarks>Using the <see cref="iTextSharp.text.pdf.PdfCopy"/> (<paramref name="UseSmartMerge"/> = <c>False</c>) may result in larger files,
''' while using the <see cref="iTextSharp.text.pdf.PdfSmartCopy"/> (<paramref name="UseSmartMerge"/> = <c>True</c>) may result in longer processing times.</remarks>
Public Overloads Function Merge(ByVal PDFFiles As List(Of System.IO.FileInfo), ByVal UseSmartMerge As Boolean, ByVal OutputFileName As String, ByVal OverwriteExistingPDF As Boolean, ByVal SortOrder As PDFMergeSortOrder) As System.IO.FileInfo
Dim ResultFile As System.IO.FileInfo = Nothing
Dim SortedList As New List(Of System.IO.FileInfo)
Dim PDFCopier As iTextSharp.text.pdf.PdfCopy = Nothing
Dim SmartPDFCopier As iTextSharp.text.pdf.PdfSmartCopy = Nothing
If OverwriteExistingPDF Then
If System.IO.File.Exists(OutputFileName) Then
Try
System.IO.File.Delete(OutputFileName)
Catch ex As Exception
Errors.Add("Could not delete existing output file.")
Throw
End Try
End If
ElseIf System.IO.File.Exists(OutputFileName) Then
Errors.Add("Output file already exists.")
Return Nothing
End If
If Not IO.Directory.Exists(New IO.FileInfo(OutputFileName).DirectoryName) Then
Try
IO.Directory.CreateDirectory(New IO.FileInfo(OutputFileName).DirectoryName)
Catch ex As Exception
Errors.Add("Could not create output directory.")
Throw
End Try
End If
Select Case SortOrder
Case PDFMergeSortOrder.Original
SortedList = PDFFiles
Case PDFMergeSortOrder.FileDate
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.LastWriteTime).ToList
Case PDFMergeSortOrder.FileName
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.Name).ToList
Case PDFMergeSortOrder.FileNameWithDirectory
SortedList = PDFFiles.OrderBy(Function(f As System.IO.FileInfo) f.FullName).ToList
End Select
Try
Using OutputPDF As New iTextSharp.text.Document
Using PDFStream As New System.IO.FileStream(OutputFileName, System.IO.FileMode.OpenOrCreate)
If UseSmartMerge Then
SmartPDFCopier = New iTextSharp.text.pdf.PdfSmartCopy(OutputPDF, PDFStream)
Else
PDFCopier = New iTextSharp.text.pdf.PdfCopy(OutputPDF, PDFStream)
End If
OutputPDF.Open()
For Each PDF As System.IO.FileInfo In SortedList
Try
Using InputReader As New iTextSharp.text.pdf.PdfReader(PDF.FullName)
For Page As Integer = 1 To InputReader.NumberOfPages
If UseSmartMerge Then
SmartPDFCopier.AddPage(SmartPDFCopier.GetImportedPage(InputReader, Page))
Else
PDFCopier.AddPage(PDFCopier.GetImportedPage(InputReader, Page))
End If
Next Page
If InputReader.IsRebuilt Then
Warnings.Add("Damaged PDF: " & PDF.FullName & " repaired and successfully merged into output file.")
End If
End Using
Catch InvalidEx As iTextSharp.text.exceptions.InvalidPdfException
'Skip this file
Errors.Add("Invalid PDF: " & PDF.FullName & " not merged into output file.")
Catch FormatEx As iTextSharp.text.pdf.BadPdfFormatException
'Skip this file
Errors.Add("Bad PDF Format: " & PDF.FullName & " not merged into output file.")
Catch PassworddEx As iTextSharp.text.exceptions.BadPasswordException
'Skip this file
Errors.Add("Password-protected PDF: " & PDF.FullName & " not merged into output file.")
Catch OtherEx As Exception
ResultFile = Nothing
Errors.Add("Other Error: " & OtherEx.Message & vbCrLf & vbCrLf & PDF.FullName & " not merged into output file.")
If System.IO.File.Exists(OutputFileName) Then
System.IO.File.Delete(OutputFileName)
End If
Exit For
End Try
Next PDF
End Using
End Using
Catch ex As iTextSharp.text.pdf.PdfException
ResultFile = Nothing
Errors.Add("iTextSharp Error: " & ex.Message)
If Not PDFCopier Is Nothing Then
PDFCopier.Dispose()
End If
If Not SmartPDFCopier Is Nothing Then
SmartPDFCopier.Dispose()
End If
If System.IO.File.Exists(OutputFileName) Then
System.IO.File.Delete(OutputFileName)
End If
Throw
Catch other As Exception
ResultFile = Nothing
Errors.Add("Other Error: " & other.Message)
If Not PDFCopier Is Nothing Then
PDFCopier.Dispose()
End If
If Not SmartPDFCopier Is Nothing Then
SmartPDFCopier.Dispose()
End If
If System.IO.File.Exists(OutputFileName) Then
System.IO.File.Delete(OutputFileName)
End If
Throw
Finally
If Not PDFCopier Is Nothing Then
PDFCopier.Dispose()
End If
If Not SmartPDFCopier Is Nothing Then
SmartPDFCopier.Dispose()
End If
If System.IO.File.Exists(OutputFileName) Then
ResultFile = New System.IO.FileInfo(OutputFileName)
If ResultFile.Length <= 0 Then
ResultFile = Nothing
System.IO.File.Delete(OutputFileName)
End If
Else
ResultFile = Nothing
End If
End Try
Return ResultFile
End Function
#End Region
#End Region
#Region "PRIVATE METHODS"
''' <summary>
''' Recursive method to find all PDF files in subfolders of a given directory and
''' add them to the original list for merging
''' </summary>
''' <param name="RootFolder">The DirectoryInfo object in which to look for sub-directories containing additional PDF files to merge</param>
''' <returns>A list of all the PDF files found in all subfolders of the root</returns>
Private Function GetFilesFromSubFoldersForMerge(ByVal RootFolder As System.IO.DirectoryInfo) As List(Of System.IO.FileInfo)
Dim PDFFiles As New List(Of System.IO.FileInfo)
For Each PDFSubFolder As System.IO.DirectoryInfo In RootFolder.GetDirectories
For Each PDF As System.IO.FileInfo In PDFSubFolder.GetFiles("*.pdf")
If PDF.Length > 0 Then
PDFFiles.Add(PDF)
Else
Warnings.Add("Empty file : " & PDF.FullName & " not merged into output file.")
End If
Next PDF
PDFFiles.AddRange(GetFilesFromSubFoldersForMerge(PDFSubFolder))
Next PDFSubFolder
Return PDFFiles
End Function
#End Region
#End Region
End Class
EDIT: I found one other little "gotcha" in the "master" method. If the OverwriteExistingPDF
parameter is set to False
and the file specified by the OutputFileName
already exists, I needed to exit the method. I'm not sure if it would be better to generate a new exception object and try to throw that back to the calling method, but, for now I've simply set it to return Nothing
. Updated the code in this CW answer to reflect the change.
-
\$\begingroup\$ Thank you for converting it to a CW post. I wasn't sure if I should or not, so I appreciate the moderator intervention. :) \$\endgroup\$G_Hosa_Phat– G_Hosa_Phat2018年02月07日 20:52:55 +00:00Commented Feb 7, 2018 at 20:52
iText
with a tag synonym ofiTextSharp
\$\endgroup\$