commit 3747f8f381476a1c05d7420d3b648c2f89ea007b Author: Sebastian Date: Sat Jun 5 22:48:10 2021 +0200 Initial version of cookbook diff --git a/README.md b/README.md new file mode 100644 index 0000000..46d04c4 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# Das Plätzchenkochbuch + +Mit diesem Projekt kann man automatisch aus der Plätzchendatei ein PDF-Kochbuch generieren. Das Kochbuch hat ein Titelblatt, Inhaltsverzeichnis, Vorwort und ein Verzeichnis der Zutaten und Plätzchenarten. + +Rezepte stehen in Spalten, in Zeilen stehen die Zutaten. +Das Excel-File wird mit openpyxl geparsed. Zuerst wird die Index-Spalte geparsed um die verschiedenen Reihen zu identifizieren. Anschließend werden die Rezepte spaltenweise durchlaufen und nacheinander in die 'rezepte.tex' Datei geschrieben. + +Nachdem das Excel-File geparsed wurde wird 'main.tex' mit pdflatex compiled. Diese Datei included die rezepte.tex und es entsteht das fertige Kochbuch. + + +## Datenformat +Um das Excel-File parsen zu können muss es immer das gleiche Format haben. +Es gibt unter anderem die folgenden Einschränkungen und Regeln: + +1. Die Rezpte befinden sich im Worksheet 'Rezepte'. +2. Zutaten + - Die Zutaten stehen in ersten Spalte, in der 'Zutaten' auftaucht + - Die Liste der Zutaten beginnt mit 'Ingredient' und schließt mit 'Sonstige Zutaten' ab. + +3. Der Name steht in der Zeile mit 'Zutaten' +4. Die Art steht in der Zeile mit 'Art' +5. Die Hauptzutaten stehen in der Zeile mit 'Ingredient'. Mehrere Hauptzutaten werden mit Komma getrennt. + +## Weitere Hinweise: +* Es ist sinnvoll, die Textbeschreibung ausführlich zu machen. Zeilenumbrüche könntne mit + gemacht werden. +* Es sind keine Rezepte ohne Zutaten möglich + + diff --git a/figures/Coatimundi_lineart.png b/figures/Coatimundi_lineart.png new file mode 100644 index 0000000..aa223b1 Binary files /dev/null and b/figures/Coatimundi_lineart.png differ diff --git a/figures/cc-by.png b/figures/cc-by.png new file mode 100755 index 0000000..95ae616 Binary files /dev/null and b/figures/cc-by.png differ diff --git a/figures/cc-sa.png b/figures/cc-sa.png new file mode 100755 index 0000000..040ca1e Binary files /dev/null and b/figures/cc-sa.png differ diff --git a/figures/cc.png b/figures/cc.png new file mode 100755 index 0000000..afb8537 Binary files /dev/null and b/figures/cc.png differ diff --git a/figures/coati.jpg b/figures/coati.jpg new file mode 100644 index 0000000..3a58201 Binary files /dev/null and b/figures/coati.jpg differ diff --git a/figures/coati.pdf b/figures/coati.pdf new file mode 100644 index 0000000..81c1abd Binary files /dev/null and b/figures/coati.pdf differ diff --git a/figures/coati.svg b/figures/coati.svg new file mode 100644 index 0000000..031dc6a --- /dev/null +++ b/figures/coati.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/figures/coati2.jpg b/figures/coati2.jpg new file mode 100644 index 0000000..bb988eb Binary files /dev/null and b/figures/coati2.jpg differ diff --git a/figures/coati2.svg b/figures/coati2.svg new file mode 100644 index 0000000..84cc517 --- /dev/null +++ b/figures/coati2.svg @@ -0,0 +1,66 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/figures/kangaroo.pdf b/figures/kangaroo.pdf new file mode 100644 index 0000000..0f0f545 Binary files /dev/null and b/figures/kangaroo.pdf differ diff --git a/introduction.tex b/introduction.tex new file mode 100644 index 0000000..16143e8 --- /dev/null +++ b/introduction.tex @@ -0,0 +1,22 @@ +\section*{Vorwort} +\addcontentsline{toc}{section}{Vorwort} + +\vspace{1cm} + +\begin{center} + \textit{„That’s what I do: I bake and I know things.”} +\end{center} + +Das T-Shirt mit dem passenden Snoopie haben mir liebe Freunde zum 31. Geburtstag geschenkt. Da stand das achte Jahr unserer Zootierbäckerei zusammen mit dem Koala und dem Schaf bevor, das zweite Mal mit dem Otter und dem Hasen, das dritte Mal zu sechst. + +Backen ist nicht nur eine super Möglichkeit neue Dinge auszuprobieren und dabei zu entspannen, es kommt auch noch was leckeres dabei heraus. Und es ist einfach eine Freude, den Zutaten bei ihrer Metamorphose zuzusehen. +Daher kann ich das auch nicht als Aufwand begreifen. In diesem Jahr, dem durchaus faszinierenden 2020, habe ich mich an zuckerfreien Keksen versucht, teilweise waren sie gar gänzlich frei von Kohlehydraten und Süßstoffen.\\ + +In Summe waren es damit deutlich über 50 Sorten, die den Ofen verlassen haben. Allerdings kann und will ich das weder als Arbeit noch als Aufwand begreifen. Es macht schlicht riesigen Spaß, nicht nur das Backen selbst, sondern insbesondere die Vorbereitung und Planung. Dank meiner Rezeptdatei ist es ein leichtes eine entsprechende Einkaufsliste mit einem Klick zu erstellen. Und das beste: seit diesem Jahr lässt sie sich automatisch in ein lesbares Buch umwandeln. + +Dafür muss ich mich bei meinem über alle Maßen geliebten Känguru bedanken, und ihr auch, sonst könntet ihr das nun nicht lesen. +Die häufigste Frage die ich bekomme ist tatsächlich: Warum? --- Die Antwort lautet: Warum nicht?\\ + +In diesem Sinne: Viel Spaß!\\ + +\textit{Euer Nasenbär} diff --git a/kekse.py b/kekse.py new file mode 100755 index 0000000..1fe1ef2 --- /dev/null +++ b/kekse.py @@ -0,0 +1,309 @@ +#!/usr/bin/env python3 + +from openpyxl import Workbook +from openpyxl import load_workbook +import sys +import os + + + +def escape_latex (content): + content=content.replace("⁄","/") + content=content.replace("℔", "\ lb") + content=content.replace("½", "$\\frac{1}{2}$") + content=content.replace("¼", "$\\frac{1}{4}$") + content=content.replace("¾", "$\\frac{3}{4}$") + content=content.replace("\n", "\\\\\n") + content=content.replace("°", "$^\circ$") + content = content.replace("&", "\&") + content = content.replace("ö", "ö") + return content + + +# Define output file +f_latex = open("rezepte.tex","w+") + +# Load cookbook +cb = load_workbook('/home/sebastian/Projekte/Kochbuch/kekse.xlsx', data_only=1) + +sheets = cb.sheetnames + +ws = None + + +# Find worksheet with recipes +ws = cb.get_sheet_by_name("Rezepte") + +# Variables to store information while parsing + +# Legend gives the column with descriptions and starting row for the recipes +legend_row = 0 +legend_col = 0 + +# Ingredients +# Find the corresponding rows to all properties of recipes +ingredients_row_start = 0 + +in_ingredients = False +in_recipe = False + +ingredients = {} +ingredients_unit = {} +ingredients_comment = {} + +ingredients_other_row = 0 + + +# Other fields +type_row = 0 +instructions_row = 0 +baking_time_row = 0 +baking_temperature_row = 0 +number_row = 0 +resting_time_row = 0 +specials_row = 0 + +# Years +first_year_row = 0 +last_year_row = 0 +first_year = 0 + +##### + +# Go through worksheet and parse all information +for column in ws.columns: + for cell in column: + + # Find row of type of recipe + if(cell.value=="Art"): + type_row = cell.row + legend_row = cell.row + legend_col = cell.column + + if(cell.column == legend_col): + # Find row of recipe name, this is in the row with 'Zutaten' + if(cell.value == "Zutaten"): + name_row = cell.row + ingredients_row_start = cell.row +1 + in_ingredients = True + + + # Find position of ingredients + if(cell.value == "Hauptaromen"): + aroma_row = cell.row + + # Find position of source + if(cell.value == "Quelle"): + source_row = cell.row + + # Instructions + if(cell.value== "Anleitung"): + instructions_row = cell.row + + # Check if we are at end of ingredients + if(cell.value== "Sonstiges (Deko)"): + ingredients_other_row = cell.row + in_ingredients = False + + # Make list of all ingredients and their units + if(cell.row >= ingredients_row_start and in_ingredients): + string = cell.value + + if("(" in string and ")" in string): + ingredients[cell.row] = (cell.value.split('(')[0].rstrip()) + ingredients_unit[cell.row] = (cell.value.split('(')[1].split(')')[0].rstrip()) + ingredients_comment[cell.row] = (cell.value.split(')')[1].rstrip()) + else: + ingredients[cell.row] = (string) + ingredients_unit[cell.row] = ("") + ingredients_comment[cell.row] = ("") + + + # Further instructions + if(cell.value== "Backzeit (Minuten)"): + baking_time_row = cell.row + if(cell.value== "Backtemperatur Umluft (Grad)"): + baking_temperature_row = cell.row + if(cell.value== "Ruhezeit (Minuten)"): + resting_time_row = cell.row + if(cell.value== "Anzahl (ca.)"): + number_row = cell.row + if(cell.value== "Besonderheiten"): + specials_row = cell.row + + # Years + if(cell.value == 2013): + first_year_row = cell.row + last_year_row = cell.row + first_year = 2013 + + if(first_year_row > 0 and cell.value == "Kommentare zur Bearbeitung."): + # cell.row -2 instead of -1 to ignore current year 2021 + last_year_row = cell.row-2 + + # By now, we should have found everything in the legend + + + ##### + + # Parse recipe + # Go through worksheet vertically, starting with the first column + # If right of legend, then it must be a recipe + if(cell.column > legend_col): + + # Obtain information of recipe in the right order, so that we can directly write it to the tex-file. + + # Name of recipe + content = (ws._get_cell(name_row, cell.column).value) + if(content != "None\n" and content != None): + f_latex.write(str("\\begin{minipage}{\\textwidth}\n")) + + #if (content[-5:]=="(Oma)"): + # content="Omas " + content[:-6] + f_latex.write(str("\section{%s}\\vspace{0.5cm}\n" % content)) + + f_latex.write(str("\\begin{tabular}{lll}\n")) + + # Aroma + content = (ws._get_cell(aroma_row, cell.column).value) + if(content != "None\n" and content != None): + f_latex.write(str("\\faHeart & \\textbf{Hauptzutat} & %s" % content)) + + f_latex.write(str("\\index{\\textbf{%s}}" % content.replace(", ", "}} \\index{\\textbf{"))) + f_latex.write("\\\\\n") + + # Type + content = (ws._get_cell(type_row, cell.column).value) + if(content != "None\n" and content != None): + f_latex.write(str("\\faEye & \\textbf{Form} & %s" % content)) + f_latex.write(str("\\index[formen]{\\textbf{%s}}" % content.replace(", ", "}} \\index[formen]{\\textbf{"))) + f_latex.write("\\\\\n") + + # Source + content = (ws._get_cell(source_row, cell.column).value) + if(content != "None\n" and content != None): + f_latex.write(str("\\faBook & \\textbf{Quelle} & %s" % content)) + f_latex.write("\\\\\n") + + # Specials + content = (ws._get_cell(specials_row, cell.column).value) + if content == "(vegan)": + content="Vegan" + if(content != "None\n" and content != None): + f_latex.write(str("\\faStar & \\textbf{Besonderheiten} & %s" % content)) + f_latex.write("\\\\\n") + + # Baking + content1 = str(ws._get_cell(baking_time_row, cell.column).value) + content2 = str(ws._get_cell(baking_temperature_row, cell.column).value) + + if((content1 != "None" and content1 != None and content1 != "0") or (content2 != "None" and content2 != None and content2 != "0")): + f_latex.write(str("\\Oven & \\textbf{Backzeit} &")) + if(content1 != "None" and content1 != None and content1 != "0"): + if(content1[-4:]=="Min."): + content1 = content1[:-4] + f_latex.write(str("%s Minuten bei " % content1)) + else: + f_latex.write(str(" bei")) + if(content2 != "None" and content2 != None and content2 != "0"): + f_latex.write(str(" %s~$^\circ$C" % content2)) + f_latex.write("\\\\\n") + + # Resting time + content = str(ws._get_cell(resting_time_row, cell.column).value) + if(content != "None" and content != None and content != "0"): + f_latex.write(str("\\faClockO & \\textbf{Ruhezeit} &")) + if(content[-1:]=="h"): + f_latex.write(str(" %s Stunden" % content[:-1])) + else: + f_latex.write(str("%s Minuten" % content)) + f_latex.write("\\\\\n") + + # Amount + content = (ws._get_cell(number_row, cell.column).value) + if(content != "None\n" and content != None): + f_latex.write(str("\\faHashtag & \\textbf{Anzahl} & %s Stück\\\\\n" % content)) + + # Years + year = first_year + count = 0 + output = "\\faCalendar & \\textbf{Gebacken} &" + for i in range (first_year_row, last_year_row+1): + content = (ws._get_cell(i, cell.column).value) + if(content != "None\n" and content != None): + # Cookie was baked in year + output = output + " " + str(year) + "," + count +=1 + year += 1 + if(count == 0): + output = output + " Noch nie gebacken" + else: + output = output[:-1] + f_latex.write(str(output+"\\\\\n")) + + if(count > 0): + f_latex.write(str("\\faLineChart & \\textbf{Häufigkeit} & " + str(round(100/(year-first_year)*count))+"\\%\\\\\n")) + + f_latex.write(str("\\end{tabular}\n")) + + + + # List of Ingredients + f_latex.write(str("\\subsection*{Zutaten}\n")) + + f_latex.write(str("\\begin{compactitem}\n")) + for i in range (ingredients_row_start, ingredients_other_row): + content = str(ws._get_cell(i, cell.column).value) + if(content != "None\n" and content != None and content != "None"): + + #content = content + ingredients_unit[i-ingredients_row_start] + ingredients[i-ingredients_row_start] + + # Add unit and whitespaces if needed + if (ingredients_unit[i] !="g"): + content = content + " " + if (ingredients_unit[i] != ""): + content = content + ingredients_unit[i] + " " + + # Add Ingredient name + if (ingredients[i] == "Ei"): + if(content == "1 "): + content = content + "Ei" + else: + content = content + "Eier" + else: + content = content + ingredients[i] + # Add comment if available + if(ingredients_comment[i] != ""): + content = content + "; " + ingredients_unit[i] + + content=escape_latex(content) + + f_latex.write(str("\\item %s \n") % content) + + f_latex.write(str("\\end{compactitem}\n\\vspace{0.2cm}\n")) + + # Other ingredients + content = (ws._get_cell(ingredients_other_row, cell.column).value) + + if(content != "None\n" and content != None and content != "None"): + content = escape_latex(content) + f_latex.write("\\textit{Außerdem:} %s \n" % content) + + + # Instructions + content = (ws._get_cell(instructions_row, cell.column).value) + if(content != "None\n" and content != None): + content=escape_latex(content) + + f_latex.write(str("\\subsection*{Anleitung} %s\n" % content)) + + f_latex.write(str("\\end{minipage}\n\n")) + f_latex.write(str("\\vspace{2cm}\n")) + + + + +# That's all, so close files +f_latex.close() + +os.system("latexmk -pdf main.tex") diff --git a/kekse.xlsx b/kekse.xlsx new file mode 100644 index 0000000..2b39690 Binary files /dev/null and b/kekse.xlsx differ diff --git a/kekse_v1.xlsx b/kekse_v1.xlsx new file mode 100644 index 0000000..ad45132 Binary files /dev/null and b/kekse_v1.xlsx differ diff --git a/main.pdf b/main.pdf new file mode 100644 index 0000000..aba4ba3 Binary files /dev/null and b/main.pdf differ diff --git a/main.tex b/main.tex new file mode 100644 index 0000000..0ee2330 --- /dev/null +++ b/main.tex @@ -0,0 +1,45 @@ +\documentclass[a4paper, 12pt, twoside, toc=flat, toc=sectionentrywithdots, BCOR=1cm]{scrartcl} +\usepackage[utf8]{inputenc} +\usepackage[german]{babel} % Silbentrennung + +\usepackage{mdframed} +\usepackage{anyfontsize} +\usepackage{adjustbox} +\usepackage{graphicx} +\usepackage{siunitx} +\usepackage{tikzsymbols} +\usepackage{paralist} +\usepackage{imakeidx} +\usepackage{fontawesome} +\usepackage{cookingsymbols} + +% Schusterjungen und Hurenkinder unterdrücken +\widowpenalty = 10000 +\displaywidowpenalty = 10000 +\clubpenalty = 10000 + +\addtokomafont{section}{\normalfont \Huge \bfseries}{\sffamily} +\addtokomafont{subsection}{\normalfont \Large \bfseries}{\sffamily} + +\let\labelitemi\labelitemii + + +% Indices +\makeindex[title=Hauptzutaten,columns=1, intoc] +\makeindex[name=formen, title=Formen und Plätzchenarten, columns=1, intoc] + +\begin{document} + +\include{title} + +\setkomafont{sectionentry}{\rmfamily} +\tableofcontents + +\include{introduction} + +\include{rezepte} + +\printindex +\printindex[formen] + +\end{document} \ No newline at end of file diff --git a/title.tex b/title.tex new file mode 100644 index 0000000..b3fb391 --- /dev/null +++ b/title.tex @@ -0,0 +1,76 @@ + +\titlepage{ + +\mdfdefinestyle{l3style}{% +leftmargin=0pt, +backgroundcolor=gray, +fontcolor=white, +linewidth=0pt, +innertopmargin=20pt, +innerbottommargin=20pt, +innerleftmargin=20pt, +font={\fontsize{80}{70}\selectfont} +} + +\pagestyle{empty} + +\begin{adjustbox}{minipage=.6\textwidth,center} +\Large{\em ``Cookies! Me eat!''\par +\hfill --- Cookie Monster} +\end{adjustbox} + +\vspace{3em} + +\begin{flushright} +\includegraphics[width=10cm]{figures/coati.pdf} +\end{flushright} + +\vspace{-1em} + +\begin{mdframed}[style=l3style] +Plätzchen +\end{mdframed} + +{\noindent\Large\emph{Ein Kompendium}}\vspace{-0.3em} + +\vspace{2em} + + + + +\begin{adjustbox}{minipage=.3\textwidth,right} +\Large\em +Sarah Wedrich +\end{adjustbox} + +\vspace{3.2cm} +%\includegraphics[width=4cm]{figures/kangaroo.pdf} +{\Large\sffamily KANGAROO PRESS} + +\cleardoublepage +\thispagestyle{empty} + +\setlength{\parindent}{0pt} +~\\ +\vspace{5cm} +\bigbreak +\huge{Plätzchen}\par +\smallbreak +\textit{\LARGE{Ein Kompendium}}\par +\vspace{2cm} + +\begin{center}{\large{\textit{ + Sarah Wedrich\\}}} +\vspace{9cm} +\Large{\today} +\end{center} + + + +\clearpage\thispagestyle{empty} +\vspace*{\fill}\noindent +\normalsize{\textbf{Plätzchen --- Ein Kompendium}\vspace{0.3cm}\\ +Sarah Wedrich\vspace{0.2cm}\\ +\textit{sarah@wedrich.org}\\ +\textit{https://www.wedrich.org} %\\ +}}