0

Creating a PDF document from the stream of a HTTP request.

public class HomeController : Controller {
    public HomeController() {
        converter = new HtmlToPdf();
        InitializeConverter();
    }

    public void Index() {
        ConvertHtmlToPdf(new Uri("http://localhost:52328/CertificateOfOrigin?noCertificate=2691"));
    }

    public void ConvertHtmlToPdf(Uri toConvert) {
        if(toConvert == null) throw new ArgumentNullException(nameof(toConvert));
        using(var stream =new MemoryStream()) {
            var doc = converter.ConvertUrl(toConvert.AbsoluteUri);
            // The doc.AddTemplate returns a PdfTemplate and should be assigned to doc.Footer
            doc.Footer = doc.AddTemplate(doc.Pages[0].ClientRectangle.Width, 100);
            var pageNumbering = new PdfTextElement(20, 50, "Page {page_number} of {total_pages}", doc.Fonts[0], Color.Black);
            // Once template defined, I add it to the doc Footer. But...
            doc.Footer.Add(pageNumbering); // Throws a NullPointerException?
            doc.Footer = template;
            doc.Save(stream);
            doc.Close();

            using(var ms = new MemoryStream(stream.ToArray())) {
                Response.AddHeader("content-disposition", "filename=certificate-of-origin.pdf");
                Response.ContentType = "application/pdf";
                ms.CopyTo(Response.OutputStream);
                Response.End();
                Response.Close();
            }
        }
    }

    private void InitializeConverter() {
        converter.Options.MarginBottom = 0;
        converter.Options.MarginLeft = 0;
        converter.Options.MarginRight = 0;
        converter.Options.MarginTop = 0;
        converter.Options.PdfPageSize = PdfPageSize.Letter;
    }

    private readonly HtmlToPdf converter;
}

I put a breakpoint and quick watched the return of doc.AddTemplate method call and it returns an actual PdfTemplate no problem!

Other than that, everything works fine. Document is generated no problem, except when I uncomment the page numbering because the doc.Footer remains null despite its assignment.

Could it be a bug? Idk.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162

1 Answers1

2

You need to either set the header/footer content before the conversion, like here: https://selectpdf.com/demo-mvc/HtmlToPdfHeadersAndFooters

using System;
using System.Web.Mvc;

namespace SelectPdf.Samples.Controllers
{
    public class HtmlToPdfHeadersAndFootersController : Controller
    {
        // GET: HtmlToPdfHeadersAndFooters
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult SubmitAction(FormCollection collection)
        {
            // get parameters
            string headerUrl = Server.MapPath("~/files/header.html");
            string footerUrl = Server.MapPath("~/files/footer.html");

            bool showHeaderOnFirstPage = collection["ChkHeaderFirstPage"] == "on";
            bool showHeaderOnOddPages = collection["ChkHeaderOddPages"] == "on";
            bool showHeaderOnEvenPages = collection["ChkHeaderEvenPages"] == "on";

            int headerHeight = 50;
            try
            {
                headerHeight = Convert.ToInt32(collection["TxtHeaderHeight"]);
            }
            catch { }

            bool showFooterOnFirstPage = collection["ChkFooterFirstPage"] == "on";
            bool showFooterOnOddPages = collection["ChkFooterOddPages"] == "on";
            bool showFooterOnEvenPages = collection["ChkFooterEvenPages"] == "on"; 

            int footerHeight = 50;
            try
            {
                footerHeight = Convert.ToInt32(collection["TxtFooterHeight"]);
            }
            catch { }

            // instantiate a html to pdf converter object
            HtmlToPdf converter = new HtmlToPdf();

            // header settings
            converter.Options.DisplayHeader = showHeaderOnFirstPage ||
                showHeaderOnOddPages || showHeaderOnEvenPages;
            converter.Header.DisplayOnFirstPage = showHeaderOnFirstPage;
            converter.Header.DisplayOnOddPages = showHeaderOnOddPages;
            converter.Header.DisplayOnEvenPages = showHeaderOnEvenPages;
            converter.Header.Height = headerHeight;

            PdfHtmlSection headerHtml = new PdfHtmlSection(headerUrl);
            headerHtml.AutoFitHeight = HtmlToPdfPageFitMode.AutoFit;
            converter.Header.Add(headerHtml);

            // footer settings
            converter.Options.DisplayFooter = showFooterOnFirstPage ||
                showFooterOnOddPages || showFooterOnEvenPages;
            converter.Footer.DisplayOnFirstPage = showFooterOnFirstPage;
            converter.Footer.DisplayOnOddPages = showFooterOnOddPages;
            converter.Footer.DisplayOnEvenPages = showFooterOnEvenPages;
            converter.Footer.Height = footerHeight;

            PdfHtmlSection footerHtml = new PdfHtmlSection(footerUrl);
            footerHtml.AutoFitHeight = HtmlToPdfPageFitMode.AutoFit;
            converter.Footer.Add(footerHtml);

            // add page numbering element to the footer
            if (collection["ChkPageNumbering"] == "on")
            {
                // page numbers can be added using a PdfTextSection object
                PdfTextSection text = new PdfTextSection(0, 10,
                    "Page: {page_number} of {total_pages}  ",
                    new System.Drawing.Font("Arial", 8));
                text.HorizontalAlign = PdfTextHorizontalAlign.Right;
                converter.Footer.Add(text);
            }

            // create a new pdf document converting an url
            PdfDocument doc = converter.ConvertUrl(collection["TxtUrl"]);

            // custom header on page 3
            if (doc.Pages.Count >= 3)
            {
                PdfPage page = doc.Pages[2];

                PdfTemplate customHeader = doc.AddTemplate(
                    page.PageSize.Width, headerHeight);
                PdfHtmlElement customHtml = new PdfHtmlElement(
                    "<div><b>This is the custom header that will " +
                    "appear only on page 3!</b></div>",
                    string.Empty);
                customHeader.Add(customHtml);

                page.CustomHeader = customHeader;
            }

            // save pdf document
            byte[] pdf = doc.Save();

            // close pdf document
            doc.Close();

            // return resulted pdf document
            FileResult fileResult = new FileContentResult(pdf, "application/pdf");
            fileResult.FileDownloadName = "Document.pdf";
            return fileResult;
        }
    }
}

Or use this approach, to add headers/footers to an already generated pdf: https://selectpdf.com/demo-mvc/ExistingPdfHeadersAndFooters

using System.Web.Mvc;
using System.Drawing;

namespace SelectPdf.Samples.Controllers
{
    public class ExistingPdfHeadersAndFootersController : Controller
    {
        // GET: ExistingPdfHeadersAndFooters
        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult SubmitAction(FormCollection collection)
        {
            // the test file
            string filePdf = Server.MapPath("~/files/selectpdf.pdf");
            string imgFile = Server.MapPath("~/files/logo.png");

            // resize the content
            PdfResizeManager resizer = new PdfResizeManager();
            resizer.Load(filePdf);

            // add extra top and bottom margins
            resizer.PageMargins = new PdfMargins(0, 0, 90, 40);

            // add the header and footer to the existing (now resized pdf document)
            PdfDocument doc = resizer.GetDocument();

            // header template (90 points in height) with image element
            PdfTemplate header = doc.AddTemplate(doc.Pages[0].ClientRectangle.Width, 90);
            PdfImageElement img1 = new PdfImageElement(10, 10, imgFile);
            header.Add(img1);

            // footer template (40 points in height) with text element
            PdfTemplate footer = doc.AddTemplate(new RectangleF(0,
                doc.Pages[0].ClientRectangle.Height - 40,
                doc.Pages[0].ClientRectangle.Width, 40));

            // create a new pdf font
            PdfFont font2 = doc.AddFont(PdfStandardFont.Helvetica);
            font2.Size = 12;

            PdfTextElement text1 = new PdfTextElement(10, 10,
                "Generated by SelectPdf. Page number {page_number} of {total_pages}.",
            font2);
            text1.ForeColor = System.Drawing.Color.Blue;
            footer.Add(text1);

            // save pdf document
            byte[] pdf = doc.Save();

            // close pdf document
            resizer.Close();

            // return resulted pdf document
            FileResult fileResult = new FileContentResult(pdf, "application/pdf");
            fileResult.FileDownloadName = "Document.pdf";
            return fileResult;
        }
    }    
}

The best approach is the first, so try to move your footer setting before the conversion.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
Tom
  • 285
  • 2
  • 3