Vivian River
Vivian River

Reputation: 32390

Is it possible to print in the margins with iTextSharp?

I'm writing a web application that outputs PDFs. The main content of my PDF is a table data. I would like to make a message appear in the margins to the left and right of my table.

How can I do this, taking into account that the table will likely span several pages?

Upvotes: 0

Views: 1532

Answers (1)

Chris Haas
Chris Haas

Reputation: 55417

The easiest way to do this is probably to use Page Events. To use Page Events you need to subclass PdfPageEventHelper:

Public Class CustomPageEventHandler
    Inherits iTextSharp.text.pdf.PdfPageEventHelper
End Class

The parent class has a bunch of methods that you can override, the one that you probably want is OnStartPage(). By overriding this, your custom code will get called for every page in the document.

Public Class CustomPageEventHandler
    Inherits iTextSharp.text.pdf.PdfPageEventHelper
    Public Overrides Sub OnStartPage(writer As iTextSharp.text.pdf.PdfWriter, document As iTextSharp.text.Document)
        ''//Anything you do here will be done on every page
    End Sub
End Class

To bind your custom page event handler to a PdfWriter object called writer you'd just do:

writer.PageEvent = New CustomPageEventHandler()

As to what to do in the OnStartPage() method you've got a couple of choices. Unfortunately, working with the Document object itself will probably prove problematic. This object is meant as an abstraction for dealing with higher level concepts but doesn't always provide a way to do things at specific x,y coordinates. Using it here with text will just cause text to flow strangely.

Instead you'll want to work with a raw PdfContentByte object which you can get from the writer's DirectContent property.

Dim cb = writer.DirectContent

Once you have that you've got a couple of options, I'll show you two. The first is to use a ColumnText object which you can pretty much think of as a table. In fact, most people use it as a single row, single column table. The ColumnText object is nice because it allows you to use the higher level abstractions such as Paragraph and it will automatically handle things like line breaks.

Dim CT As New ColumnText(writer.DirectContent)
CT.SetSimpleColumn(llx, lly, urx, ury) ''//Coordinates to draw text to
CT.AddElement(New Paragraph("This goes in the margin"))
CT.Go()

The second option is to just draw the text yourself. The biggest downside of this is that you can't work with the higher level abstractions like Paragraph. So if you draw a really long line of text it won't break it and start a new line for you, it will keep on drawing outside of the viewable document.

Dim cb = writer.DirectContent
cb.BeginText()
cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.TIMES_BOLD, BaseFont.CP1250, BaseFont.NOT_EMBEDDED), 8)
cb.SetColorFill(BaseColor.RED)
cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "right margin", x, y, 0)
cb.EndText()

Putting that all together, below is a full working VB.Net 2010 WinForm app targeting iTextSharp 5.1.2.0 that shows off all of the above. See the comments in the code for specific details.

Option Strict On
Option Explicit On

Imports System.IO
Imports iTextSharp.text
Imports iTextSharp.text.pdf

Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        ''//Test file that we'll create
        Dim TestFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.pdf")
        ''//Standard PDF setup, change as needed for your stream type
        Using FS As New FileStream(TestFile, FileMode.Create, FileAccess.Write, FileShare.None)
            Using Doc As New Document(PageSize.LETTER)
                Using writer = PdfWriter.GetInstance(Doc, FS)
                    ''//Bind our custom event handler to our writer object
                    writer.PageEvent = New CustomPageEventHandler()
                    Doc.Open()

                    ''//Add text on page 1
                    Doc.Add(New Paragraph("Page 1"))
                    ''//Add a new page
                    Doc.NewPage()
                    ''//Add text on page 2
                    Doc.Add(New Paragraph("Page 2"))

                    Doc.Close()
                End Using
            End Using
        End Using

        Me.Close()
    End Sub
    Public Class CustomPageEventHandler
        Inherits iTextSharp.text.pdf.PdfPageEventHelper
        ''//This will get called whenever a new page gets added to the document
        Public Overrides Sub OnStartPage(writer As iTextSharp.text.pdf.PdfWriter, document As iTextSharp.text.Document)
            ''//Pre-calculate the Y coordinates for use later
            Dim yBot = document.PageSize.Height - 300
            Dim yTop = yBot + 200

            ''//For the left margin we'll use the ColumnText object
            Dim CT As New ColumnText(writer.DirectContent)
            ''//Create a single column object bound to our margin and using the y coordinates from above
            CT.SetSimpleColumn(0, yBot, document.LeftMargin, yTop)
            ''//Add a simple paragraph
            CT.AddElement(New Paragraph("This goes in the margin"))
            ''//Draw the text
            CT.Go()


            ''//For the right margin we'll draw the text manually
            ''//Grab the raw canvas
            Dim cb = writer.DirectContent
            ''//Store the current graphics state so that we can restore it later
            cb.SaveState()

            ''//Flag that we're begining text
            cb.BeginText()
            ''//Set a font and size to draw with
            cb.SetFontAndSize(BaseFont.CreateFont(BaseFont.TIMES_BOLD, BaseFont.CP1250, BaseFont.NOT_EMBEDDED), 8)
            ''//Set a color for the text
            cb.SetColorFill(BaseColor.RED)
            ''//Draw the text at a specific x,y coordinate. NOTE: These commands assume do not break text for you automatically
            cb.ShowTextAligned(PdfContentByte.ALIGN_LEFT, "right margin", document.PageSize.Width - document.RightMargin, yTop, 0)
            ''//Flag that we're doing with our text
            cb.EndText()

            ''//Restore the graphics state to whatever it was before we started messing with it
            cb.RestoreState()


        End Sub
    End Class
End Class

Upvotes: 1

Related Questions