2013-11-14 4 views
2

(с использованием 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() ? Я-то отсутствует)

ответ

2

Я считаю, что я решил это, часть функции OnEndPage:

If writer.PageNumber > 1 Then 

должен быть

If writer.PageNumber = 1 Then 

как, от того, что я прочитал, любой мар джины применяются к последующим страницам. это означало бы, что маржа будет изменена для страницы 3, поскольку номер страницы будет равен 2, поэтому мне нужно установить поля в конце страницы 1, а не на странице 2.

Смежные вопросы