Welcome Guest Search | Active Topics | Sign In | Register

HTML5 <Footer> Tag not rendering at bottom of page Options
Aaron
Posted: Tuesday, January 16, 2018 11:22:09 AM
Rank: Advanced Member
Groups: Member

Joined: 12/13/2017
Posts: 29
Hi,

Our html has a footer on some pages, but this seems to render inline on the page and not at the bottom of the page as would be expected.

<footer>
<p>some footer text</p>
<p>some more footer text><p>
</footer>

Regards
eo_support
Posted: Tuesday, January 16, 2018 2:31:33 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,067
Hi,

You won't be able to use HTML5 footer with the HTML to PDF converter. The HTML to PDF converter has its own header/footer mechanism. See here for more details:

https://www.essentialobjects.com/doc/pdf/htmltopdf/header.aspx

Thanks!
Aaron
Posted: Wednesday, January 17, 2018 3:41:39 AM
Rank: Advanced Member
Groups: Member

Joined: 12/13/2017
Posts: 29
Thanks. This is a real shame that it doesn't work, as now you have to add in bespoke code with essentially hard coded values to precisely add int he footer on the correct pages. This is as opposed to a generic html approach where the html footer is part of the html document. I would like to suggest that you look at adding support for the HTML5 <Footer> to render this html at the bottom of the current page. This will allow the html document to control the footer and have different footers (or no footer) on different pages.
eo_support
Posted: Wednesday, January 17, 2018 9:18:12 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,067
Hi,

Yes. What you suggested makes perfect sense. We will look into this and see what we can do.

Thanks!
Aaron
Posted: Thursday, January 18, 2018 8:46:54 AM
Rank: Advanced Member
Groups: Member

Joined: 12/13/2017
Posts: 29
For anyone else that is reading this post, then I have managed to write a generic <Footer> handler to do the above. It will be a lot easier to have it as part of the standard processing though. My handler works as follows:-

1. set the <footer>'s to be "hidden"
update the raw html to set the visibility as 'hidden' --> Regex.Replace(draftHtml, "<footer", $"<footer style='visibility:hidden'", RegexOptions.IgnoreCase);

2. using a "EO.Pdf.Paginator", get all of the footer elements. --> HtmlElement[] footers = paginator.Document.GetElementsByTagName("footer");

3. Process the raw Html and pull out the linked CSS and also each <footer> fragment of HTML

4. For each footer element, build a new footer fragment "with <html><head><link to css /></head><body><footer>....</footer></body></html>
5. Use the original (hidden) footer from the pdf to get the size info for the replacement footer ... HtmlToPdf.Options.OutputArea = new RectangleF(footer.Location.X, inchesFromTop, footer.Size.Width, 10.0f);

5. Create a pdf area from it and add to the (hidden) footers page at the bottom ... HtmlToPdf.ConvertHtml(fullFooterHtml, pdfDocument.Pages[footer.Location.PageIndex]);

loop through all footers.


private string HideFooters(string draftHtml)
{
if (draftHtml == null)
return null;

return Regex.Replace(draftHtml, "<footer", $"<footer style='visibility:hidden'", RegexOptions.IgnoreCase);
}

/// <summary>
/// Reposition the footer at the bottom of the pdf page
/// </summary>
/// <param name="paginator"></param>
/// <param name="pdfDocument"></param>
/// <param name="rawHtml"></param>
private void AddPageFooter(Paginator paginator, PdfDocument pdfDocument, string rawHtml)
{
HtmlElement[] footers = paginator.Document.GetElementsByTagName("footer");
if (footers.Length == 0)
return;

var footersHtml = GetFootersHtml(rawHtml);
var cssLinks = GetCssLinks(rawHtml);

if (footersHtml.Count != footers.Length)
throw new InvalidOperationException("Footer count mismatch");

for (int i=0;i< footers.Length; i++)
{
HtmlElement footer = footers[i];
string footerHtml = footersHtml[i];
string fullFooterHtml = BuildFullFooterHtml(footerHtml, cssLinks);

//---------------------------------------------------------
// recreate the footer at the bottom of the page
//---------------------------------------------------------
float inchesFromTop = (11.69f - 0.4f) - footer.Size.Height; // A4 sheet is 11.69 inches high
HtmlToPdf.Options.BaseUrl = ConfigurationManager.AppSettings["TemplateBaseUrl"];
HtmlToPdf.Options.OutputArea = new RectangleF(footer.Location.X, inchesFromTop, footer.Size.Width, 10.0f);
HtmlToPdf.ConvertHtml(fullFooterHtml, pdfDocument.Pages[footer.Location.PageIndex]);
}
}

private string BuildFullFooterHtml(string footerHtml, List<string> cssLinks)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("<html>");
sb.AppendLine(" <head>");

foreach (var cssLink in cssLinks)
sb.AppendLine($" {cssLink}");

sb.AppendLine(" </head>");
sb.AppendLine(" <body>");
sb.AppendLine($" {footerHtml}");
sb.AppendLine(" </body>");
sb.AppendLine("</html>");

return sb.ToString();
}
private List<string> GetCssLinks(string rawHtml)
{
List<string> footers = new List<string>();
int startIndex = 0;
var footerNode = $"<link";

var endOfHtmlHead = rawHtml.IndexOf("</head>", StringComparison.InvariantCultureIgnoreCase);

while (true)
{
startIndex = rawHtml.IndexOf(footerNode, startIndex, StringComparison.InvariantCultureIgnoreCase);
if (startIndex < 0)
return footers;

if (startIndex > endOfHtmlHead)
return footers;

var endIndex = rawHtml.IndexOf("/>", startIndex, StringComparison.InvariantCultureIgnoreCase);
if (endIndex <= startIndex)
return footers;

string htmlSnippet = rawHtml.Substring(startIndex, (endIndex - startIndex) + 2);
footers.Add(htmlSnippet);

startIndex = endIndex;
}
}
private List<string> GetFootersHtml(string rawHtml)
{
List<string> footers = new List<string>();
int startIndex = 0;
var footerNode = $"<footer";

while (true)
{
startIndex = rawHtml.IndexOf(footerNode, startIndex, StringComparison.InvariantCultureIgnoreCase);
if (startIndex < 0)
return footers;

var endIndex = rawHtml.IndexOf("</footer>", startIndex, StringComparison.InvariantCultureIgnoreCase);
if (endIndex <= startIndex)
return footers;

string htmlSnippet = rawHtml.Substring(startIndex, (endIndex - startIndex) + 9);
string cleansedHtml = htmlSnippet.Replace("style='visibility:hidden'", "");
footers.Add(cleansedHtml);

startIndex = endIndex;
}
}
Aaron
Posted: Thursday, January 18, 2018 9:05:57 AM
Rank: Advanced Member
Groups: Member

Joined: 12/13/2017
Posts: 29
//-----------------------------------------------------
// Pre-process the Html
//-----------------------------------------------------
draftHtml = HideFooters(draftHtml);

//-----------------------------------------------------
// Convert to Pdf
//-----------------------------------------------------
HtmlToPdfOptions options = new HtmlToPdfOptions();
options.BaseUrl = ConfigurationManager.AppSettings["TemplateBaseUrl"];
options.UsePrintMedia = true;
options.JpegQualityLevel = 100;
options.AutoFitX = HtmlToPdfAutoFitMode.None;
options.AutoFitY = HtmlToPdfAutoFitMode.None;

using (HtmlToPdfSession session = HtmlToPdfSession.Create(options))
{
//-----------------------------------------------------------------
// render document
//-----------------------------------------------------------------
session.LoadHtml(draftHtml);
Paginator paginator = session.CreatePaginator();
var pdfResult = session.RenderAsPDF(paginator);

//-----------------------------------------------------------------
// Page Footers
//-----------------------------------------------------------------
AddPageFooter(paginator, pdfResult.PdfDocument, draftHtml);


//-----------------------------------------------------------------
// Output the pdf stream
//-----------------------------------------------------------------
var reportStream = new MemoryStream();
pdfResult.PdfDocument.Save(reportStream);
reportStream.Flush();
reportStream.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(reportStream, "application/pdf");
}
}
eo_support
Posted: Thursday, January 18, 2018 2:25:02 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,067
Thank you very much for sharing. That is an incredible solution! I am sure it will benefit other users before we implement this feature on our side.


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.