1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using System . Xml . Linq ;
6+ using DocSharp . Docx ;
7+ using DocumentFormat . OpenXml ;
8+ using DocumentFormat . OpenXml . Packaging ;
9+ using DocumentFormat . OpenXml . Wordprocessing ;
10+ using W = DocumentFormat . OpenXml . Wordprocessing ;
11+ using QuestPDF . Fluent ;
12+ using System . Globalization ;
13+ using M = DocumentFormat . OpenXml . Math ;
14+ using System . Diagnostics ;
15+
16+ namespace DocSharp . Renderer ;
17+
18+ public partial class DocxRenderer : DocxEnumerator < QuestPdfModel > , IDocumentRenderer < QuestPDF . Fluent . Document >
19+ {
20+ internal void ProcessHeaderFooters ( SectionProperties sectionProperties , QuestPdfPageSet pageSet , MainDocumentPart mainPart , QuestPdfModel output )
21+ {
22+ // Rules for header and footer in DOCX:
23+ // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.headerreference?view=openxml-3.0.1
24+ // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.footerreference?view=openxml-3.0.1
25+ // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.evenandoddHeaders?view=openxml-3.0.1
26+ // https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.wordprocessing.titlepage?view=openxml-3.0.1
27+
28+ // Check if different headers/footers for odd/even pages are enabled in this document.
29+ var documentSettings = mainPart . DocumentSettingsPart ? . Settings ;
30+ bool evenOddEnabled = ( documentSettings ? . GetFirstChild < EvenAndOddHeaders > ( ) ) . ToBool ( ) ;
31+ // In DOCX, this setting affects both headers and footers, and all sections in the document.
32+
33+ // Check if different header/footer for the first page in the section are enabled
34+ bool firstPageEnabled = sectionProperties . GetFirstChild < TitlePage > ( ) . ToBool ( ) ;
35+ // In DOCX, this setting affects both headers and footers but is section-specific.
36+
37+ // EvenAndOddHeaders and TitlePage are assumed false if not present.
38+
39+
40+ // Process default header for this section.
41+ var headerRefDefault = FindHeaderReference ( sectionProperties , HeaderFooterValues . Default ) ;
42+ // Header and footer of a specified type (default/odd/first) should be inherited
43+ // from the previous section, if not defined in this section.
44+ // The FindHeaderReference and FindFooterReference functions handle this logic.
45+ if ( HeaderFooterHelpers . GetHeaderFromReference ( headerRefDefault , mainPart ) is Header defaultHeader )
46+ {
47+ currentContainer . Push ( pageSet . HeaderOddOrDefault ) ;
48+ base . ProcessHeader ( defaultHeader , output ) ;
49+ if ( currentContainer . Count > 0 )
50+ currentContainer . Pop ( ) ;
51+ }
52+
53+ // Process default footer for this section
54+ var footerRefDefault = FindFooterReference ( sectionProperties , HeaderFooterValues . Default ) ;
55+ if ( HeaderFooterHelpers . GetFooterFromReference ( footerRefDefault , mainPart ) is Footer defaultFooter )
56+ {
57+ currentContainer . Push ( pageSet . FooterOddOrDefault ) ;
58+ base . ProcessFooter ( defaultFooter , output ) ;
59+ if ( currentContainer . Count > 0 )
60+ currentContainer . Pop ( ) ;
61+ }
62+
63+ // Process even header and footer, if enabled.
64+ // If not enabled, header/footer for even pages should be ignored if present.
65+ if ( evenOddEnabled )
66+ {
67+ // If no header/footer for even pages is found in this section or the previous ones,
68+ // a blank header/footer is created.
69+ // Another header/footer type should *not* be used in its place.
70+ pageSet . HeaderEven = new ( ) ;
71+ pageSet . FooterEven = new ( ) ;
72+
73+ // Try to find even pages header
74+ var headerRefEven = FindHeaderReference ( sectionProperties , HeaderFooterValues . Even ) ;
75+ if ( HeaderFooterHelpers . GetHeaderFromReference ( headerRefEven , mainPart ) is Header evenHeader )
76+ {
77+ // Process even pages header
78+ currentContainer . Push ( pageSet . HeaderEven ) ;
79+ base . ProcessHeader ( evenHeader , output ) ;
80+ if ( currentContainer . Count > 0 )
81+ currentContainer . Pop ( ) ;
82+ }
83+
84+ // Try to find even pages footer
85+ var footerRefEven = FindFooterReference ( sectionProperties , HeaderFooterValues . Even ) ;
86+ if ( HeaderFooterHelpers . GetFooterFromReference ( footerRefEven , mainPart ) is Footer evenFooter )
87+ {
88+ // Process even pages footer
89+ currentContainer . Push ( pageSet . FooterEven ) ;
90+ base . ProcessFooter ( evenFooter , output ) ;
91+ if ( currentContainer . Count > 0 )
92+ currentContainer . Pop ( ) ;
93+ }
94+ }
95+
96+ // Process first page header and footer, if enabled.
97+ // If not enabled, header/footer for first page should be ignored if present.
98+ if ( firstPageEnabled )
99+ {
100+ // If no header/footer for first page is found in this section or the previous ones,
101+ // a blank header/footer is created.
102+ // Another header/footer type should *not* be used in its place.
103+ pageSet . HeaderFirst = new ( ) ;
104+ pageSet . FooterFirst = new ( ) ;
105+
106+ // Try to find header for first page
107+ var headerRefFirst = FindHeaderReference ( sectionProperties , HeaderFooterValues . First ) ;
108+ if ( HeaderFooterHelpers . GetHeaderFromReference ( headerRefFirst , mainPart ) is Header firstHeader )
109+ {
110+ // Process header
111+ currentContainer . Push ( pageSet . HeaderFirst ) ;
112+ base . ProcessHeader ( firstHeader , output ) ;
113+ if ( currentContainer . Count > 0 )
114+ currentContainer . Pop ( ) ;
115+ }
116+
117+ // Try to find footer for first page
118+ var footerRefFirst = FindFooterReference ( sectionProperties , HeaderFooterValues . First ) ;
119+ if ( HeaderFooterHelpers . GetFooterFromReference ( footerRefFirst , mainPart ) is Footer firstFooter )
120+ {
121+ // Process footer
122+ currentContainer . Push ( pageSet . FooterFirst ) ;
123+ base . ProcessFooter ( firstFooter , output ) ;
124+ if ( currentContainer . Count > 0 )
125+ currentContainer . Pop ( ) ;
126+ }
127+ }
128+ }
129+ }
0 commit comments