Solved

How do I add bookmarks to PDF using iTextSharp in Visual Studio

Posted on 2016-11-04
2
121 Views
Last Modified: 2016-11-25
I am trying to add a bookmark when I merge PDFs into one PDF.  It's, of course, not working.  Any help or direction would be greatly appreciated.

Here is my code:

                        Dim merged As Boolean = True

                        Using Stream As New FileStream(jfFile, FileMode.Create)

                            Dim document As New Document()
                            Dim pdf As New PdfCopy(document, Stream)
                            Dim reader As PdfReader = Nothing
                            Dim writer As PdfWriter = Nothing
                            Dim pNumber As Integer = 0
                            Try
                                document.Open()

                                Dim getPDF = (From id In d.tbl645s _
                                   Where id.closedDate = "" _
                                    Or id.closedDate Is Nothing _
                                    Order By id.projName1 Ascending _
                                    Select id.hardcopyLink).ToList

                             
                                getPDF.Insert(0, jfFileOrg)

                                Dim chpNo As Integer = 1

                                For Each file As String In getPDF

                                    Dim getName = (From id In d.tbl645s _
                                                  Where id.hardcopyLink = file _
                                                  Select id.projNumber2).ToList

                                    If getName.Count = 1 Then

                                        reader = New PdfReader(file)
                                        Dim chap As New Chapter("Chapter ", chpNo)
                                        chap.BookmarkTitle = CStr(getName.Item(0))
                                        chap.BookmarkOpen = True
                                        pdf.Add(chap)
                                        pdf.AddDocument(reader)
                                        reader.Close()
                                        chpNo += 1
                                    Else
                                        reader = New PdfReader(file)
                                        pdf.AddDocument(reader)
                                        reader.Close()
                                    End If

                                Next

                            Catch generatedExceptionName As Exception
                                merged = False
                                If reader IsNot Nothing Then
                                    reader.Close()
                                End If
                            Finally
                                If document IsNot Nothing Then
                                    document.Close()
                                End If
                            End Try
                        End Using

Open in new window

0
Comment
Question by:Karen Wilson
2 Comments
 
LVL 32

Accepted Solution

by:
Robberbaron (robr) earned 500 total points
ID: 41875290
I use PDFSharp, similar but has a better licence.

In it, bookmark page is called Outline..

and to that I add DocumentLinks
XRect docid_rect = new XRect(new PdfSharp.Drawing.XPoint(marginX, yIdx - contentBoxHt), new PdfSharp.Drawing.XPoint(gfx.PageSize.Width, yIdx));
	outlineEntry = string.Format("{0} ({1}) : {2} ", id.DocId, id.RevId, id.DocName);
	gfx.DrawString(outlineEntry, font, XBrushes.CadetBlue, docid_rect, XStringFormats.TopLeft);


	//have to transform to Defult page orientation
	PdfRectangle linkzone = new PdfRectangle(gfx.Transformer.WorldToDefaultPage(docid_rect));
	pageIdx.AddDocumentLink(linkzone, outPDF.PageCount + indexpages);  //link to page about to be added
	idxCount++;  //count the number of indexs written

	// Create a sub bookmark
	//outline.Outlines.Add(id.FileName, page, true);
	outline.Outlines.Add(outlineEntry, page, true);  //add full index entry

Open in new window

hope this helps
0
 

Author Closing Comment

by:Karen Wilson
ID: 41877033
After doing more research I found a different solution.  I will give you the credit because you answered and your answer falls in line with what I did.  Here is the code I used for others who may read this question.

I created a function to perform the bookmarking.  I got this from a previous answer in Expert Exchange and converted it to VB.net.  It, of course, uses information that I require so you'll have to change bits of it to meet your need.

 Public Function MergePdfFiles(ByVal pdfFiles() As String, ByVal outputPath As String) As Boolean

        Dim result As Boolean = False
        Dim pdfCount As Integer = 0 'total input pdf file count
        Dim f As Integer = 0 'pointer to current input pdf file
        Dim fileName As String = String.Empty 'current input pdf filename
        Dim reader As iTextSharp.text.pdf.PdfReader = Nothing
        Dim pageCount As Integer = 0 'current input pdf page count
        Dim pdfDoc As iTextSharp.text.Document = Nothing 'the output pdf document
        Dim writer As PdfWriter = Nothing
        Dim cb As PdfContentByte = Nothing
        'Declare a variable to hold the imported pages
        Dim page As PdfImportedPage = Nothing
        Dim rotation As Integer = 0
        'Declare a font to used for the bookmarks
        Dim bookmarkFont As iTextSharp.text.Font = iTextSharp.text.FontFactory.GetFont(iTextSharp.text.FontFactory.HELVETICA, _
        8, iTextSharp.text.Font.NORMAL, iTextSharp.text.BaseColor.GRAY)

        Try
            pdfCount = pdfFiles.Length

            If pdfCount > 1 Then
                'Open the 1st pad using PdfReader object
                fileName = pdfFiles(f)
                reader = New iTextSharp.text.pdf.PdfReader(fileName)
                'Get page count
                pageCount = reader.NumberOfPages
                'Instantiate an new instance of pdf document and set its margins. This will be the output pdf.
                'NOTE: bookmarks will be added at the 1st page of very original pdf file using its filename. The location
                'of this bookmark will be placed at the upper left hand corner of the document. So you'll need to adjust
                'the margin left and margin top values such that the bookmark won't overlay on the merged pdf page. The
                'unit used is "points" (72 points = 1 inch), thus in this example, the bookmarks' location is at 1/4 inch from
                'left and 1/4 inch from top of the page.
                pdfDoc = New iTextSharp.text.Document(reader.GetPageSizeWithRotation(1), 18, 18, 18, 18)
                'Instantiate a PdfWriter that listens to the pdf document
                writer = PdfWriter.GetInstance(pdfDoc, New System.IO.FileStream(outputPath, System.IO.FileMode.Create))
                'Set metadata and open the document
                With pdfDoc
                    .AddAuthor(Environ("username"))
                    .AddCreationDate()
                    .AddCreator("EIMS")
                    .AddSubject("PMP")
                    'Use the filename as the title... You can give it any title of course.
                    .AddTitle("PMP Data Pack")
                    'Add keywords, whatever keywords you want to attach to it
                    .AddKeywords("Report, Merged PDF, " & System.IO.Path.GetFileName(outputPath))
                    .Open()
                End With
                'Instantiate a PdfContentByte object
                cb = writer.DirectContent
                'Now loop thru the input pdfs
                While f < pdfCount
                    'Declare a page counter variable
                    Dim i As Integer = 0
                    'Loop thru the current input pdf's pages starting at page 1
                    While i < pageCount
                        i += 1
                        'Get the input page size
                        pdfDoc.SetPageSize(reader.GetPageSizeWithRotation(i))
                        'Create a new page on the output document
                        pdfDoc.NewPage()
                        'If it is the 1st page, we add bookmarks to the page
                        If i = 1 Then
                            'First create a paragraph using the filename as the heading

                            Dim getTO = (From id In d.tbl645s _
                                        Where id.hardcopyLink = CStr(fileName) _
                                        Select id.projNumber2).ToList

                            Dim fName As String = "Task Orders"

                            If getTO.Count = 1 Then
                                fName = CStr(getTO.Item(0))
                            End If

                            Dim para As New iTextSharp.text.Paragraph(fName.ToUpper(), bookmarkFont)
                            'Then create a chapter from the above paragraph
                            Dim chpter As New iTextSharp.text.Chapter(para, f + 1)
                            'Finally add the chapter to the document
                            pdfDoc.Add(chpter)
                        End If
                        'Now we get the imported page
                        page = writer.GetImportedPage(reader, i)
                        'Read the imported page's rotation
                        rotation = reader.GetPageRotation(i)
                        'Then add the imported page to the PdfContentByte object as a template based on the page's rotation
                        If rotation = 90 Then
                            cb.AddTemplate(page, 0, -1.0F, 1.0F, 0, 0, reader.GetPageSizeWithRotation(i).Height)
                        ElseIf rotation = 270 Then
                            cb.AddTemplate(page, 0, 1.0F, -1.0F, 0, reader.GetPageSizeWithRotation(i).Width + 60, -30)
                        Else
                            cb.AddTemplate(page, 1.0F, 0, 0, 1.0F, 0, 0)
                        End If
                    End While
                    'Increment f and read the next input pdf file
                    f += 1
                    If f < pdfCount Then
                        fileName = pdfFiles(f)
                        reader = New iTextSharp.text.pdf.PdfReader(fileName)
                        pageCount = reader.NumberOfPages
                    End If
                End While
                'When all done, we close the docum went so that the pdfwriter object can write it to the output file
                pdfDoc.Close()
                result = True
            End If
        Catch ex As Exception
            Throw New Exception(ex.Message)
        End Try
        Return result
    End Function

'=============================

I then made a list of all the PDFs I require and put it into an array.  I ran it through the function and added adding page numbers to my merged PDF.

 Dim getPDF = (From id In d.tbl645s _
                            Where id.closedDate = "" _
                            Or id.closedDate Is Nothing _
                            Order By id.projName1 Ascending _
                            Select id.hardcopyLink).ToList

                       getPDF.Insert(0, jfFileOrg) 'I am adding the cover page I created to the list of PDFs

                        Dim input() As String = getPDF.ToArray
                        Dim output As String = jfFile 'Then call the function to merge the files
                        If MergePdfFiles(input, output) = True Then

                            '=========  Add Page Numbers ========================

                            Dim bytes As Byte() = File.ReadAllBytes(jfFile)

                            Dim blackFont As iTextSharp.text.Font = FontFactory.GetFont("Arial", 9, Font.Bold, BaseColor.BLACK)

                            Using stream As New MemoryStream()

                                Dim reader As New PdfReader(bytes)

                                Using stamper As New PdfStamper(reader, stream)

                                    Dim pages As Integer = reader.NumberOfPages

                                    For i As Integer = 1 To pages
                                        ColumnText.ShowTextAligned(stamper.GetUnderContent(i), Element.ALIGN_LEFT, New Phrase(i.ToString() & " of " & CStr(pages), blackFont), 568.0F, 15.0F, 0)
                                    Next

                                End Using

                                bytes = stream.ToArray()

                            End Using

                            File.WriteAllBytes(jfFile, bytes)
                            System.Diagnostics.Process.Start(jfFile)

                        Else
                            MessageBox.Show("Files did not merged successfully")
                        End If
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

I think the Typed DataTable and Typed DataSet are very good options when working with data, but I don't like auto-generated code. First, I create an Abstract Class for my DataTables Common Code.  This class Inherits from DataTable. Also, it can …
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

829 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question