Eigentlich hatte ich Papierbüchern ja schon abgeschworen, denn wenn ich heutzutage noch irgendein Werk aus Papier, meist gebraucht, kaufe, wandert es sofort durch den sogenannten Schnetzler, dann den Scanner, und landet schließlich digitalisiert auf meinem Luxus-iPad, um erst dort gelesen zu werden.
Doch eine Art von Papierbuch finde ich immer noch interessant und sogar der digitalen Form überlegen: Den dicken Fotoband, den man zufällig hingestreut auf einem Tischchen in der Hotel-Lobby oder einer Ferienwohnung findet. Man lässt sich in einen danebenstehenden Sessel plumpsen, lehnt sich zurück, legt die Füße hoch, und fängt gemütlich an zu blättern.
Ein "Coffee Table Book" nennt man so etwas auf amerikanisch, wohl weil es meist auf den niedrigen Kaffeetischchen ausliegt, und man kann solche Werke auch selbst mit eigenen Fotos produzieren. Die Online-Anbieter Shutterfly, Snapfish oder Blurb bieten Browser-Tools, um Fotos hochzuladen und über die Seiten eines virtuellen Papierbuchs zu verstreuen. Drückt der Kunde dann den Submit-Knopf und bezahlt, bringt der Postbote nach ein, zwei Wochen ein hochwertiges Buch mit Harteinband ins Haus.
Abbildung 1: Ein vom Autor erzeugtes und online gedrucktes Fotobuch. |
Der Gestaltungsprozess online ist jedoch eher beschränkt, bietet keinerlei Versionskontrolle und man hat dauernd Angst, dass dass die schludrig programmierte Applikation gleich die bisher investierte Arbeit verwirft und man von vorne beginnen muss. Wie wäre es mit einem handgestrickten Programm für zuhause, das Fotobücher als PDF erzeugt, die man dann einfach und billiger in einem Rutsch bei einem Service wie Lulu.com drucken und binden lassen kann?
Und wieso sollte ein Mensch beim Arrangieren der Bilder mit der Maus herumfitzeln müssen, bis diese alle auf einer Linie sind, wenn ein Satzprogramm wie TeX die Fotos auf Kommando automatisch dorthin dirigiert wo sie hingehören? Allerdings kann man kaum einem User zumuten, sich mit der schrulligen TeX-Syntax herumzuschlagen und Fotobücher im Texteditor einzugeben, mittels gefährlich aussehender Kommandos, die mit umgekehrten Schrägstrichen beginnen und den Text in geschweiften Klammern sehen wollen.
Mit etwas Kleister-Code aus Ruby können aber auch Nicht-Programmierer Druckvorlagen für ihre Kaffeetischbücher erstellen. Listing 1 zeigt die Definition eines Fotobands, und der Kontaktabzug in Abbildung 2 das davon generierte PDF. Der User nutzt pro Seite ein Template (z.B. "cover" für die Umschlagseite, "four" für eine Seite mit vier Bildern) und gibt die dazugehörigen Fotos als photos
und den untermalenden Text als text
hinzu. Schwupps, spuckt die abschließende Methode print()
in Zeile 35 ein PDF unter dem in Zeile 5 definierten Namen ("mybook"
), das ein PDF-Viewer wie zum Beispiel evince
mit evince mybook.pdf
anzeigt. Ein Online-Druckservice macht daraus ratz-fatz einen Prachtband mit Hardcover. Nicht schlecht, oder?
01 #!/usr/bin/ruby 02 require_relative "bm" 03 04 b = Bm.new 05 b.name = "mybook" 06 07 b.add "intro" 08 09 b.add "cover", 10 text: "Unstoppable Mike Schilli", 11 photos: ["ring.jpg"] 12 13 b.add "chapter" 14 15 b.add "single", 16 text: "On the Beach", 17 photos: ["ob-jump.jpg"] 18 19 b.add "twotowers", 20 text: "Planet of the Apes", 21 photos: ["icpf.jpg", "icp.jpg"] 22 23 b.add "four", 24 text: "All Along the Coast", 25 photos: ["thornton-jump.jpg", 26 "beach-rock.jpg", 27 "heron.jpg", 28 "beach-trunk.jpg"] 29 30 b.add "chapter", 31 text: "The End" 32 33 b.add "outro" 34 35 b.print
Abbildung 2: Ein PDF-Viewer zeigt das fertige Fotobuch an, bevor es in Druck geht. |
Unter der Haube erzeugt das Ruby-Interface dabei anhand der Templates TeX-Snippets, und baut hierzu mittels Variablen erläuternden Text und Pfade zu den Dateien der einzubettenden Fotos ein. Die print()
-Methode in Zeile 35 klatscht am Ende alles zusammen und ruft das Programm xelatex
auf, das daraus ein professionell aussehendes PDF setzt. Das Programm xelatex
installiert der Admin zum Beispiel unter Ubuntu mit dem Kommando sudo apt install texlive-xetex
. Es nimmt TeX-Dateien entgegen, setzt den Text, und hält leere Rechtecke für die Fotos entsprechend ihrem Format und den Satzvorgaben frei. Der PDF-Treiber pflanzt anschließend die hereingereichten JPG-Fotos in die Löcher und fertig ist der Lack.
Der Vorteil? Jetzt steht die Buchbeschreibung als Code in einer Textdatei (neues Tech-Modewort CoC, oder "Coffeebook as Code"), die der User jederzeit wieder abrufen, modifizieren, oder mittels Versionskontrolle auf einen historischen Stand zurücksetzen kann.
Allerdings ist das, was TeX unter der Haube treibt, so ausgefuchst, dass es oft schwer vorherzusagen ist, ob das Arrangement der Photos im Template nun den hehren Vorstellungen des Layouters entsprechen wird. Die Chose kompliziert sich außerdem, weil praktisch niemand mehr (außer TeX-Autor Knuth selbst) reines TeX schreibt, um Bücher zu setzen, sondern meist das daraufsitzende Makro-Paket LaTeX nutzt. Aber die richtige Zauberformel zu finden, damit LaTeX nicht plötzlich unvermittelt die Seite umbricht oder verrückte Entscheidungen trifft, erfordert oft nervenzehrende Fitzelei am Code, bis der TeX-Compiler das richtige Layout ausspuckt.
Ist aber ein Template einmal gemacht, wird es bis ans Ende der Zeit funktionieren. Das Original-Buch von TeX-Erfinder Knuth ([2]) und das Werk seiner LaTeX-Jünger [3] sind übrigens auch heute noch lesenswert, falls man sie in einem Antiquariat findet. Und noch immer publizieren Experten mathematische "Papers" in LaTeX, und auch der Autor dieser Zeilen hat vor mehr als 20 Jahren mal ein Perl-Buch in LaTeX geschrieben ([4]). Diese Wahl setzt einen Autor definitiv einer extrem steilen Lernkurve aus, aber wer Versionskontrolle und Reproduzierbarkeit ohne manuelle Schritte schätzt, hat auch heute kaum eine andere Wahl. Professionelle Satzprogramme wie Adobe InDesign oder QuarkXPress können auch heute noch, knapp 50 Jahre später, immer noch nichts automatisch.
Warum Ruby als Kleister-Code und nicht Go, wie sonst üblich im Programmier-Snapshot? Für reine Textmanipulation und simplen, prägnanten, und einfach zu erweiternden Code, der fast schon wie eine Config-Datei ausschaut, ist eine Skriptsprache wie Ruby einfach nicht zu schlagen. Noch dazu eignet sich Rubys Template-System Emb
hervorragend zum Einpflanzen von Text oder Fotodateien in die Snippets mit dem TeX-Salat, nicht ohne Grund nutzen CM-Tools wie Puppet und Chef Ruby als Referenzsprache für die dynamische Anpassung mannigfaltiger Konfigurationsdateien auf individuelle Umgebungen.
Listing 2 zeigt den Ruby-Kleister, der eine Klasse definiert, die User-Skripts zum Generieren von Coffee-Table-Books wie Listing 1 einbinden müssen. Mit require_relative bm
finden Skripts die Bibliothek aus Listing 2 im gleichen Verzeichnis und können dann sofort mit Bm.new
loslegen. Mit der zurückkommenden Instanz bm
erstellen sie mit wenigen Kommandos anspruchsvolle Fotobände.
Die TeX-Templates liegen der Ordnung halber alle in einem Unterverzeichnis tmpl
. Damit User sie nur mit Namen aufrufen können (zum Beispiel "cover"), definiert Listing 2 eine Instanzvariable @tmpldir
, die auf das Unterverzeichnis mit den Templates zeigt. Geht es ans Auslesen eines Templates, klatscht Zeile 14 vor den hereingereichten Namen der Datei den tmpl
-Pfad, hängt hinter den Namen noch eine .tex
-Endung an. Schon zeigt der generierte Pfad auf eine real existierende Datei, die der Template-Prozessor ERB in Zeile 19 einlesen kann.
01 #!/usr/bin/ruby 02 require 'erb' 03 04 class Bm 05 attr_accessor :name 06 07 def initialize 08 @tmpldir = "tmpl" 09 @photodir = "photos" 10 @tex = "" 11 end 12 13 def add(tmpl, text: "", photos: []) 14 tpath = "#{@tmpldir}/#{tmpl}.tex" 15 16 photos = photos.map { 17 |path| "#{@photodir}/#{path}" } 18 19 t = ERB.new(File.read(tpath)) 20 @tex += t.result_with_hash( 21 text: text, photos: photos) 22 end 23 24 def print 25 texf = "#{@name}.tex" 26 File.open(texf, "w") { 27 |f| f.write(@tex) } 28 system("xelatex", texf) 29 end 30 end
Den hereingereichten Text zur Seitenunterschrift und die Pfade zu den Fotodateien baut der Template-Prozessor mittels der Methode results_with_hash()
in Zeile 20 in das jeweilige Template ein. Als Platzhalter in den Templates fungieren dabei <%= text %> für den Seitentext und <%= photos[0] %> für das erste Element des unter dem Parameter photos
übergebenen Arrays zu JPG-Pfaden der einzubindenden Fotos. Auch bei den Bildpfaden muss der User also nicht jedesmal umständlich den gesamten Pfad tippen. Solange die Instanzvariable @photodir
auf das Verzeichnis zeigt, in dem alle Bilder liegen (im Beispiel photos
), muss der User in Listing 1 jeweils nur den pfadlosen Dateinamen angeben.
Um den Namen der zu erzeugenden Buchdatei zu bestimmen, setzt das aufrufende Skript das Attribut name
eines Bm
-Objektes, wie in Zeile 5 in Listing 1. Damit dies funktioniert, definiert Listing 2 mit attr_accessor
in Zeile 5 mit :name
ein les- und schreibbares Attribut name
für alle Objekte der Klasse.
So kann eine Instanz der Klasse Bm
in bm
einfach mit bm.name = "mybook"
wie in Zeile 5 in Listing 1 per Zuweisung den Namen setzen, den Zeile 25 in Listing 2 mit @name
von der Instanzvariable abfrägt und innerhalb eines Strings mit "#{@name}"
interpoliert. So steht der Name der TeX-Datei fest, in der der TeX-Salat landen soll, und die im nächsten Schritt an den LaTeX-Compiler xelatex
geschickt wird.
So braucht Zeile 26 nur die .tex
-Datei zum Schreiben zu öffnen, die in der Instanzvariablen @tex
angesammelten TeX-Instruktionen dort abzulegen, worauf der system()
-Aufruf in Zeile 28 xelatex
darauf ansetzt, was, falls alles gut geht, eine gleichnamige .pdf
-Datei mit dem fertigen Fotobuch erzeugt.
Wie sehen nun die Templates aus? TeX- oder vielmehr LaTeX-Code ist von rückwärtigen Querstrichen übersäht und begrenzt Textbereiche mittels geschweifter Klammern. Nach einer Präambel aus Dokumenttyp und verwendeten Zusatzpaketen beginnen die eigentlichen Dokumente immer mit der Anweisung \begin{document}
und enden mit \end{document}
. Dem tragen die Templates "intro.tex" und "outro.tex" (Listing 3 und 4) Rechnung, die den Anfang und das Ende jedes erzeugten Fotoalbums bilden.
Die LaTeX-Pakete color
und pagecolor
setzen die Farben des Fonts und des Hintergrunds im Dokument. Da Fotobücher im "Dark Mode", also weißer Schrift auf schwarzem Hintergrund irgendwie professioneller aussehen, setzt das Template \color{white}
und \pagecolor{black}
.
01 \documentclass[10pt]{book} 02 \usepackage[export]{adjustbox} 03 \usepackage{color} 04 \pagecolor{black} 05 \color{white} 06 \usepackage[paperwidth=9in, 07 paperheight=7in, 08 total={8in,6.5in}]{geometry} 09 \pagestyle{empty} 10 \begin{document} 11 \sffamily
1 \end{document}
LaTeX-Dokumente drucken normalerweise die Seitennummern unten auf jede Seite, was bei Fotobänden eher unüblich ist, also unterdrückt der Befehl \pagestyle{empty}
dieses Feature. Auch wirkt TeXs Standard-Font Computer Modern heutzutage etwas antiquiert, die Sans-Serif-Version, die das Kommando \sffamily
aktiviert, entspricht heutzutage eher dem Geschmack der Zeit. Das Paket adjustbox
unterstützt das graphics
-Paket beim Einbinden von Bildern und deren Schrumpfung, damit sie in die vom Layout-Roboter vorgegebenen Rechtecke passen.
Das Format des Fotobands legt das Paket geometry
ab Zeile 6 von Listing 3 fest. Entsprechend der Vorgaben des verwendeten Druckdienstleisters messen die Seiten 9 mal 7 Inches im Querformat, wobei der tatsächlich bedruckte Bereich mit 8 mal 6,5 Inches etwas kleiner ist, damit noch etwas Rand bleibt. Wer andere Dienstleister nutzt, kann hier Anpassungen am Seitenformat vornehmen.
Das Ende des TeX-Dokuments läutet das outro
-Template ein, das lediglich ein \end{document}
absetzt, damit TeX später weiß, dass Schicht im Schacht ist.
Ein TeX-Template für eine leere Seite mit einem optionalen zentrierten Textbaustein zeigt Listing 5. Der Template-Prozessor wird den Platzhalter <%= text %>
in Zeile 3 beim Einbinden durch den als text
gesetzten Parameterwert ersetzen. Damit der Text als Kapitelüberschrift zentriert in der Mitte der Seite zu liegen kommt, setzt Zeile 2 mit \vspace*
einen Füllraum oberhalb und Zeile 4 einen gleichgroßen Bereich unterhalb des in Zeile 3 mittels \center
horizontal zentrierten Textes in der Größe Huge
. Da die beiden Füllräume oben und unten nach den Regeln der gerechten Platzaufteilung gleich große Flächen einnehmen, schwebt der Text in der Mitte der Seite. TeX unterscheidet übrigens zwischen \vspace
und \vspace*
: Das erste Kommando ohne den Stern wird am Seitenanfang ignoriert, was die Kapitelüberschrift nicht mittig, sondern am oberen Rand der Seite schweben ließe.
1 \null\newpage 2 \vspace*{\fill} 3 \center{\Huge{<%= text %>}} 4 \vspace*{\fill}
Die Titelseite des Fotobuches zeigt ein Foto mit einer Zeile Text in einem großen Font darunter, beides zum rechten Rand ausgerichtet. Listing 6 leitet hierzu im Template cover.tex
mittels \begin{center}
eine horizontal zentrierte Umgebung ein, und bindet mit \includegraphics
aus dem graphics
-Paket der LaTeX-Bibliothek ein 3 Inches hoch gerendertes Foto ein. Der Template-Prozessor erhält später einen Array mit Foto-Dateien, und der Platzhalter <= photos[0] %>
setzt den Pfad der ersten Datei in der Liste ein. LaTeX reserviert daraufhin den vom Foto beanspruchten Platz im Dokument, und der PDF-Treiber setzt später das Foto hinein, nachdem er es auf die benötigte Größe skaliert hat.
01 \vspace*{\fill} 02 \begin{center} 03 \hfill 04 \includegraphics[height=3in,valign=t]{ 05 <%= photos[0] %>} 06 \hspace*{4cm} 07 \end{center} 08 \vspace{2cm} 09 \begin{center} 10 \hfill \Huge{<%= text %>} 11 \hspace*{4cm} 12 \end{center} 13 \vspace{1cm}
Für Fotos, die groß rauskommen sollen zeigt Listing 7 ein Template für ein seitenfüllendes Querformatfoto mit darunterstehendem Text, wie in Seite 3 des fertigen Fotobuchs in Abbildung 2 zu sehen. Der Befehl \includegraphics{}
stellt im Layout Platz für ein Bild bereit, die Angabe von height
beschränkt den Platz in der vertikalen, damit auf der Seite noch Platz für den darunterstehenden Text bleibt. Den platziert Zeile 10 mit einem halben Zentimeter Extraabstand unter dem Foto.
1 \null 2 \begin{figure} 3 \centering 4 \includegraphics[height=5.5in,valign=t]{ 5 <%= photos[0] %>} 6 \linebreak 7 \par\vspace{.5cm}\par 8 \Huge{\sffamily <%= text %>} 9 \end{figure}
Wer im Querformat des Buchs auf einer Seite lieber zwei Fotos im Hochformat nebeneinander sehen möchte, greift auf das Template twotowers.tex
(Sinnbild für zwei Bilder im Hochformat) in Listing 8 zu. Es referenziert die beiden als Parameter hereingereichten Fotos mit <%= photos[0] %>
und <%= photos[1] %>
. Als Beispiel im Fotoband in Abbildung 2 dient ein Bild von einem Stück abgebrochener Straße, dessen spiegelbildlicher Gegenpart das Tool convert
aus der Sammlung ImageMagick
erzeugt hat. Immer für einen Gimmick gut!
01 \null 02 \begin{figure} 03 \centering 04 \includegraphics[height=5in,valign=t]{ 05 <%= photos[0] %>} 06 \hspace{1cm} 07 \includegraphics[height=5in,valign=t]{ 08 <%= photos[1] %>} 09 \linebreak 10 \par \vspace{1cm} \par 11 \Huge{\sffamily <%= text %>} 12 \end{figure}
Eine Buchseite im Querformat kann aber auch vier quaderförmig angeordnete Querformatfotos aufnehmen. Das Template four.tex
in Listing 9 zeigt den dazugehörigen TeX-Code. Damit der Abstand zwischen den Bildern ansprechend rüberkommt, schrumpft das Template die Fotos auf eine Höhe von 2.5 Inches, und setzt den horizontalen Abstand in den Zeilen 5 und 13 auf 0,5cm, und den vertikalen Zwischenraum in Zeile 9 auf 0,75cm. Der darunterliegende Text in der Riesenschrift \Huge
ist innerhalb der \centering
-Umgebung ebenfalls zentriert und schwebt, wie von Zeile 17 vorgegeben, 0,5cm unterhalb des unteren Bildpaars. Die Anweisung \par
leitet in TeX jeweils einen neuen Absatz ein, und \vspace{}
weist den Satzautomaten an, zwischen den Absätzen Platz zu lassen, in diesem Fall 0,5cm.
01 \begin{figure} 02 \centering 03 \includegraphics[height=2.5in,valign=t]{ 04 <%= photos[0] %>} 05 \hspace{.5cm} 06 \includegraphics[height=2.5in,valign=t]{ 07 <%= photos[1] %>} 08 \par 09 \vspace{.75cm} 10 \par 11 \includegraphics[height=2.5in,valign=b]{ 12 <%= photos[2] %>} 13 \hspace{.5cm} 14 \includegraphics[height=2.5in,valign=b]{ 15 <%= photos[3] %>} 16 \linebreak 17 \par\vspace{.5cm}\par 18 \Huge{\sffamily <%= text %>} 19 \end{figure}
Mit diesen Templates lässt sich schon ein ansprechender Fotoband erstellen, bestehend aus dem Einband, leeren Seiten, oder Kapitel-Überschriften, sowie Fotoseiten mit einem Foto im Querformat, zwei Fotos im Hochformat, oder gleich vier Fotos im Querformat, alle mit optionalem Seitentext. Zum Erzeugen des fertigen Fotobands im PDF-Format muss nur ein Skript wie Listing 1 her, das die Templates abruft und entsprechende Fotos von der Platte einbindet. Wer möchte, kann seiner Kreativität aber noch freien Lauf lassen, beliebige neue TeX-Templates erzeugen und im aufrufenden Ruby-Skript nutzen. Da die gesamte Buchdefinition in einer Textdatei liegt, verwaltet von einem Versionskontrollsystem wie git
, kann der User ohne Verlustangst Änderungen einarbeiten, oder auch Teile eines alten Bandes in einen neuen Übernehmen. Programmierte Fotobanderstellung eben.
Noch ein Bonmot fand ich übrigens im 1984 in erster Auflage erschienenen TeX-Book von Donald Knuth ([2]): Auf Seite 110 erklärt er, warum TeX zwar akribisch versucht, Absätze so umzubrechen, dass die Wortabstände in allen Zeilen möglichst gleich erscheinen, bis zu dem Punkt, an dem ein einziges Wort am Ende eines Absatzes zu einem Totalumbruch des ganzen Absatztextes führt. Auf der anderen Seite schaut es aber beim Seitenumbruch nicht mehrere Seiten voraus, um Abbildungen und Textabsätze möglichst schlau über die Seiten zu verteilen. Den Grund für diese Design-Entscheidung nennt Autor Knuth auch gleich: Der RAM-Speicher des Computers wäre schlicht nicht groß genug gewesen, um mehrere Seiten gleichzeitig vorzuhalten. Wie die Zeiten sich ändern.
Listings zu diesem Artikel: http://www.linux-magazin.de/static/listings/magazin/2022/02/snapshot/
Donald Knuth, "The TeX Book", Addison-Wesley, 1992
Michel Goossens, Frank Mittelbach, Sebastian Rahtz, Denis Roegel, Herbert Voss, "The LaTeX Graphics Companion", 2nd Edition, 2007
Michael Schilli, "Go To Perl 5", 4. Auflage, Addison-Wesley, 1998
Hey! The above document had some coding errors, which are explained below:
Unknown directive: =desc