2

In my application I've to generate a report from the html content. For this purpose I am using the iTextPDF library 5.5.0 with XMLWorker 5.5.0. End user can design the content of report (Header, Footer, Subject) using tinyMC editor. I am storing those HTML content in DB. Please note this HTML content may include images, tables or any thing that tinyMC allows. Now when user tries to generate the report, I am fetching the data from the database and tried to generate the header and footer from HTML using code given below.

       /**
         * Adds the header and the footer.
         * @see com.itextpdf.text.pdf.PdfPageEventHelper#onEndPage(
         *      com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document)
         */
        public void onEndPage(PdfWriter writer, Document document) {
            Phrase footerPhrase = new Phrase();

            DBFooter = "<table width='200 border='1' cellpadding='1' cellspacing='1'><tbody><tr><td>content1</td><td>content2</td></tr><tr><td>&nbsp;</td><td>&nbsp;</td>
            </tr><tr><td>jhvhjvh</td><td><img src='D:\DemoApp\images\User1.png' width='48' height='48' alt='' /></td></tr></tbody></table>
            <p style='text-align: center;'>This is the footer</p>"

            CSSResolver cssResolver = new StyleAttrCSSResolver();
            CssFile cssFile = XMLWorkerHelper.getCSS(new ByteArrayInputStream(CSS.getBytes()));
            cssResolver.addCss(cssFile);

            // HTML
            HtmlPipelineContext htmlContext = new HtmlPipelineContext(null);
            htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory());

            // Pipelines
            ElementList elements = new ElementList();
            ElementHandlerPipeline pdf = new ElementHandlerPipeline(elements, null);
            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);
            try {
                p.parse(new ByteArrayInputStream(DBFooter.toString().getBytes()));
            } catch (IOException e) {
            }
            footerPhrase.addAll(elements);

            Rectangle rect = writer.getBoxSize("art");
            switch (writer.getPageNumber() % 2) {
            case 0:
                ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_RIGHT, header[0], rect.getRight(),
                                           rect.getTop(), 0);
                break;
            case 1:
                ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_LEFT, header[1], rect.getLeft(),
                                           rect.getTop(), 0);
                break;
            }

            ColumnText.showTextAligned(writer.getDirectContent(), Element.ALIGN_CENTER, footerPhrase,
                                       (rect.getLeft() + rect.getRight()) / 2, rect.getBottom() - 50, 0);
        }

I've followed this link to add header footer. And changed the onEndPage function as above.

Problem is the above code only prints the "This is the footer" from the content of footer. It's not showing the table. How can I bring the HTML content in Header / Footer.

Please note that I can show html content in report body (including table / images etc.) but not in header / footer.

IT ppl
  • 2,626
  • 1
  • 39
  • 56
  • You are using the `showTextAligned()` method which is a method that can be used to add *a single line*. I hope you agree that a table is not *a single line*. Please read my answers to the questions [How to fit a String inside a rectangle?](http://stackoverflow.com/questions/13526043/) and [ColumnText ignores alignment](http://stackoverflow.com/questions/18142623/itext-columntext-ignores-alignment) These questions are part of [The Best iText Questions on StackOverflow](http://pages.itextpdf.com/ebook-stackoverflow-questions.html) – Bruno Lowagie Feb 02 '15 at 12:32
  • Bruno, I tried to SOP the footerPhrase but it gives me only one line as following. System.out.println(footerPhrase.toString()); and output was [com.itextpdf.text.pdf.PdfPTable@54655133, This is the footer] – IT ppl Feb 02 '15 at 12:42
  • What is SOP? Also: don't use code in a comment. Don't put a `PdfPTable` in a `Phrase` (it's not done). Please start by reading some of the answers in my book (you couldn't have done that in only 10 minutes, so don't tell me you've tried following my advice; that can't be true). – Bruno Lowagie Feb 02 '15 at 12:44
  • I am not putting pdfPTable in Pharse, I am having an html table stored in Database. This would be dynamic content as user will design the header/footer using ckeditor / TinyMCE. so each time I need to bring the content from db and generate the report dynamically. so the content might contain image, table and text as well. – IT ppl Feb 02 '15 at 12:47
  • 1
    You are lying. Assuming that `footerPhrase` is a `Phrase` and `footerPhrase.toString()` returns [com.itextpdf.text.pdf.PdfPTable@54655133, This is the footer], then you **are** putting a `PdfPTable` in a `Phrase`. I do not help liars. As far as I am concerned, this conversation is closed. – Bruno Lowagie Feb 02 '15 at 12:53
  • Bruno, I am not lying. my data contains a dynamic content and the footerPhrase is filled with XMLWorker. It is showing the .PdfPTable because my content are in html table format. it may differ from user to user. I would like to assure that I'vent added pdfPTable explicitly. I am trying to put the content from XMLworker to the phrase. Sorry for the inconvenience as I am newbie to iTextPDF. Thanks for your advices. I will read your book referenced here. Thanks a lot again. – IT ppl Feb 02 '15 at 12:59
  • So you *are* adding a `PdfPTable` to a `Phrase`! What I am trying to explain to you by referring to different questions that have already been answered is that you shouldn't use a `Phrase` (nor `showTextAligned()` for that matter). Instead you should use `ColumnText` in *composite mode* as explained in the answers to the questions you were referred to. – Bruno Lowagie Feb 02 '15 at 13:14

1 Answers1

0

Managed to add html header and footer in C# using page events and elements handler of itext sharp xml worker

    /// <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;
    }
}

page events and elements handler code is here

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);
            }
        }
    }
}
dicodino
  • 121
  • 4