2016-06-29 22 views
0

Hintergrund:iTextSharp base64 eingebettete Bild in Header nicht Parsen/zeigt

ich einen Editor, wo ich die Kopf- und Fußzeile eines Dokuments in HTML bearbeiten und sie dann in das Hauptdokument zusammenführen. Base64 Eingebettete Bilder funktionieren perfekt im Hauptdokumentinhalt, aber in den Kopf- oder Fußzeilen verschwinden sie (wenn ich also ein Hauptdokument mit image1.png habe und dieses Dokument eine Kopfzeile mit image_header.png hat, wird image1 angezeigt, image_header wird nicht). Es sieht für mich so aus, dass der Tag-Prozessor nicht auf die Elemente in PageHeader html angewendet wird.

ich eine benutzerdefinierte ImageTagProcessor (unten) erstellt haben

Public Class CustomImageTagProcessor 
    Inherits iTextSharp.tool.xml.html.Image 
    Public Overrides Function [End](ctx As IWorkerContext, tag As Tag, currentContent As IList(Of IElement)) As IList(Of IElement) 
     Dim attributes As IDictionary(Of String, String) = tag.Attributes 
     Dim src As String = String.Empty 
     If Not attributes.TryGetValue(iTextSharp.tool.xml.html.HTML.Attribute.SRC, src) Then 
      Return New List(Of IElement)(1) 
     End If 

     If String.IsNullOrEmpty(src) Then 
      Return New List(Of IElement)(1) 
     End If 



     If src.StartsWith("data:image/", StringComparison.InvariantCultureIgnoreCase) Then 
      ' data:[<MIME-type>][;charset=<encoding>][;base64],<data> 
      Dim base64Data As String = src.Substring(src.IndexOf(",") + 1) 
      Dim imagedata As Byte() = Convert.FromBase64String(base64Data) 
      Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(imagedata) 

      Dim list As List(Of IElement) = New List(Of IElement)() 
      Dim htmlPipelineContext As pipeline.html.HtmlPipelineContext = GetHtmlPipelineContext(ctx) 
      list.Add(GetCssAppliers().Apply(New Chunk(DirectCast(GetCssAppliers().Apply(image, tag, htmlPipelineContext), iTextSharp.text.Image), 0, 0, True), tag, htmlPipelineContext)) 
      Return list 
     Else 
      If File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, src)) Then 
       Dim imagedata As Byte() = File.ReadAllBytes(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, src)) 
       Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, src)) 

       Dim list As List(Of IElement) = New List(Of IElement)() 
       Dim htmlPipelineContext As pipeline.html.HtmlPipelineContext = GetHtmlPipelineContext(ctx) 
       list.Add(GetCssAppliers().Apply(New Chunk(DirectCast(GetCssAppliers().Apply(image, tag, htmlPipelineContext), iTextSharp.text.Image), 0, 0, True), tag, htmlPipelineContext)) 
       Return list 
      End If 
      Return MyBase.[End](ctx, tag, currentContent) 
     End If 
    End Function 
End Class 

und wird durch den folgenden Code in der Haupt PDF Generator Bibliothek

Dim tagProcessors As DefaultTagProcessorFactory = CType(Tags.GetHtmlTagProcessorFactory(), DefaultTagProcessorFactory) 
tagProcessors.RemoveProcessor(HTML.Tag.IMG) ' remove the default processor 
tagProcessors.AddProcessor(HTML.Tag.IMG, New CustomImageTagProcessor()) ' use our new processor 

'Setup CSS 
Dim cssResolver As ICSSResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(True) 
cssResolver.AddCssFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "assets/css/pdf.css"), True) 
'Setup Fonts 
Dim xmlFontProvider As XMLWorkerFontProvider = New XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS) 
xmlFontProvider.RegisterDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "assets/fonts/")) 

Dim cssAppliers As CssAppliers = New CssAppliersImpl(xmlFontProvider) 
Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(cssAppliers) 
htmlContext.SetAcceptUnknown(True) 
htmlContext.SetTagFactory(tagProcessors) 

'Setup Pipelines 
Dim pdf As PdfWriterPipeline = New PdfWriterPipeline(document, writer) 
Dim htmlp As HtmlPipeline = New HtmlPipeline(htmlContext, pdf) 
Dim css As CssResolverPipeline = New CssResolverPipeline(cssResolver, htmlp) 

In meinem Header Klasse (Vererben von PdfPageEventHelper) a verbunden neue Instanz der Klasse in:

Public Sub New(ByVal headerHTML As String, ByVal footerHTML As String) 
    MyBase.New() 

    '< Other code not related > 

    Dim pdfElHandler As New PdfElementsHandler() 

    Using sr As TextReader = New StringReader(Me.HeaderHTML) 
     XMLWorkerHelper.GetInstance().ParseXHtml(pdfElHandler, sr) 
    End Using 
    headerElements = pdfElHandler.elements 

    Using sr As TextReader = New StringReader(Me.FooterHTML) 
     XMLWorkerHelper.GetInstance().ParseXHtml(pdfElHandler, sr) 
    End Using 
    footerElements = pdfElHandler.elements 

    headerTable = New PdfPTable(1) 
    headerTable = BuildElements(headerElements, "header") 

    footerTable = New PdfPTable(1) 
    footerTable = BuildElements(footerElements, "footer") 

End Sub 

Private Function BuildElements(tableElements As ElementList, type As String) As PdfPTable 

     Dim holderTable As New PdfPTable({1}) 
     holderTable.HorizontalAlignment = Element.ALIGN_LEFT 

     Dim holderCell As New PdfPCell() 
     holderCell.Padding = 0 
     holderCell.UseBorderPadding = False 
     holderCell.Border = 0 

     If type = "header" Then 
      If Not String.IsNullOrEmpty(HeaderHTML) Then 

       For Each el As IElement In tableElements 
        holderCell.AddElement(el) 
       Next 

       Dim holderRow As New PdfPRow({holderCell}) 
       holderTable.Rows.Add(holderRow) 

      End If 
     End If 

     If type = "footer" Then 
      If Not String.IsNullOrEmpty(FooterHTML) Then 

       For Each el As IElement In tableElements 
        holderCell.AddElement(el) 
       Next 

       Dim holderRow As New PdfPRow({holderCell}) 
       holderTable.Rows.Add(holderRow) 

      End If 
     End If 
     holderTable.WidthPercentage = 100 

     Return holderTable 
    End Function 

Eine Debug-Schritt durch die headerElements nach ParseXHTML zeigt:

1 Table (correct) 
1 Row (correct) 
2 Cells (correct) 
Cell[0] Empty (not correct, there should be an image Element in here, parsed from an <img src="data:image/png;base64,xxxxxx... html element 
Cell[1] Contains composite text elements (correct) 

Mein OnEndPage Ereignis wie folgt aussieht:

Public Overrides Sub OnEndPage(ByVal writer As PdfWriter, ByVal document As Document) 
     'MyBase.OnEndPage(writer, document) 
     Dim pageSize As Rectangle = document.PageSize 

     Dim tagProcessors As DefaultTagProcessorFactory = CType(Tags.GetHtmlTagProcessorFactory(), DefaultTagProcessorFactory) 
     tagProcessors.RemoveProcessor(HTML.Tag.IMG) ' remove the default processor 
     tagProcessors.AddProcessor(HTML.Tag.IMG, New CustomImageTagProcessor()) ' use our new processor 

     Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(Nothing) 
     htmlContext.SetAcceptUnknown(True) 
     htmlContext.SetTagFactory(tagProcessors) 



     Dim FinalMarginTop, FinalMarginBottom As Single 
     FinalMarginTop = Me.MarginTop 
     FinalMarginBottom = Me.MarginBottom 

     document.SetMargins(MarginLeft, MarginRight, MarginTop, MarginBottom) 

     If Me.UsesHeader Or Me.UsesFooter Then 
      Dim under As PdfContentByte = writer.DirectContent 
      Dim ct As New ColumnText(writer.DirectContent) 

      If Me.UsesHeader Then 
       'Create the header rectangle 
       Dim headerRect As New Rectangle(0, document.PageSize.Height, document.PageSize.Width, CalculatedHeaderHeight) 

       headerRect.Left += MarginLeft 
       headerRect.Right -= MarginRight ' document.RightMargin 
       headerRect.Top += MarginTop ' document.TopMargin 
       headerRect.Bottom -= MarginBottom ' document.BottomMargin 

       If HeaderType = EnumHeaderDisplayType.FirstPageOnly Then 
        If writer.PageNumber = 1 Then 
         ct.SetSimpleColumn(headerRect) 
         ct.AddElement(headerTable) 
         ct.Go() 

         FinalMarginTop = MarginTop 
        End If 
       Else 
        ct.SetSimpleColumn(headerRect) 
        ct.AddElement(headerTable) 
        ct.Go() 

        FinalMarginTop = CalculatedHeaderHeight + MarginTop 
       End If 
      End If 

      If Me.UsesFooter Then 
       Dim footerRect As New Rectangle(0, 0, pageSize.Width, CalculatedFooterHeight) 
       footerRect.BorderWidth = 0 
       footerRect.Left += document.LeftMargin 
       footerRect.Right -= document.RightMargin 
       footerRect.Top += CalculatedFooterHeight 
       footerRect.Bottom += document.BottomMargin 
       ct.SetSimpleColumn(footerRect) 
       ct.AddElement(footerTable) 
       ct.Go() 

       FinalMarginBottom = CalculatedFooterHeight + MarginBottom 
      End If 

     End If 


    End Sub 

Deshalb denke ich, dass der Prozessor Benutzerdefinierte Image-Tag braucht in diesem Stadium angewendet werden , aber ich kann nicht sehen, wo in OnEndPage ich es verwenden kann.

Antwort

0

Also habe ich die Antwort darauf gefunden. Die Pipelineverarbeitung für das Hauptdokument galt nicht für die Verfasser, die die Kopf- und Fußzeilen erstellten.

Ich musste die Tagprozessoren, CSSResolver, Schriftarten und Pipelines innerhalb der PAGEEVENT ebenso einrichten. Sobald dies geschehen war, wurden die Bilder verarbeitet und Bytes der bearbeiteten Bilder wurden auf dem Hauptdokument auf jedem pageevent angewendet (oder Seite)

so meinen Code

wurde
If Me.UsesHeader Then 
      headerElements = New ElementList() 'XMLWorkerHelper.ParseToElementList(Me.HeaderHTML, Nothing) 
      headerTable = SetTable(headerElements, Me.HeaderHTML) 
      CalculatedHeaderHeight = headerTable.Rows(0).MaxHeights 
     End If 

     If Me.UsesFooter Then 
      footerElements = New ElementList() 'XMLWorkerHelper.ParseToElementList(Me.HeaderHTML, Nothing) 
      footerTable = SetTable(footerElements, Me.FooterHTML) 
      CalculatedFooterHeight = footerTable.Rows(0).MaxHeights 
     End If 

wo footerElements und headerElements vom Typ sind ElementList und die SetTable Funktion ist:

Public Function SetTable(ByVal elements As ElementList, ByVal htmlcode As String) As PdfPTable 

     Dim tagProcessors As DefaultTagProcessorFactory = CType(Tags.GetHtmlTagProcessorFactory(), DefaultTagProcessorFactory) 
     tagProcessors.RemoveProcessor(HTML.Tag.IMG) ' remove the default processor 
     tagProcessors.AddProcessor(HTML.Tag.IMG, New CustomImageTagProcessor()) ' use our new processor 

     Dim cssResolver As ICSSResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(True) 
     cssResolver.AddCssFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "assets/css/pdf.css"), True) 

     'Setup Fonts 
     Dim xmlFontProvider As XMLWorkerFontProvider = New XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS) 
     xmlFontProvider.RegisterDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "assets/fonts/")) 

     Dim cssAppliers As CssAppliers = New CssAppliersImpl(xmlFontProvider) 

     Dim htmlContext As HtmlPipelineContext = New HtmlPipelineContext(cssAppliers) 
     htmlContext.SetAcceptUnknown(True) 
     htmlContext.SetTagFactory(tagProcessors) 

     Dim pdf As ElementHandlerPipeline = New ElementHandlerPipeline(elements, Nothing) 
     Dim htmlp As HtmlPipeline = New HtmlPipeline(htmlContext, pdf) 
     Dim css As CssResolverPipeline = New CssResolverPipeline(cssResolver, htmlp) 

     Dim worker As XMLWorker = New XMLWorker(css, True) 
     Dim p As XMLParser = New XMLParser(worker) 

     'Dim holderTable As New PdfPTable({1}) 
     Dim holderTable As PdfPTable = New PdfPTable({1}) 

     holderTable.HorizontalAlignment = Element.ALIGN_LEFT 

     Dim holderCell As New PdfPCell() 
     holderCell.Padding = 0 
     holderCell.UseBorderPadding = False 
     holderCell.Border = 0 

     p.Parse(New MemoryStream(System.Text.Encoding.ASCII.GetBytes(htmlcode))) 

     For Each el As IElement In elements 
      holderCell.AddElement(el) 
     Next 

     Dim holderRow As New PdfPRow({holderCell}) 
     holderTable.Rows.Add(holderRow) 
     holderTable.WidthPercentage = 100 

     Return holderTable 

    End Function 

und das mein Problem gelöst