(使用itextsharp 5.4.3)
我创建了一个应用程序,用户可以在其中创建围绕页面主要内容的自定义xhtml页眉和页脚。所以生成的pdf如下所示:
------------------------
| xhtml parsed Header |
------------------------
| |
| xhtml parsed content |
| |
------------------------
| xhtml parsed Footer |
------------------------
我已正确生成pdf但是我只希望标题出现在第一页上,并且能够(重新)设置其余页面的边距。目前它仅显示第一页上的标题(正确)但保留其余页面的边距(不正确)而不显示标题(正确)。 所以3页生成的pdf看起来像
------------------------
| xhtml parsed Header |
------------------------
| |
| xhtml parsed content |
| |
------------------------
| Page 1 |
------------------------
------------------------
| |
------------------------
| |
| xhtml parsed content |
| |
------------------------
| Page 2 |
------------------------
------------------------
| |
------------------------
| |
| xhtml parsed content |
| |
------------------------
| Page 3 |
------------------------
使用XML Parser和PageEvents解析内容 (生成按钮的代码)
Protected Sub btnPreview_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPreview.Click
Dim bytes As Byte()
Dim replaced As String = HttpUtility.HtmlDecode(letterRadEdit.Content.Replace("<br>", "<br />"))
Dim replaced2 As String = HttpUtility.UrlDecode(replaced)
bytes = System.Text.Encoding.UTF8.GetBytes(letterRadEdit.Content)
Dim tagProcessor As tool.xml.html.DefaultTagProcessorFactory()
Using input As New MemoryStream(bytes, False)
Dim ms As New MemoryStream()
Dim document As New iTextSharp.text.Document(iTextSharp.text.PageSize.LETTER, 36.0F, 36.0F, 52.0F, 52.0F)
Dim headerFooter As New iTextSharpHeaderFooter()
If Not String.IsNullOrEmpty(ddlHeaders.SelectedValue) Or Not String.IsNullOrEmpty(ddlFooters.SelectedValue) Then
Using db As New dbEntities()
If Not String.IsNullOrEmpty(ddlHeaders.SelectedValue) Then
'Get header content
Dim headerGuid As Guid = New Guid(ddlHeaders.SelectedValue)
Dim selectedheader As New LetterHeaderFooter()
selectedheader = (From hf In db.LetterHeaderFooters
Where hf.HeadFootID = headerGuid And hf.HeadFootType = 1
Select hf).FirstOrDefault()
Dim headerbytes As Byte()
headerbytes = System.Text.Encoding.UTF8.GetBytes(HttpUtility.HtmlDecode(selectedheader.HeadFootContent.Replace("<br>", "<br />").Trim()))
headerFooter.HeaderHTML = HttpUtility.HtmlDecode(selectedheader.HeadFootContent.Replace("<br>", "<br />").Trim())
headerFooter.HeaderContent = headerbytes
'Start building header into table
Dim page As New Rectangle(document.PageSize.Width - 72.0F, document.PageSize.Height)
Dim cellHeight As Single = document.TopMargin
Dim header As New PdfPTable(1)
header.TotalWidth = page.Width
Dim c As New PdfPCell()
c.HorizontalAlignment = Element.ALIGN_LEFT
c.Border = PdfPCell.BOTTOM_BORDER
Dim mh As SampleHandler = New SampleHandler()
Using sr As TextReader = New StringReader(headerFooter.HeaderHTML)
XMLWorkerHelper.GetInstance().ParseXHtml(mh, sr)
End Using
For Each el As IElement In mh.elements
c.AddElement(el)
Next
header.AddCell(c)
Dim startingMargin As Single = (header.TotalHeight + document.TopMargin)
document.SetMargins(document.LeftMargin, document.RightMargin, startingMargin, document.BottomMargin)
headerFooter.PageHeader = header
End If
End Using
End If
Dim writer As PdfWriter = PdfWriter.GetInstance(document, ms)
writer.PageEvent = headerFooter
writer.CloseStream = False
document.Open()
Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(Nothing)
htmlContext.SetAcceptUnknown(True)
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory())
Dim cssResolver As ICSSResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(True)
cssResolver.AddCssFile(HttpContext.Current.Server.MapPath("~/assets/css/pdf.css"), True)
Dim pipeline As New CssResolverPipeline(cssResolver, New HtmlPipeline(htmlContext, New PdfWriterPipeline(document, writer)))
Dim pdfworker As New XMLWorker(pipeline, True)
Dim p As New XMLParser(True, pdfworker, New System.Text.UTF8Encoding)
Try
p.Parse(input)
Catch
Finally
pdfworker.Close()
End Try
document.Close()
ms.Position = 0
Response.ContentType = "application/pdf"
Response.AppendHeader("Expires", "0")
Response.AppendHeader(
"Cache-Control",
"must-revalidate, post-check=0, pre-check=0"
)
Response.AppendHeader("Pragma", "public")
Response.AppendHeader("content-disposition", "attachment; filename=preview.pdf")
Response.BinaryWrite(ms.ToArray())
ms.Flush()
End Using
End Sub
iTextSharpHeaderFooter类位于
之下Public Class iTextSharpHeaderFooter
Inherits PdfPageEventHelper
Private _HeaderStream As Byte()
Private _FooterStream As Byte()
Private _HeaderHTML As String
Private _FooterHTML As String
Private _headerPdf As Document
Private _footerPdf As Document
Private _usesHeader As Boolean
Private _pageHeader, _pageFooter As PdfPTable
'This is the contentbyte object of the writer
Dim cb As PdfContentByte
' we will put the final number of pages in a template
Dim template As PdfTemplate
' this is the BaseFont we are going to use for the header / footer
Dim bf As BaseFont = Nothing
' This keeps track of the creation time
Dim PrintTime As DateTime = DateTime.Now
Public Property HeaderContent() As Byte()
Get
Return _HeaderStream
End Get
Set(ByVal value As Byte())
_HeaderStream = value
End Set
End Property
Public Property FooterContent() As Byte()
Get
Return _FooterStream
End Get
Set(ByVal value As Byte())
_FooterStream = value
End Set
End Property
Public Property HeaderHTML() As String
Get
Return _HeaderHTML
End Get
Set(ByVal value As String)
_HeaderHTML = value
End Set
End Property
Public Property FooterHTML() As String
Get
Return _FooterHTML
End Get
Set(ByVal value As String)
_FooterHTML = value
End Set
End Property
Public Property letterHeader() As Document
Get
Return _headerPdf
End Get
Set(ByVal value As Document)
_headerPdf = value
End Set
End Property
Public Property letterFooter() As Document
Get
Return _footerPdf
End Get
Set(ByVal value As Document)
_footerPdf = value
End Set
End Property
Public Property UsesHeader() As Boolean
Get
Return _usesHeader
End Get
Set(ByVal value As Boolean)
_usesHeader = value
End Set
End Property
Public Property PageHeader() As PdfPTable
Get
Return _pageHeader
End Get
Set(ByVal value As PdfPTable)
_pageHeader = value
End Set
End Property
Public Property PageFooter() As PdfPTable
Get
Return _pageFooter
End Get
Set(ByVal value As PdfPTable)
_pageFooter = value
End Set
End Property
' we override the onOpenDocument method
Public Overrides Sub OnOpenDocument(ByVal writer As PdfWriter, ByVal document As Document)
MyBase.OnOpenDocument(writer, document)
Try
PrintTime = DateTime.Now
Catch de As DocumentException
Catch ioe As System.IO.IOException
End Try
End Sub
Public Overrides Sub OnStartPage(ByVal writer As PdfWriter, ByVal document As Document)
MyBase.OnStartPage(writer, document)
End Sub
Public Overrides Sub OnEndPage(ByVal writer As PdfWriter, ByVal document As Document)
MyBase.OnEndPage(writer, document)
Dim pageSize As Rectangle = document.PageSize
Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(Nothing)
htmlContext.SetAcceptUnknown(True)
htmlContext.SetTagFactory(Tags.GetHtmlTagProcessorFactory())
If Not HeaderContent Is Nothing And HeaderContent.Length > 0 And writer.PageNumber < 2 Then
Dim page As New Rectangle(document.PageSize.Width - 72.0F, document.PageSize.Height)
PageHeader.WriteSelectedRows(0, -1, 0, -1, document.LeftMargin, page.Height, writer.DirectContent)
End If
If writer.PageNumber > 1 Then
document.SetPageSize(New Rectangle(36.0F, 36.0F, 52.0F, PageFooter.TotalHeight))
End If
If Not FooterContent Is Nothing And FooterContent.Length > 0 Then
Dim page As New Rectangle(document.PageSize.Width - 72.0F, document.PageSize.Height)
PageFooter.WriteSelectedRows(0, -1, 0, -1, document.LeftMargin, PageFooter.TotalHeight, writer.DirectContent)
End If
Dim fontSize As Integer = 160
Dim xPosition As Integer = 300
Dim yPosition As Integer = 400
Dim angle As Integer = 45
Dim under As PdfContentByte = writer.DirectContentUnder
Dim baseFont As BaseFont = baseFont.CreateFont(baseFont.HELVETICA, baseFont.WINANSI, baseFont.EMBEDDED)
under.BeginText()
under.SetColorFill(BaseColor.LIGHT_GRAY)
under.SetFontAndSize(baseFont, fontSize)
under.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Preview", xPosition, yPosition, angle)
under.EndText()
End Sub
Public Overrides Sub OnCloseDocument(ByVal writer As PdfWriter, ByVal document As Document)
MyBase.OnCloseDocument(writer, document)
End Sub
End Class
我尝试在OnEndPage和OnStartPage中更改页边距,但都没有任何结果。我查看了上一个问题“How do I change the margin for the second page in a PDF using iTextsharp?”,但看不到我想(或应该)添加page.NewPage()NewPage在页面事件中的位置?
(同样作为一个子问题,我的pdf在Acrobat Reader X中关闭时继续说“你想保存更改”,我查看了之前的SO问题,它说使用ToArray()而不是ToBuffer(),am我错过了什么?)
答案 0 :(得分:2)
我相信我已经解决了这个问题,这是OnEndPage函数的一部分:
If writer.PageNumber > 1 Then
应该是
If writer.PageNumber = 1 Then
正如我所读到的,任何边距都会应用到后续页面。这意味着第3页的页边距会更改,因为页码是2,因此我需要设置第1页末尾的页边距而不是第2页。