I am dynamically generating a PDF document with iTextSharp. I don't know how many pages it will contain. I have managed to create headers and footers on all pages by overriding OnStartPage and OnEndPage on PdfPageEventHelper. However, with this approach the header is the same on all pages and the footer is the same on all pages. I need to be more dynamic: I need to show a different footer on the last page.
When I am in the OnEndPage method I know the pagenumber of the page, but I don't know whether it is the last. When I am in the OnCloseDocument method I know the total number of pag开发者_Python百科es, but I cannot from here "delete" or "remove" or change the footer that was added to the last page by OnEndPage.
So you've got a main loop of code that's creating pages and adding content, right? Once that content finishes can you set a global flag that OnEndPage
looks for?
The code below (in VB.Net, sorry) creates a class (so we can pass it around by reference) with a single boolean variable that once we finish our main processing loop we set to true
so that OnEndPage
knows to do something different. Sorry for the verbose IPdfPageEvent
, VB requires all methods to be declared even if you don't use them.
Option Explicit On
Option Strict On
Imports iTextSharp.text
Imports iTextSharp.text.pdf
Imports System.IO
Public Class Form1
''//Holds our state information
Private PageState As CustomPageState
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
''//Create a new document
Dim Doc As New iTextSharp.text.Document(PageSize.LETTER)
''//Write it to a memory stream
Using FS As New FileStream(Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "Output.pdf"), FileMode.Create, FileAccess.Write, FileShare.Read)
''//Grab the writer
Dim writer = PdfWriter.GetInstance(Doc, FS)
''//Create an object that we can pass by reference around to store the page state
Me.PageState = New CustomPageState()
''//Wire our event handler and pass in the page state
writer.PageEvent = New MyCustomPdfEvent(Me.PageState)
''//Open the PDF for writing
Doc.Open()
''//Main loop, create a bunch of pages
For I = 1 To 10
Doc.NewPage()
Doc.Add(New Phrase("Hello"))
''//This code goes at the very end of our main loop
If I = 10 Then Me.PageState.IsLastPage = True
Next
''//Close the PDF
Doc.Close()
End Using
End Sub
''//This is our state container. Its just has a boolean value but its wrapped in a class so that we can pass it around by reference
Public Class CustomPageState
Public Property IsLastPage As Boolean = False
End Class
Public Class MyCustomPdfEvent
Implements IPdfPageEvent
''//Reference to the state container
Private PageState As CustomPageState
Public Sub New(ByRef pageState As CustomPageState)
Me.PageState = pageState
End Sub
Public Sub OnEndPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document) Implements iTextSharp.text.pdf.IPdfPageEvent.OnEndPage
If Me.PageState.IsLastPage Then
''//Last page, do something different
Else
''//Do normal page footer
End If
End Sub
Public Sub OnChapter(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single, ByVal title As iTextSharp.text.Paragraph) Implements iTextSharp.text.pdf.IPdfPageEvent.OnChapter
End Sub
Public Sub OnChapterEnd(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single) Implements iTextSharp.text.pdf.IPdfPageEvent.OnChapterEnd
End Sub
Public Sub OnCloseDocument(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document) Implements iTextSharp.text.pdf.IPdfPageEvent.OnCloseDocument
End Sub
Public Sub OnGenericTag(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal rect As iTextSharp.text.Rectangle, ByVal text As String) Implements iTextSharp.text.pdf.IPdfPageEvent.OnGenericTag
End Sub
Public Sub OnOpenDocument(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document) Implements iTextSharp.text.pdf.IPdfPageEvent.OnOpenDocument
End Sub
Public Sub OnParagraph(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single) Implements iTextSharp.text.pdf.IPdfPageEvent.OnParagraph
End Sub
Public Sub OnParagraphEnd(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single) Implements iTextSharp.text.pdf.IPdfPageEvent.OnParagraphEnd
End Sub
Public Sub OnSection(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single, ByVal depth As Integer, ByVal title As iTextSharp.text.Paragraph) Implements iTextSharp.text.pdf.IPdfPageEvent.OnSection
End Sub
Public Sub OnSectionEnd(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document, ByVal paragraphPosition As Single) Implements iTextSharp.text.pdf.IPdfPageEvent.OnSectionEnd
End Sub
Public Sub OnStartPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document) Implements iTextSharp.text.pdf.IPdfPageEvent.OnStartPage
End Sub
End Class
End Class
I believe you can modify instances of PdfTemplate
until you call document.close()
.
- Change your header/footer code to draw everything inside a
PdfTemplate
. - Save the last
PdfTemplate
between pages. - Just before calling
document.close()
, reset that last header-and-or-footer and draw it the way you need it for that last page.
PS: Using a PdfTemplate
can be really efficient when drawing Exactly The Same Thing to multiple pages. You build the template once, then reuse it on every page that needs it. In this particular case however, it actually adds a little overhead because you have to create one for each page just so you can change the last one after the fact.
OTOH, if you have largely the same stuff on every page, plus a little extra stuff on the last one, you can nest templates. One that has Unchanging Stuff, and another template that simply wraps that one on all pages but the last. On the last page, rather than resetting the existing content, you could simply add to it.
PPS: IIRC, this is how you build "page x of y" footers. All the pages contain some direct content with "page x of ". Once you've rendered all your pages, prior to close()
, you fill in that template with the page count.
精彩评论