【问题标题】:iTextsharp base64 embedded image in header not parsing/showing标题中的 iTextsharp base64 嵌入图像未解析/显示
【发布时间】:2016-06-29 07:55:46
【问题描述】:

背景:

我有一个编辑器,可以在其中编辑 HTML 文档的页眉和页脚,然后将它们合并到主文档中。 Base64 嵌入图像在主文档内容中完美运行,但在页眉或页脚中它们消失了(因此,如果我有一个带有 image1.png 的主文档,并且该文档有一个带有 image_header.png 的页眉,则将显示 image1,image_header惯于)。在我看来,标签处理器并未应用于 PageHeader html 中的元素。

我创建了一个自定义 ImageTagProcessor(下)

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

并通过主 PDF 生成器库中的以下代码连接

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)

在我的 HeaderFooter 类(继承自 PdfPageEventHelper)中,该类的新实例实例化为:

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

ParseXHTML 显示后 headerElements 的调试步骤

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)

我的OnEndPage 活动看起来像:

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

所以我认为在这个阶段需要应用自定义图像标签处理器,但我看不到在 OnEndPage 的哪个位置可以使用它。

【问题讨论】:

    标签: vb.net base64 pdf-generation itext html-to-pdf


    【解决方案1】:

    所以我想出了这个问题的答案。主文档的管道处理不适用于构建页眉和页脚的作者。

    我还必须在 pageevent 中设置标签处理器、cssresolver、字体和管道。完成此操作后,图像被处理,处理后图像的字节被应用到每个 pageevent(或 pageend)上的主文档

    所以我的代码变成了

    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
    

    其中footerElementsheaderElements 的类型为ElementList SetTable 函数是:

    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
    

    这解决了我的问题

    【讨论】:

      猜你喜欢
      • 2012-02-08
      • 2022-07-26
      • 2015-02-08
      • 2012-03-25
      • 1970-01-01
      • 2019-06-25
      • 2013-01-31
      • 2020-02-04
      • 2010-11-15
      相关资源
      最近更新 更多