Reputation: 32390
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
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