Get a height of primary header and footer

I have seen a lot of topics and same code there u getting height using LayoutEnumerator. So, how i can get PRIMARY height of the footer and header, cause i have cases where user can deny render header and footer on a first page. I cannot show example of code, cause it’s a lot of code, cause i’m working with runtime user low-code programmed docx editors.

For now i have code that works fine if user accepts “show header and footer on a first page”:

private static void UpdateFirstHeaderFooter(AsposeBuilder asposeBuilder, PageConfiguration pageConfiguration, int tabIndex)
{
    var pageNumberSettings = pageConfiguration.PageNumber;
    var headerFooterSettings = pageConfiguration.HeaderFooter;

    if (pageNumberSettings != null)
    {
        var shouldRenderFirstPageNumber = pageNumberSettings?.ShowOnFirstPage ?? true;

        if (tabIndex != 0 || (tabIndex == 0 && shouldRenderFirstPageNumber))
        {
            asposeBuilder.MoveToHeaderFooter(pageNumberSettings.Position.ToHeaderFooterFirst());
            asposeBuilder.InsertPageNumberField(pageNumberSettings);
        }
    }

    if (headerFooterSettings != null)
    {
        var shouldRenderFirstPageHeaderFooter = headerFooterSettings?.ShowOnFirstPage ?? true;

        if (tabIndex != 0 || (tabIndex == 0 && shouldRenderFirstPageHeaderFooter))
        {
            var headerHtml = HtmlAdapter.AdaptForWords(headerFooterSettings.Header?.Value?.OutputText);
            var footerHtml = HtmlAdapter.AdaptForWords(headerFooterSettings.Footer?.Value?.OutputText);

            if (!string.IsNullOrEmpty(headerHtml))
            {
                asposeBuilder.MoveToHeaderFooter(HeaderFooterType.HeaderFirst);
                asposeBuilder.InsertHtml(headerHtml);
            }

            if (!string.IsNullOrEmpty(footerHtml))
            {
                asposeBuilder.MoveToHeaderFooter(HeaderFooterType.FooterFirst);
                asposeBuilder.InsertHtml(footerHtml);
            }
        }
    }

    asposeBuilder.MoveToDocumentEnd();
}

@bloodboilAaromatic If it is required to calculate header/footer content height, you can move content into a separate document main body and then use LayoutEnumerator to calculate it’s height. For example see the following code:

Document doc = new Document("C:\\Temp\\in.docx");

int sectIndex = 0;
foreach (Section s in doc.Sections)
{
    foreach (HeaderFooter hf in s.HeadersFooters)
    {
        // Create a temporary document for rendering header content.
        Document tmp = (Document)doc.Clone(false);
        tmp.Sections.Add(tmp.ImportNode(hf.ParentSection, false, ImportFormatMode.UseDestinationStyles));
        tmp.FirstSection.AppendChild(new Body(tmp));
        // Copy content of the header to the temporary section.
        foreach (Node n in hf.GetChildNodes(NodeType.Any, false))
            tmp.FirstSection.Body.AppendChild(tmp.ImportNode(n, true, ImportFormatMode.UseDestinationStyles));

        // Remove top and bottom margins.
        tmp.FirstSection.PageSetup.TopMargin = 0;
        tmp.FirstSection.PageSetup.BottomMargin = 0;

        // Use LayoutEnumerator to calculate the bottom edge fo visible content.
        LayoutEnumerator enumerator = new LayoutEnumerator(tmp);
        RectangleF rect = RectangleF.Empty;
        rect = CalculateVisibleRect(enumerator, rect);
        tmp.FirstSection.PageSetup.PageHeight = rect.Height;
        Console.WriteLine(rect.Height);
        tmp.UpdatePageLayout();

        tmp.Save($@"C:\Temp\hf_{sectIndex}_{hf.HeaderFooterType}.png");
    }

    sectIndex++;
}
private static RectangleF CalculateVisibleRect(LayoutEnumerator enumerator, RectangleF rect)
{
    RectangleF result = rect;
    do
    {
        if (enumerator.MoveFirstChild())
        {
            if (enumerator.Type == LayoutEntityType.Line || enumerator.Type == LayoutEntityType.Span)
                result = result.IsEmpty ? enumerator.Rectangle : RectangleF.Union(result, enumerator.Rectangle);
            result = CalculateVisibleRect(enumerator, result);
            enumerator.MoveParent();
        }
    } while (enumerator.MoveNext());

    return result;
}
1 Like

i undestanded it wisely? i should anyway move to a separate document to calculate header and footer size? There is now way i can do it on second page, cause i see in debug mode that after all logic done i have 4 object in array: firstFooter, firstHeader, primaryFooter and primaryHeader

@bloodboilAaromatic Each section in MS Word document can have 3 types of headers and 3 types of footers: primary, even and first page. So the easiest way to calculate height of each of them is to copy their content into a separate document as suggested above.

btw what about just delete FooterFirst and HeaderFirst from Section[n].HeaderFooters after all work is done. Testing it now and don’t see any related problems. Is it possible to meet a concealed problems?

I have found an exact reason why i have related problem. I don’t want to render any data in first header and footer so i miss this block of the code:

if (pageConf.HeaderFooter.ShowOnFirstPage == true)
{
    asposeBuilder.MoveToHeaderFooter(HeaderFooterType.HeaderFirst);
    asposeBuilder.InsertHtml(headerHtml);
}
if (pageConf.HeaderFooter.ShowOnFirstPage == true)
{
    asposeBuilder.MoveToHeaderFooter(HeaderFooterType.FooterFirst);
    asposeBuilder.InsertHtml(footerHtml);
}

If i have ShowOnFirstPage == false then i’m settings DifferentFirstPageHeaderFooter = true
Cause i dont want to render any footer and header on first page

if (configuration.HeaderFooter.ShowOnFirstPage == false)
{
    asposeBuilder.PageSetup.DifferentFirstPageHeaderFooter = true;
}
else if(configuration.HeaderFooter.ShowOnFirstPage == true)
{
    asposeBuilder.PageSetup.DifferentFirstPageHeaderFooter = false;
}

Then have this code:

private static void FindAndMeasureHeaderFooter(LayoutEnumerator enumerator, string[] layoutEnumeratorKind, ref double height)
{
    do
    {
        if (enumerator.Type == LayoutEntityType.HeaderFooter)
        {
            if (layoutEnumeratorKind.Contains(enumerator.Kind))
            {
                height = Math.Ceiling(enumerator.Rectangle.Height); // in points
                height /= 0.75d; // in pixels 
                return;
            }
        }

        if (enumerator.MoveLastChild())
        {
            FindAndMeasureHeaderFooter(enumerator, layoutEnumeratorKind, ref height);
            enumerator.MoveParent();
        }

        if (enumerator.Type == LayoutEntityType.Page)
        {
            return;
        }

    } while (enumerator.MovePrevious());
}

Where i calculates header footer distance. But there is a problem
When DifferentFirstPageHeaderFooter = false its iterates for FirstFooter and FirstHeader
When DifferentFirstPageHeaderFooter = true its iterates for PrimaryFooter and PrimaryHeader

So, logic contradict each other. I want to skip first page headerFooter by setting DifferentFirstPageHeaderFooter but LayoytEnumerator iterates via FirstFooter and FirstHeader

How can i use DifferentFirstPageHeaderFooter = false and iterate via PrimaryHeader and PrimaryFooter?

@bloodboilAaromatic Setting DifferentFirstPageHeaderFooter = false instructs MS Word that the section has the same header/footer for first and other pages in the section. But the section still can contain both first and primary headers/footers. So probably, you should also remove first page header/footer from the processed section.

K, for now i gonna leave a “separate document” way out cause we do not sure does removing first footer and first header from section not affect a result. Thx, issue closed. If u have more related information to removing first header and footer from result please provide.

@bloodboilAaromatic You can use the following simple code to remove first page header/footer:

Document doc = new Document(@"C:\Temp\in.docx");

if (doc.FirstSection.HeadersFooters[HeaderFooterType.HeaderFirst] != null)
    doc.FirstSection.HeadersFooters[HeaderFooterType.HeaderFirst].Remove();
if (doc.FirstSection.HeadersFooters[HeaderFooterType.FooterFirst] != null)
    doc.FirstSection.HeadersFooters[HeaderFooterType.FooterFirst].Remove();

doc.Save(@"C:\Temp\out.docx");