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
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.