使用iText库将html转换为pdf时未应用hr的内联CSS

Vis*_*kar 9 html android itext xmlworker

我正在使用Itext库为android将html转换为pdf,这是正常工作但在某些事情它没有正确解析.我想创建一个红色的虚线分隔符,但它总是给我一个深灰色的实线分隔符.

我的html标签是

<hr noshade style="border: 0; width:100%;border-bottom-width: 1px; border-bottom-style: dotted; border-bottom-color: red">
Run Code Online (Sandbox Code Playgroud)

我的转换代码

        Document document = new Document(PageSize.A4);

        //this sets the margin to the created pdf
        document.setMargins(35, 35, 150, 100);

        PdfWriter writer = PdfWriter.getInstance(document,
                new FileOutputStream(fileWithinMyDir));
        if (isPrescription) {
            HeaderFooterPageEvent event = new HeaderFooterPageEvent();
            writer.setPageEvent(event);
        } else {
            CertificateFooterPageEvent event = new CertificateFooterPageEvent();
            writer.setPageEvent(event);
        }
        document.open();
        HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
        htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());
        htmlContext.setImageProvider(new AbstractImageProvider() {
            public String getImageRootPath() {

                Uri uri = Uri.parse("file:///android_asset/");

                return uri.toString();
            }
        });


        CSSResolver cssResolver =
                XMLWorkerHelper.getInstance().getDefaultCssResolver(false);

        // Pipelines
        PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer);
        HtmlPipeline html = new HtmlPipeline(htmlContext, pdf);
        CssResolverPipeline css = new CssResolverPipeline(cssResolver, html);

        XMLWorker worker = new XMLWorker(css, true);

        XMLParser p = new XMLParser(worker);
        InputStream is = new ByteArrayInputStream(htmlString.getBytes());
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, is);
        p.parse(is);

        document.close();
Run Code Online (Sandbox Code Playgroud)

kuu*_*nbo 5

我是.NET开发人员,所以代码在C#中。但是您应该能够轻松翻译以下内容。

iText是PDF优先的库,并且[X]HTML解析非常复杂,因此在这方面还不完整。每当解析[X]HTML并且事情没有按照您期望的方式进行时,您应该遵循的基本步骤是:

  1. 验证是否XML Worker支持标签:标签类
  2. 如果支持该标记在这种情况下为true),请查看默认实现。在这里,它由Horizo​​ntalRule类处理。但是,我们看到您的用例不支持,因此一种解决方法是将该代码用作蓝图。(如下所示),您也可以从特定的标记类继承并覆盖End()方法,如此处所示。无论哪种方式,您要做的就是实现自定义标签处理器。
  3. 如果支持该标记,则需要通过继承AbstractTagProcessor来滚动自己的自定义标记处理器。

无论如何,这是一个简单的示例,可以帮助您入门。首先,自定义标签处理器:

public class CustomHorizontalRule : AbstractTagProcessor
{
    public override IList<IElement> Start(IWorkerContext ctx, Tag tag)
    {
        IList<IElement> result;
        LineSeparator lineSeparator;
        var cssUtil = CssUtils.GetInstance();

        try
        {
            IList<IElement> list = new List<IElement>();
            HtmlPipelineContext htmlPipelineContext = this.GetHtmlPipelineContext(ctx);

            Paragraph paragraph = new Paragraph();
            IDictionary<string, string> css = tag.CSS;
            float baseValue = 12f;
            if (css.ContainsKey("font-size"))
            {
                baseValue = cssUtil.ParsePxInCmMmPcToPt(css["font-size"]);
            }
            string text;
            css.TryGetValue("margin-top", out text);
            if (text == null) text = "0.5em";

            string text2;
            css.TryGetValue("margin-bottom", out text2);
            if (text2 == null) text2 = "0.5em";

            string border;
            css.TryGetValue(CSS.Property.BORDER_BOTTOM_STYLE, out border);
            lineSeparator = border != null && border == "dotted"
                ? new DottedLineSeparator()
                : new LineSeparator();

            var element = (LineSeparator)this.GetCssAppliers().Apply(
                lineSeparator, tag, htmlPipelineContext
            );

            string color;
            css.TryGetValue(CSS.Property.BORDER_BOTTOM_COLOR, out color);
            if (color != null)
            {
                // WebColors deprecated, but docs don't state replacement
                element.LineColor = WebColors.GetRGBColor(color);
            }

            paragraph.SpacingBefore += cssUtil.ParseValueToPt(text, baseValue);
            paragraph.SpacingAfter += cssUtil.ParseValueToPt(text2, baseValue);
            paragraph.Leading = 0f;
            paragraph.Add(element);
            list.Add(paragraph);
            result = list;
        }
        catch (NoCustomContextException cause)
        {
            throw new RuntimeWorkerException(
                LocaleMessages.GetInstance().GetMessage("customcontext.404"),
                cause
            );
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

大部分代码直接取自现有资源,但检查CSS.Property.BORDER_BOTTOM_STYLECSS.Property.BORDER_BOTTOM_COLOR设置边框样式和颜色(如果它们插入<hr> style属性中的话)除外。

然后,将上面的定制标记处理器添加到XML Worker TagProcessorFactory

using (var stream = new FileStream(OUTPUT_FILE, FileMode.Create))
{
    using (var document = new Document())
    {
        var writer = PdfWriter.GetInstance(document, stream);
        document.Open();

        var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
        // custom tag processor above
        tagProcessorFactory.AddProcessor(
            new CustomHorizontalRule(),
            new string[] { HTML.Tag.HR }
        );
        var htmlPipelineContext = new HtmlPipelineContext(null);
        htmlPipelineContext.SetTagFactory(tagProcessorFactory);

        var pdfWriterPipeline = new PdfWriterPipeline(document, writer);
        var htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline);
        var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);
        var cssResolverPipeline = new CssResolverPipeline(
            cssResolver, htmlPipeline
        );

        var worker = new XMLWorker(cssResolverPipeline, true);
        var parser = new XMLParser(worker);
        var xHtml = "<hr style='border:1px dotted red' />";
        using (var stringReader = new StringReader(xHtml))
        {
            parser.Parse(stringReader);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

需要注意的一件事是,即使我们使用速记border内联样式,iText的CSS解析器似乎也可以在内部设置所有样式。即,您可以使用四种常用样式中的任何一种进行检查-我刚好使用了CSS.Property.BORDER_BOTTOM_STYLECSS.Property.BORDER_BOTTOM_COLOR

生成的PDF:

在此处输入图片说明