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

Posted on 2016-11-04
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

                                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
                                        chpNo += 1
                                        reader = New PdfReader(file)
                                    End If


                            Catch generatedExceptionName As Exception
                                merged = False
                                If reader IsNot Nothing Then
                                End If
                                If document IsNot Nothing Then
                                End If
                            End Try
                        End Using

Open in new window

Question by:Karen Wilson
LVL 32

Accepted Solution

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

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  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)

            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
                    '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))
                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
                        'Create a new page on the output document
                        '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
                        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)
                            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
                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)

                                End Using

                                bytes = stream.ToArray()

                            End Using

                            File.WriteAllBytes(jfFile, bytes)

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

Featured Post

ScreenConnect 6.0 Free Trial

At ScreenConnect, partner feedback doesn't fall on deaf ears. We collected partner suggestions off of their virtual wish list and transformed them into one game-changing release: ScreenConnect 6.0. Explore all of the extras and enhancements for yourself!

Question has a verified solution.

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

This tutorial demonstrates one way to create an application that runs without any Forms but still has a GUI presence via an Icon in the System Tray. The magic lies in Inheriting from the ApplicationContext Class and passing that to Application.Ru…
Parsing a CSV file is a task that we are confronted with regularly, and although there are a vast number of means to do this, as a newbie, the field can be confusing and the tools can seem complex. A simple solution to parsing a customized CSV fi…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

803 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