Fancyhdr Header and Footer not working. Latex with PyLatex

45 views Asked by At

I build Latex files via Overleaf, which are then compiled asynchronously with Celery Worker in Django and PyLatex. We use pdfLaTeX as compiler. I have created a .tex file, which is then saved as .txt, enriched with data and compiled. The image exchange and text exchange work very well so far. The only problem is that PyLatex does not want to accept my fancyhdr header and footer. One the the left image in the footer is displayed, but absolutely shifted. There is no trace of the gradient in the header and/or the rest of the footer. Do you have any ideas as to why this could be? I work locally with Miktex and have actually installed all the necessary packages.

Here is the preamble of the .tex file:

\documentclass{article}
\usepackage{lipsum} % For dummy text


% ######################################################### IMPORTS ##################
% Basic imports
\usepackage{graphicx} % Images
\usepackage{geometry} % Page Layout
\usepackage{titlesec} % Overwriting Section Style 
\usepackage{xcolor} % Coloring
\usepackage{tcolorbox} % Content Boxing 
\usepackage{tikz}
\usepackage{fancyhdr}


% From customfooter.sty
\newcommand{\setcustomfooter}{%
    \fancyhf{} % Clear all header and footer fields
    \renewcommand{\footrulewidth}{0pt}
    \fancyfoot[C]{%
        \begin{tikzpicture}[overlay, remember picture]
            % Footer area
            \path (current page.south west) rectangle ([yshift=1.5cm]current page.south east);

            % Left image
            \node[anchor=west] at ([yshift=0.75cm, xshift=0.5cm]current page.south west) {
                \includegraphics[height=0.75cm, keepaspectratio]{assets/img/78241ec6-9e96-4a5d-bfd3-55433081368e.png}
            };

            % Right image
            \node[anchor=east] at ([yshift=0.75cm, xshift=-0.5cm]current page.south east) {
                \includegraphics[height=1cm, keepaspectratio]{assets/img/c15f7986-2e57-42b4-b5d5-da8f3257d34a.png}
            };

            % Page number
            \node at ([yshift=0.75cm]current page.south) {\thepage};
        \end{tikzpicture}%
    }
}
\setcustomfooter

% From customheader.sty
\usetikzlibrary{calc}
\definecolor{startcolor}{RGB}{225,8,20}
\definecolor{endcolor}{RGB}{144,14,38}

\newcommand{\setgradientheader}[1]{%
    \renewcommand{\headrulewidth}{0pt} 
    \fancyhead[C]{%
        \begin{tikzpicture}[overlay, remember picture]
            % Header area with gradient background
            \fill [left color=startcolor, right color=endcolor] ($(current page.north west)+(0.0cm,-0.5cm)$) rectangle ($(current page.north east)-(0.0cm,2.5cm)$);

            % Header Text
            \node[anchor=east, text=white, font=\LARGE, align=right] at ($(current page.north east)-(1cm,1.5cm)$) {#1};

            % Left side image
            \node[anchor=north west, inner sep=0] at ($(current page.north west)+(1cm,-1cm)$) {
                \includegraphics[height=1cm, keepaspectratio]{assets/img/8c26b223-68a4-4954-a90d-7b37dae90eae.png}
            };
        \end{tikzpicture}
    }
}

\pagestyle{fancy}

% ####################################################################################
% ######################################################### STYLE SETTINGS ###########

% Colors
\definecolor{darkpurple}{HTML}{8C1F3C}
\definecolor{greyish}{HTML}{7F7F7F}
\definecolor{lightgreyish}{HTML}{f4f4f4}
\definecolor{white}{HTML}{FFFFFF}
\definecolor{black}{HTML}{000000}
\definecolor{lightred}{HTML}{E32636}
\definecolor{redish}{HTML}{C00000}

% Set Variables and Layout Definitions
\geometry{
    a4paper, % Paper size
    left=0.5cm, % Left margin
    right=1.5cm, % Right margin
    top=1cm, % Top margin
    bottom=1.5cm, % Bottom margin
    includeheadfoot, % Include space for the header and footer
    headheight=2cm, % Height of the header
    headsep=0.5cm, % Space between header and text
    footskip=1cm % Space between text and footer
    }

% New Section Style
\titleformat{\section}
  {\normalfont\Large\bfseries\color{redish}} % format
  {\thesection}{1em}{} % label and spacing


% Additional Text Field Likert Scale 
\newcommand{\likert}[1]{
    \begin{tikzpicture}[baseline=(current bounding box.center), align=center]
        % Draw the circles/nodes
        \foreach \x in {1,2,3,4,5} {
            % Check if this node is the selected one
            \ifnum\x=#1
                \node[draw=darkpurple, circle, fill=darkpurple, minimum size=1cm] (\x) at (2*\x, 0) {};
            \else
                \node[draw=darkpurple, circle, minimum size=1cm] (\x) at (2*\x, 0) {};
            \fi
        }
        
        % Manually add text labels below each circle
        \node at (2, -1.2) {Very low};
        \node at (4, -1.2) {Low};
        \node at (6, -1.2) {Neutral};
        \node at (8, -1.2) {High};
        \node at (10, -1.2) {Very high};
    \end{tikzpicture}
}

% ####################################################################################




\begin{document}

% ########### START LANDING PAGE 1 
\setgradientheader{} 
\vspace*{\fill}

And here is the wrapper class to compile:

class LatexCompiler:
    
    def __init__(self, tex_file, replacements={}):
        
        self.temp_dir_pdfs = TEMP_DIR_PDFS
        os.makedirs(self.temp_dir_pdfs, exist_ok=True)
        
        # Setting the tex file 
        self._tex_file = tex_file 
        
        # Setting the replacements
        self._replacements = replacements
       
    def _load_tex_file(self):
        """
        Loading the desired tex (.txt) file.
        """
        script_dir = os.path.dirname(os.path.realpath(__file__))
        cPath = os.path.join(script_dir, 'statics', 'texs', self._tex_file + ".txt")
        cPath = os.path.normpath(cPath)
        
        with open(cPath, "r", encoding="utf-8") as f:
            file = f.read()
    
        self.tex_file = file 
        
        
    def _replace_placeholders(self):
        for key, value in self._replacements.items():            
            self.tex_file = self.tex_file.replace(key, value, -1)         
            
    
    def _get_sequential_name(self):
        return str(int(time.time())) + "_" + str(uuid.uuid4())[:8]       
    
            
    def _split_latex_content(self):
        lines = self.tex_file.splitlines()
        preamble = []
        content = []
        in_preamble = True

        for line in lines:
            
            if "\\documentclass" in line:
                continue 
            
            if '\\begin{document}' in line:
                in_preamble = False
                continue
            elif '\\end{document}' in line:
                break

            if in_preamble:
                preamble.append(line)
            else:
                content.append(line)

        return '\n'.join(preamble), '\n'.join(content)

    def run(self):
        self._load_tex_file() 
        self._replace_placeholders() 
        
        
    def compile(self):
        doc = Document(documentclass='article')
        preamble, content = self._split_latex_content()
        doc.preamble.append(NoEscape(preamble))
        doc.change_page_style("fancy")
        doc.append(NoEscape(content)) 
        
        with tempfile.NamedTemporaryFile(delete=False, dir=self.temp_dir_pdfs) as temp_pdf:
            temp_pdf_path = temp_pdf.name 
            
        doc.generate_pdf(temp_pdf_path, clean_tex=False, clean=False, compiler='pdflatex')
        
        with open(temp_pdf_path + ".pdf", 'rb') as pdf_file:
            pdf_io = BytesIO(pdf_file.read())
            
        # os.remove(temp_pdf_path + ".pdf")
        # os.remove(temp_pdf_path + ".tex")
        # os.remove(temp_pdf_path)
        
        pdf_io.seek(0)
        pdf_bytes = pdf_io.getvalue() 
        pdf_io.close() 
        return pdf_bytes
1

There are 1 answers

0
SeRo On

Solution: When using [overlay, remember picture] the .tex needs to be compiled several times. "latexmk" takes care of this by itself otherwise, just wrap the "doc.generate_pdf" around an for loop and let it be compiled some times.

Note: There is no real Error Logs I could find with PyLatex; So if you use and replace placeholders like I do, check several times that placeholders are in place and that you escape inserted texts correctly.