【问题标题】:Using itextsharp xmlworker to convert html to pdf and write text vertically使用itextsharp xmlworker 将html转换为pdf并垂直写入文本
【发布时间】:2016-07-10 20:37:56
【问题描述】:

xmlworker中是否可以实现自下而上的书写方向?我想在表中使用它。 我的代码是

     <table border=1>
     <tr>
     <td style="padding-right:18px">
          <p style="writing-mode:sideways-lr;text-align:center">First</p</td>
     <td style="padding-right:18px">
          <p style="writing-mode:sideways-lr;text-align:center">Second</p></td></tr>
     <tr><td><p style="text-align:center">1</p>  </td>
         <td><p style="text-align:center">2</p></td> 
     </tr>
        </table>

但是从 html 转换为 pdf 后它不起作用。文本 FIRST 和 SECOND 的方向不是自下而上。

【问题讨论】:

  • 您需要编写自定义代码来执行此操作。如果您添加您期望的HTMLsample,那么有人可能能够提供帮助...

标签: c# html asp.net itextsharp xmlworker


【解决方案1】:
public void addHtmlToPdf(Document document, PdfWriter writer, String html) {
    PdfPTable table = new PdfPTable(1);
    PdfPCell cell = new PdfPCell();
    ElementList list = XMLWorkerHelper.ParseToElementList(html, null);
    foreach(IElement element in list) {
        cell.AddElement(element);
    }
    table.AddCell(cell);
    document.Add(table);
}

utf8 的替代方案:

public void addHtmlToPdf_Utf8(Document document, PdfWriter writer, String html) 
{
    XMLWorkerHelper xml = XMLWorkerHelper.GetInstance();
    xml.ParseXHtml(writer, document, stringToStream(html), System.Text.Encoding.UTF8);
}
public Stream stringToStream(string txt) {
    var stream = new MemoryStream();
    var w = new StreamWriter(stream);
    w.Write(txt);
    w.Flush();
    stream.Position = 0;
    return stream;
}

【讨论】:

    【解决方案2】:

    这是一个非常有趣的问题,所以对该问题 +1。

    第一步是查找 iTextSharp XML Worker 是否支持 HTML td 标签。映射可以在iTextSharp.tool.xml.html.Tags 的源代码中找到。在那里你会发现td 映射到iTextSharp.tool.xml.html.table.TableData,这使得实现自定义标签处理器的工作更容易一些。 IE。我们需要做的就是从类继承并覆盖End()

    public class TableDataProcessor : TableData
    {
        /*
         * a **very** simple implementation of the CSS writing-mode property:
         * https://developer.mozilla.org/en-US/docs/Web/CSS/writing-mode
         */
        bool HasWritingMode(IDictionary<string, string> attributeMap)
        {
            bool hasStyle = attributeMap.ContainsKey("style");
            return hasStyle
                    && attributeMap["style"].Split(new char[] { ';' })
                    .Where(x => x.StartsWith("writing-mode:"))
                    .Count() > 0
                ? true : false;
        }
    
        public override IList<IElement> End(
            IWorkerContext ctx,
            Tag tag,
            IList<IElement> currentContent)
        {
            var cells = base.End(ctx, tag, currentContent);
            var attributeMap = tag.Attributes;
            if (HasWritingMode(attributeMap))
            {
                var pdfPCell = (PdfPCell) cells[0];
                // **always** 'sideways-lr'
                pdfPCell.Rotation = 90;
            }
            return cells;
        }
    }
    

    正如内联 cmets 中所述,这是一个非常简单的实现,可满足您的特定需求。您需要添加额外的逻辑来支持任何其他 writing-mode CSS property value,并包括任何健全性检查。

    更新

    根据@Daniel留下的评论,不清楚HTML转换成PDF时如何添加自定义CSS。首先是更新后的 HTML:

    string XHTML = @"
    <h1>Table with Vertical Text</h1>
    <table><tr>
    <td style='writing-mode:sideways-lr;text-align:center;width:40px;'>First</td>
    <td style='writing-mode:sideways-lr;text-align:center;width:40px;'>Second</td></tr>
    <tr><td style='text-align:center'>1</td>
    <td style='text-align:center'>2</td></tr></table>
    
    <h1>Table <u>without</u> Vertical Text</h1>
    <table width='50%'>
    <tr><td class='light-yellow'>0</td></tr>
    <tr><td>1</td></tr>
    <tr><td class='light-yellow'>2</td></tr>
    <tr><td>3</td></tr>
    </table>";
    

    然后是自定义 CSS 的小 sn-p:

    string CSS = @"
        body {font-size: 12px;}
        table {border-collapse:collapse; margin:8px;}
        .light-yellow {background-color:#ffff99;}
        td {border:1px solid #ccc;padding:4px;}
    ";
    

    稍微困难的部分是额外的设置 - 您不能使用在 SO 上常见的开箱即用的简单 XMLWorkerHelper.GetInstance().ParseXHtml()。这是一个简单的帮助方法,可以帮助您入门:

    public void ConvertHtmlToPdf(string xHtml, string css)
    {
        using (var stream = new FileStream(OUTPUT_FILE, FileMode.Create))
        {
            using (var document = new Document())
            {
                var writer = PdfWriter.GetInstance(document, stream);
                document.Open();
    
                // instantiate custom tag processor and add to `HtmlPipelineContext`.
                var tagProcessorFactory = Tags.GetHtmlTagProcessorFactory();
                tagProcessorFactory.AddProcessor(
                    new TableDataProcessor(), 
                    new string[] { HTML.Tag.TD }
                );
                var htmlPipelineContext = new HtmlPipelineContext(null);
                htmlPipelineContext.SetTagFactory(tagProcessorFactory);
    
                var pdfWriterPipeline = new PdfWriterPipeline(document, writer);
                var htmlPipeline = new HtmlPipeline(htmlPipelineContext, pdfWriterPipeline);
    
                // get an ICssResolver and add the custom CSS
                var cssResolver = XMLWorkerHelper.GetInstance().GetDefaultCssResolver(true);
                cssResolver.AddCss(css, "utf-8", true);
                var cssResolverPipeline = new CssResolverPipeline(
                    cssResolver, htmlPipeline
                );
    
                var worker = new XMLWorker(cssResolverPipeline, true);
                var parser = new XMLParser(worker);
                using (var stringReader = new StringReader(xHtml))
                {
                    parser.Parse(stringReader);
                }
            }
        }
    }
    

    see the documentation(iText 删除了文档,链接到 Wayback Machine)而不是重新解释上面的示例代码,以便更好地了解为什么需要以这种方式设置解析器。

    另请注意:

    1. XML Worker 支持所有 CSS2/CSS3 属性,因此您可能需要试验哪些方法有效,哪些方法无效,以了解您希望PDF 查看浏览器中显示的 HTML。
    2. HTML sn-p 删除了p 标签,因为样式可以直接应用于td 标签。
    3. 内联width 属性。如果省略,列将是可变宽度,与文本已水平呈现时匹配。

    使用 iTextSharp 和 XML Worker 版本 5.5.9 测试这是 更新的结果:

    【讨论】:

    • 非常感谢。这很有帮助。在我的情况下,html文件很大。有很多表,但只有两个表需要垂直文本我想知道如何在我自己的 css 的其余部分中实现你的代码。我以前这样做过:using (var myCss = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_css))) { using (var msHtml = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(example_html))) { iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, doc, msHtml, myCss ); } }
    • @Daniel - 更新了答案以包含一个帮助方法,该方法允许您传递 HTML 字符串和 CSS 字符串。
    • @kuujinbo 我正在尝试你的方法,但这是未定义的“new TableDataProcessor()”,文档链接也不起作用
    • @kuujinbo 最近一次更新大约在 2 年前。如果能再更新就太好了
    • @Selman - 更新了超链接。 TableDataProcessor 代码示例的一部分,所以你需要将它包含在你正在做的任何事情中。话虽如此,我已经 很长时间 没有使用过 iText,但我知道他们推荐使用版本 7。
    猜你喜欢
    • 2013-06-28
    • 2013-09-24
    • 2022-03-07
    • 2011-05-22
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    • 2018-02-15
    • 2013-01-26
    相关资源
    最近更新 更多