(с использованием itextsharp 5.4.3)iTextSharp применять различные поля для различных страниц
Я создал приложение, в котором пользователь может создавать пользовательское 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, в котором говорится, что вместо ToBuffer() используется ToArray() ? Я-то отсутствует)