65.9K
CodeProject is changing. Read more.
Home

PDF Merge

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.87/5 (37 votes)

Mar 29, 2010

CPOL
viewsIcon

132200

downloadIcon

9607

This Windows application lets you merge image and PDF files in a given folder into one PDF file.

Introduction

This complete Windows application lets you merge image and PDF files in a given folder into one PDF file. It also lets you password protect the PDF file. It uses free iTextSharp library.

Using the code

To use this program, simply select a folder and click Process. The program will create a PDF file within each folder and subfolder. The file will have the same name as the folder plus the PDF extension.

Here is the code:



    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        cbFileType.SelectedIndex = 0
    End Sub

    Private Sub btnFrom_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFrom.Click
		fldFrom.SelectedPath = txtFrom.Text
		fldFrom.ShowDialog()
        txtFrom.Text = fldFrom.SelectedPath
    End Sub

    Private Sub btnProcess_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProcess.Click

		btnProcess.Enabled = False

        Dim sFromPath As String = txtFrom.Text
		If Not Directory.Exists(sFromPath) Then
			btnProcess.Enabled = True
			MsgBox("Folder does not exist")
			Exit Sub
		End If

        txtOutput.Text = ""
        txtOutput.Text += "Starting..." & vbCrLf
        ProccessFolder(sFromPath)
		txtOutput.Text += "Done!"

		btnProcess.Enabled = True

    End Sub

	Private Function PadExt(ByVal s As String) As String
		s = UCase(s)
		If s.Length > 3 Then
			s = s.Substring(1, 3)
		End If
		Return s
	End Function

    Function GetPageCount(ByVal sFolderPath As String) As Integer
        Dim iRet As Integer = 0
        Dim oFiles As String() = Directory.GetFiles(sFolderPath)

        For i As Integer = 0 To oFiles.Length - 1
            Dim sFromFilePath As String = oFiles(i)
            Dim oFileInfo As New FileInfo(sFromFilePath)
            Dim sFileType As String = cbFileType.SelectedItem
			Dim sExt As String = PadExt(oFileInfo.Extension)

            Select Case sFileType
                Case "All"
                    If sExt = "PDF" Then
                        iRet += 1
                    ElseIf sExt = "JPG" Or sExt = "TIF" Then
                        iRet += 1
                    End If

                Case "PDF"
                    If sExt = "PDF" Then
                        iRet += 1
                    End If

                Case "JPG", "TIF"
                    If sExt = "JPG" Or sExt = "TIF" Then
                        iRet += 1
                    End If
            End Select
        Next

        Return iRet
    End Function

    Sub ProccessFolder(ByVal sFolderPath As String)

        Dim bOutputfileAlreadyExists As Boolean = False
        Dim oFolderInfo As New System.IO.DirectoryInfo(sFolderPath)
		Dim sOutFilePath As String = sFolderPath & "\" & oFolderInfo.Name & ".pdf"

		If chkCreateInParentFolder.Checked Then
			sOutFilePath = oFolderInfo.Parent.FullName & "\" & oFolderInfo.Name & ".pdf"
		End If

		If IO.File.Exists(sOutFilePath) Then
			Try
				IO.File.Delete(sOutFilePath)
			Catch ex As Exception
				txtOutput.Text += "Output file already exists: " & sOutFilePath & _
								 " and could not be deleted." & vbTab & vbCrLf
				bOutputfileAlreadyExists = True
			End Try
		End If

        Dim iPageCount As Integer = GetPageCount(sFolderPath)
        If iPageCount > 0 And bOutputfileAlreadyExists = False Then
            txtOutput.Text += "Processing folder: " & sFolderPath & " - " & iPageCount & " files." & vbCrLf

            Dim oFiles As String() = Directory.GetFiles(sFolderPath)
            ProgressBar1.Maximum = oFiles.Length

            Dim oPdfDoc As New iTextSharp.text.Document()
            Dim oPdfWriter As PdfWriter = PdfWriter.GetInstance(oPdfDoc, New FileStream(sOutFilePath, FileMode.Create))
            If txtPassword.Text <> "" Then
                oPdfWriter.SetEncryption(PdfWriter.STRENGTH40BITS, txtPassword.Text, txtPassword.Text, PdfWriter.AllowCopy)
            End If
            oPdfDoc.Open()

			System.Array.Sort(Of String)(oFiles)

            For i As Integer = 0 To oFiles.Length - 1
                Dim sFromFilePath As String = oFiles(i)
                Dim oFileInfo As New FileInfo(sFromFilePath)
                Dim sFileType As String = cbFileType.SelectedItem
				Dim sExt As String = PadExt(oFileInfo.Extension)

				Try
					Select Case sFileType
						Case "All"
							If sExt = "PDF" Then
								AddPdf(sFromFilePath, oPdfDoc, oPdfWriter)
							ElseIf sExt = "JPG" Or sExt = "TIF" Then
								AddImage(sFromFilePath, oPdfDoc, oPdfWriter, sExt)
							End If

						Case "PDF"
							If sExt = "PDF" Then
								AddPdf(sFromFilePath, oPdfDoc, oPdfWriter)
							End If

						Case "JPG", "TIF"
							If sExt = "JPG" Or sExt = "TIF" Then
								AddImage(sFromFilePath, oPdfDoc, oPdfWriter, sExt)
							End If

					End Select

				Catch ex As Exception
					txtOutput.Text += sFromFilePath & vbTab & ex.Message & vbCrLf
				End Try

				If chkDeleteSourceFiles.Checked And IO.File.Exists(sFromFilePath) Then
					Try
						IO.File.Delete(sFromFilePath)
					Catch ex As Exception
						txtOutput.Text += "Could not delete " & sFromFilePath & _
						 ", " & ex.Message & vbCrLf
					End Try
				End If

                ProgressBar1.Value = i
            Next

            Try
                oPdfDoc.Close()
                oPdfWriter.Close()
            Catch ex As Exception
                txtOutput.Text += ex.Message & vbCrLf
                Try
                    IO.File.Delete(sOutFilePath)
                Catch ex2 As Exception
                End Try
            End Try

            ProgressBar1.Value = 0
        End If

		Dim oFolders As String() = Directory.GetDirectories(sFolderPath)
        For i As Integer = 0 To oFolders.Length - 1
            Dim sChildFolder As String = oFolders(i)
            Dim iPos As Integer = sChildFolder.LastIndexOf("\")
            Dim sFolderName As String = sChildFolder.Substring(iPos + 1)
            ProccessFolder(sChildFolder)
        Next

	End Sub

	Sub AddBookmark(ByRef oPdfDoc As iTextSharp.text.Document, ByVal sFromFilePath As String)
		If chkBookmarks.Checked = False Then
			Exit Sub
		End If

		Dim oChapter As New iTextSharp.text.Chapter("", 0)
		oChapter.NumberDepth = 0
		Dim oFileInfo As New FileInfo(sFromFilePath)
		oChapter.BookmarkTitle = oFileInfo.Name
		oPdfDoc.Add(oChapter)
	End Sub

	Sub AddPdf(ByVal sInFilePath As String, ByRef oPdfDoc As iTextSharp.text.Document, ByRef oPdfWriter As PdfWriter)

		AddBookmark(oPdfDoc, sInFilePath)

		Dim oDirectContent As iTextSharp.text.pdf.PdfContentByte = oPdfWriter.DirectContent
		Dim oPdfReader As iTextSharp.text.pdf.PdfReader = New iTextSharp.text.pdf.PdfReader(sInFilePath)
		Dim iNumberOfPages As Integer = oPdfReader.NumberOfPages
		Dim iPage As Integer = 0

		Do While (iPage < iNumberOfPages)
			iPage += 1

			Dim iRotation As Integer = oPdfReader.GetPageRotation(iPage)
			Dim oPdfImportedPage As iTextSharp.text.pdf.PdfImportedPage = oPdfWriter.GetImportedPage(oPdfReader, iPage)

			If chkResize.Checked Then
				If (oPdfImportedPage.Width <= oPdfImportedPage.Height) Then
					oPdfDoc.SetPageSize(iTextSharp.text.PageSize.LETTER)
				Else
					oPdfDoc.SetPageSize(iTextSharp.text.PageSize.LETTER.Rotate())
				End If

				oPdfDoc.NewPage()

				Dim iWidthFactor As Single = oPdfDoc.PageSize.Width / oPdfReader.GetPageSize(iPage).Width
				Dim iHeightFactor As Single = oPdfDoc.PageSize.Height / oPdfReader.GetPageSize(iPage).Height
				Dim iFactor As Single = Math.Min(iWidthFactor, iHeightFactor)

				Dim iOffsetX As Single = (oPdfDoc.PageSize.Width - (oPdfImportedPage.Width * iFactor)) / 2
				Dim iOffsetY As Single = (oPdfDoc.PageSize.Height - (oPdfImportedPage.Height * iFactor)) / 2

				oDirectContent.AddTemplate(oPdfImportedPage, iFactor, 0, 0, iFactor, iOffsetX, iOffsetY)

			Else
				oPdfDoc.SetPageSize(oPdfReader.GetPageSizeWithRotation(iPage))
				oPdfDoc.NewPage()

				If (iRotation = 90) Or (iRotation = 270) Then
					oDirectContent.AddTemplate(oPdfImportedPage, 0, -1.0F, 1.0F, 0, 0, oPdfReader.GetPageSizeWithRotation(iPage).Height)
				Else
					oDirectContent.AddTemplate(oPdfImportedPage, 1.0F, 0, 0, 1.0F, 0, 0)
				End If
			End If
		Loop

	End Sub

	Sub AddImage(ByVal sInFilePath As String, ByRef oPdfDoc As iTextSharp.text.Document, ByRef oPdfWriter As PdfWriter, ByVal sExt As String)

		AddBookmark(oPdfDoc, sInFilePath)

		If chkResize.Checked = False Then
			Dim oDirectContent As iTextSharp.text.pdf.PdfContentByte = oPdfWriter.DirectContent
			Dim oPdfImage As iTextSharp.text.Image
			oPdfImage = iTextSharp.text.Image.GetInstance(sInFilePath)
			oPdfImage.SetAbsolutePosition(1, 1)
			oPdfDoc.SetPageSize(New iTextSharp.text.Rectangle(oPdfImage.Width, oPdfImage.Height))
			oPdfDoc.NewPage()
			oDirectContent.AddImage(oPdfImage)
			Exit Sub
		End If

		Dim oImage As System.Drawing.Image = System.Drawing.Image.FromFile(sInFilePath)

		'Multi-Page Tiff
		If sExt = "TIF" Then
			Dim iPageCount As Integer = oImage.GetFrameCount(Imaging.FrameDimension.Page)
			If iPageCount > 1 Then
				For iPage As Integer = 0 To iPageCount - 1
					oImage.SelectActiveFrame(Imaging.FrameDimension.Page, iPage)
					Dim oMemoryStream As New IO.MemoryStream()
					oImage.Save(oMemoryStream, System.Drawing.Imaging.ImageFormat.Png)
					Dim oImage2 As System.Drawing.Image = System.Drawing.Image.FromStream(oMemoryStream)
					AddImage2(oImage2, oPdfDoc, oPdfWriter)
					oMemoryStream.Close()
				Next
				Exit Sub
			End If
		End If

		AddImage2(oImage, oPdfDoc, oPdfWriter)
		oImage.Dispose()

	End Sub


	Sub AddImage2(ByRef oImage As System.Drawing.Image, ByRef oPdfDoc As iTextSharp.text.Document, ByRef oPdfWriter As PdfWriter)

		Dim oDirectContent As iTextSharp.text.pdf.PdfContentByte = oPdfWriter.DirectContent
		Dim oPdfImage As iTextSharp.text.Image
		Dim iWidth As Single = oImage.Width
		Dim iHeight As Single = oImage.Height
		Dim iAspectRatio As Double = iWidth / iHeight

		Dim iWidthPage As Single = 0
		Dim iHeightPage As Single = 0

		If iAspectRatio < 1 Then
			'Landscape image
			iWidthPage = iTextSharp.text.PageSize.LETTER.Width
			iHeightPage = iTextSharp.text.PageSize.LETTER.Height
		Else
			iHeightPage = iTextSharp.text.PageSize.LETTER.Width
			iWidthPage = iTextSharp.text.PageSize.LETTER.Height
		End If

		Dim iPageAspectRatio As Double = iWidthPage / iHeightPage

		Dim iWidthGoal As Single = 0
		Dim iHeightGoal As Single = 0
		Dim bFitsWithin As Boolean = False

		If iWidth < iWidthPage And iHeight < iHeightPage Then
			'Image fits within the page
			bFitsWithin = True
			iWidthGoal = iWidth
			iHeightGoal = iHeight

		ElseIf iAspectRatio > iPageAspectRatio Then
			'Width is too big
			iWidthGoal = iWidthPage
			iHeightGoal = iWidthPage * (iHeight / iWidth)

		Else
			'Height is too big
			iWidthGoal = iHeightPage * (iWidth / iHeight)
			iHeightGoal = iHeightPage
		End If

		If bFitsWithin = False Then
			oImage = FixedSize(oImage, iWidthGoal, iHeightGoal)
			'oImage.Save("C:\temp\folder1\Lilly_copy.jpg")
		End If

		oPdfImage = iTextSharp.text.Image.GetInstance(oImage, System.Drawing.Imaging.ImageFormat.Png)
		oPdfImage.SetAbsolutePosition(1, 1)

		If iAspectRatio < 1 Then
			'Landscape image
			oPdfDoc.SetPageSize(iTextSharp.text.PageSize.LETTER)
		Else
			oPdfDoc.SetPageSize(iTextSharp.text.PageSize.LETTER.Rotate())
		End If

		oPdfDoc.NewPage()
		oPdfImage.ScaleAbsolute(iWidthGoal, iHeightGoal)
		oDirectContent.AddImage(oPdfImage)

	End Sub

	Private Function FixedSize(ByVal imgPhoto As System.Drawing.Image, _
	ByVal Width As Integer, ByVal Height As Integer) As System.Drawing.Image

		If txtResizeResolution.Text = "" OrElse IsNumeric(txtResizeResolution.Text) = False Then
			txtOutput.Text += "Resize Resolution is not a number."
			Return imgPhoto
		End If

		Dim iResizeResolution As Double = CDbl(txtResizeResolution.Text) / 100
		Width = Width * iResizeResolution
		Height = Height * iResizeResolution

		Dim sourceWidth As Integer = imgPhoto.Width
		Dim sourceHeight As Integer = imgPhoto.Height
		Dim sourceX As Integer = 0
		Dim sourceY As Integer = 0
		Dim destX As Integer = 0
		Dim destY As Integer = 0

		Dim nPercent As Single = 0
		Dim nPercentW As Single = 0
		Dim nPercentH As Single = 0

		nPercentW = (CSng(Width) / CSng(sourceWidth))
		nPercentH = (CSng(Height) / CSng(sourceHeight))

		If nPercentH < nPercentW Then
			nPercent = nPercentH
			destX = CInt(((Width - (sourceWidth * nPercent)) / 2))
		Else
			nPercent = nPercentW
			destY = CInt(((Height - (sourceHeight * nPercent)) / 2))
		End If

		Dim destWidth As Integer = CInt((sourceWidth * nPercent))
		Dim destHeight As Integer = CInt((sourceHeight * nPercent))

		Dim bmPhoto As New Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
		bmPhoto.SetResolution(imgPhoto.HorizontalResolution, imgPhoto.VerticalResolution)

		Dim grPhoto As Graphics = Graphics.FromImage(bmPhoto)
		grPhoto.Clear(Color.White)
		grPhoto.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic

		grPhoto.DrawImage(imgPhoto, New Rectangle(destX, destY, destWidth, destHeight), _
		  New Rectangle(sourceX, sourceY, sourceWidth, sourceHeight), GraphicsUnit.Pixel)

		grPhoto.Dispose()
		imgPhoto.Dispose()

		Return bmPhoto
	End Function