如何向页面添加HTML页眉和页脚?

3
如何使用iText从html源添加标题到pdf?
目前,我们已经扩展了PdfPageEventHelper并重写了这些方法。虽然工作正常,但在达到2页或更多页时会抛出RuntimeWorkerException异常。
 @Override
    void onStartPage(PdfWriter writer, Document document) {
        InputStream is = new ByteArrayInputStream(header?.getBytes());
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, is);
    }

    @Override
    void onEndPage(PdfWriter writer, Document document) {
        InputStream is = new ByteArrayInputStream(footer?.getBytes());
        XMLWorkerHelper.getInstance().parseXHtml(writer, document, is);

    }
2个回答

4
通常情况下,在onStartPage()事件中添加内容是禁止的。在onEndPage()中,向document对象添加内容也是禁止的。你应该使用PdfWriteronEndPage()方法中添加页眉和页脚,而不是使用document对象。此外:重复解析HTML会浪费大量的CPU资源。
请查看HtmlHeaderFooter示例。
它包含两个HTML片段,一个用于页眉,另一个用于页脚。
public static final String HEADER =
    "<table width=\"100%\" border=\"0\"><tr><td>Header</td><td align=\"right\">Some title</td></tr></table>";
public static final String FOOTER =
    "<table width=\"100%\" border=\"0\"><tr><td>Footer</td><td align=\"right\">Some title</td></tr></table>";

请注意,描述页眉和页脚的更好方法不是使用HTML,但也许这是您的要求之一,所以我不会问您为什么不使用在官方文档中解释的任何方法。顺便说一下:您需要解决问题的所有信息也可以在那个免费电子书中找到,所以您可能想要下载它...
我们将在页面事件中仅读取这些HTML片段一次,然后在每个页面上重复渲染元素。
public class HeaderFooter extends PdfPageEventHelper {
    protected ElementList header;
    protected ElementList footer;
    public HeaderFooter() throws IOException {
        header = XMLWorkerHelper.parseToElementList(HEADER, null);
        footer = XMLWorkerHelper.parseToElementList(FOOTER, null);
    }
    @Override
    public void onEndPage(PdfWriter writer, Document document) {
        try {
            ColumnText ct = new ColumnText(writer.getDirectContent());
            ct.setSimpleColumn(new Rectangle(36, 832, 559, 810));
            for (Element e : header) {
                ct.addElement(e);
            }
            ct.go();
            ct.setSimpleColumn(new Rectangle(36, 10, 559, 32));
            for (Element e : footer) {
                ct.addElement(e);
            }
            ct.go();
        } catch (DocumentException de) {
            throw new ExceptionConverter(de);
        }
    }
}

你看到我们用来添加从XML Worker获取的Element对象的机制了吗?我们创建一个ColumnText对象,它将写入writer直接内容(使用document是禁止的)。我们定义了一个Rectangle并使用go()渲染元素。
结果显示在html_header_footer.pdf中。

嗨,我在解析这个值时遇到了困难:<table width="100%" border="0"><tr><td><span class="bold">页脚</span></td><td align="right">某个标题</td></tr></table> 有什么帮助吗? - Narayan Subedi
@Prabhat 发布一个问题,解释一下你遇到的困难。请勿使用评论来提问或回答新问题。 - Bruno Lowagie
Bruno,我在stackoverflow上发布了一个问题http://stackoverflow.com/questions/37767027/html-string-is-not-parsed-with-itext-xml-parser,我卡在这里了,请你帮忙回答一下。谢谢。 - Narayan Subedi
我在编写以下代码时遇到了错误:“ColumnText ct = new ColumnText(writer.getDirectContent());”,其中在“writer.”后面我没有找到“getDirectContent”。 - chirag
@chirag,你决定不升级到iText 7,而是坚持使用iText 5。你能详细说明一下为什么选择使用一个不再受支持的版本吗?“不再受支持”的概念意味着关于该版本的问题将不再得到回答,除非你是付费客户。你是付费客户吗? - Bruno Lowagie

4

Bruno的答案是正确的,但对我来说并没有完全奏效,因为XMLWorkerHelper.parsetoElementsList无法解析一些系统字体。另一方面,XMLWorkerHelper.getInstance().parseXHtml(writer, document, is)能够正确解析系统字体,因此我不得不采用元素处理程序的方法,在这里运行良好。以下是C#代码:

    /// <summary>
    /// returns pdf in bytes.
    /// </summary>
    /// <param name="contentsHtml">contents.</param>
    /// <param name="headerHtml">header contents.</param>
    /// <param name="footerHtml">footer contents.</param>
    /// <returns></returns>
    public Byte[] GetPDF(string contentsHtml, string headerHtml, string footerHtml)
    {
        // Create a byte array that will eventually hold our final PDF
        Byte[] bytes;

        // Boilerplate iTextSharp setup here

        // Create a stream that we can write to, in this case a MemoryStream
        using (var ms = new MemoryStream())
        {
            // Create an iTextSharp Document which is an abstraction of a PDF but **NOT** a PDF
            using (var document = new Document(PageSize.A4, 40, 40, 120, 120))
            {
                // Create a writer that's bound to our PDF abstraction and our stream
                using (var writer = PdfWriter.GetInstance(document, ms))
                {
                    // Open the document for writing
                    document.Open();

                    var headerElements = new HtmlElementHandler();
                    var footerElements = new HtmlElementHandler();

                    XMLWorkerHelper.GetInstance().ParseXHtml(headerElements, new StringReader(headerHtml));

                    XMLWorkerHelper.GetInstance().ParseXHtml(footerElements, new StringReader(footerHtml));

                    writer.PageEvent = new HeaderFooter(headerElements.GetElements(), footerElements.GetElements());

                    // Read your html by database or file here and store it into finalHtml e.g. a string
                    // XMLWorker also reads from a TextReader and not directly from a string
                    using (var srHtml = new StringReader(contentsHtml))
                    {
                        // Parse the HTML
                        iTextSharp.tool.xml.XMLWorkerHelper.GetInstance().ParseXHtml(writer, document, srHtml);
                    }

                    document.Close();
                }
            }

            // After all of the PDF "stuff" above is done and closed but **before** we
            // close the MemoryStream, grab all of the active bytes from the stream
            bytes = ms.ToArray();
        }
        return bytes;
    }
}

页面事件和元素处理器的代码在这里

public partial class HeaderFooter : PdfPageEventHelper
{
    private ElementList HeaderElements { get; set; }
    private ElementList FooterElements { get; set; }

    public HeaderFooter(ElementList headerElements, ElementList footerElements)
    {
        HeaderElements = headerElements;
        FooterElements = footerElements;
    }

    public override void OnEndPage(PdfWriter writer, Document document)
    {
        base.OnEndPage(writer, document);
        try
        {
            ColumnText headerText = new ColumnText(writer.DirectContent);
            foreach (IElement e in HeaderElements)
            {
                headerText.AddElement(e);
            }
            headerText.SetSimpleColumn(document.Left, document.Top, document.Right, document.GetTop(-100), 10, Element.ALIGN_MIDDLE);
            headerText.Go();

            ColumnText footerText = new ColumnText(writer.DirectContent);
            foreach (IElement e in FooterElements)
            {
                footerText.AddElement(e);
            }
            footerText.SetSimpleColumn(document.Left, document.GetBottom(-100), document.Right, document.GetBottom(-40), 10, Element.ALIGN_MIDDLE);
            footerText.Go();
        }
        catch (DocumentException de)
        {
            throw new Exception(de.Message);
        }
    }
}

public class HtmlElementHandler : IElementHandler
{
    public ElementList Elements { get; set; }

    public HtmlElementHandler()
    {
        Elements = new ElementList();
    }

    public ElementList GetElements()
    {
        return Elements;
    }

    public void Add(IWritable w)
    {
        if (w is WritableElement)
        {
            foreach (IElement e in ((WritableElement)w).Elements())
            {
                Elements.Add(e);
            }
        }
    }
}

由于某些原因,我的页眉和页脚都没有显示,但主要内容是显示的。 - Morgs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接