【问题标题】:iTextSharp XMLWorker parsing really slowiTextSharp XMLWorker 解析真的很慢
【发布时间】:2014-01-22 06:31:48
【问题描述】:

我正在使用以下代码在我的 WPF 应用程序中使用 iTextSharp XMLWorker 解析 HTML 字符串:

var css = "";
using (var htmlMS = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(html)))
{                    
    //Create a stream to read our CSS
    using (var cssMS = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(css)))
    {                        
        //Get an instance of the generic XMLWorker
        var xmlWorker = XMLWorkerHelper.GetInstance();

        //Parse our HTML using everything setup above
        xmlWorker.ParseXHtml(writer, doc, htmlMS, cssMS, System.Text.Encoding.UTF8, fontProv);                        
    }
}

解析工作正常,但速度很慢,解析 HTML 大约需要 2 秒。因此,对于 50 页的 pdf,大约需要 2 分钟。我在我的 HTML 字符串中使用内联样式。这是自然行为还是可以优化?

【问题讨论】:

  • 你的 HTML 嵌套很深吗?例如,所有东西都包裹在一个巨大的 DIV 中吗?在这些情况下,解析器(甚至常规桌面浏览器)必须一直到文档末尾才能呈现第一件事。你在用桌子吗? PDF 没有表格的概念,因此 iText 必须模拟它们,如果它们很长,则计算成本会很高。你在使用图像吗?如果是这样,iText 必须加载/下载图像(取决于它们的引用方式),这也需要时间。
  • 我还没有答案,但我也看到这个库有多慢。大部分时间都被 ParseXHtml 内部的以下方法消耗掉了:iTextSharp.text.FontFactoryImp.RegisterDirectories
  • 我发现只有在调试模式下运行我的应用程序时,XMLWorkerHelper 实例才超级慢。
  • 另见 Java iText 问题 - stackoverflow.com/q/15621218/179972

标签: c# itextsharp


【解决方案1】:

这个问题是错误的,因为它表明 HTML 解析正在减慢一切。这不是真的。瓶颈甚至在 HTML 的第一个 sn-p 被解析之前就出现了。

您正在使用最基本的几行代码从 HTML 创建 PDF,如 ParseHtml 示例所示:

public void createPdf(String file) throws IOException, DocumentException {
    // step 1
    Document document = new Document();
    // step 2
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
    // step 3
    document.open();
    // step 4
    XMLWorkerHelper.getInstance().parseXHtml(writer, document,
            new FileInputStream(HTML));
    // step 5
    document.close();
}

此代码很简单,但它在内部执行了很多操作,如另一个问题的 cmets 中所述:XMLWorkerHelper performance slow

注册字体目录的行为会消耗大量时间。您可以通过使用您自己的FontProvider 来避免这种情况,就像在ParseHtmlFonts 示例中所做的那样。

public void createPdf(String file) throws IOException, DocumentException {
    // step 1
    Document document = new Document();

    // step 2
    PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(file));
    writer.setInitialLeading(12.5f);

    // step 3
    document.open();

    // step 4

    // CSS
    CSSResolver cssResolver = new StyleAttrCSSResolver();
    CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream(CSS));
    cssResolver.addCss(cssFile);

    // HTML
    XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
    fontProvider.register("resources/fonts/Cardo-Regular.ttf");
    fontProvider.register("resources/fonts/Cardo-Bold.ttf");
    fontProvider.register("resources/fonts/Cardo-Italic.ttf");
    fontProvider.addFontSubstitute("lowagie", "cardo");
    CssAppliers cssAppliers = new CssAppliersImpl(fontProvider);
    HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers);
    htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

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

    // XML Worker
    XMLWorker worker = new XMLWorker(css, true);
    XMLParser p = new XMLParser(worker);
    p.parse(new FileInputStream(HTML));

    // step 5
    document.close();
}

在这种情况下,我们指示 iText DONTLOOKFORFONTS,从而节省大量时间。我们不是让 iText 寻找字体,而是告诉 iText 我们将在 HTML 中使用哪些字体。

【讨论】:

  • 感谢您从源头提供明确的答案 - 我将开始相应地扩展我的代码库。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-05-25
  • 2015-05-31
  • 2012-05-17
  • 1970-01-01
  • 2017-11-10
  • 2010-12-28
  • 2013-01-25
相关资源
最近更新 更多