Metainformationen zur Seite

Markdown und Co.

Inzwischen (Nov 2022) steht für mich fest, dass ich mit einem Workflow, in dem ich meine Texte in Markdown schreibe und dann als HTML und PDF audgeben kann sehr gut zurecht komme.

Die Grundidee ist, das Schreiben der Inhalte von der endgültigen Formatierung zu trennen. Trotzdem sollen die Formatierungen schon im ASCII-Text (naja, Unicode-Text) erkennbar sein. Weitere Vorteile ergäben sich, wenn man eine Versionsverwaltung wie Git einsetzen würde, da diese zeilenweise Textdateien versioniert. Damit kann man z.B. bei einem Buch, das in einer Markdown-Datei geschrieben wird, jede Änderung nachvollziehen. Dies ist mit einem Textverarbeitungsprogramm (Word, Writer) so nicht möglich. Mein restlicher Workflow ist allerdings Nextcloud-basiert, so dass Git eine zusätzliche und für mich nicht vorteilhafte Verkomplizierung wäre.

Weitere Artikel in dieser Serie: moderne Web-Fonts-Nutzung

Idee

Markdown ist bekanntlich eine vergleichsweise einfache Methode um sofort gut lesbaren strukturierten Text zu schreiben. Ohne Menüs, eine Maus oder Tastatur-Shortcuts zu nutzen kann man Texte mit hierarchischen Überschriften, Fett/Kursivschrift, Tabellen, Zitaten, Links, Fußnoten und Code-Fragmenten schreiben. Es sind bereits einige Bücher sowie viele E-Books in Markdown geschrieben worden.

Persönlicher Bedarf: Ich verfasse für den Physik/Informatikunterricht Skripte zu meinem Unterricht (primär für mich und als Tafelbild - kein Lehrwerk). Dabei werden die üblichen Features genutzt: Hierarchische Überschriften, Abbildungen, Einteilung in Spalten (meist für Beschreibungen neben Bildern), Mathematische Formeln, Tabellen, Quelltexte (in unterschiedlichen „Sprachen“), Definitionen usw. Dies alles geht inzwischen problemlos in Markdown mit den Ergänzungen von Pandoc und mir [z.B. werden bei mir Quelltexte in einem hellgrauen Kasten angezeigt, der rechts oben ein oranges „JS“ enthält, wenn der Quelltext Javascript ist. Entsprechend für alle bei mir vorkommenden Sourcen (Python, Java, HTML, CSS, Bash usw.)]. Wegen der dynamischeren Formatierung zeige ich an den digitalen Tafeln lieber die HTML-Variante. Um es den Schüler(inne)n digital zur Verfügung zu stellen ist das PDF-Format geschickter, da nur eine Datei und final formatiert.

Praxis

Dienste wie z.B. Github zeigen Markdown-Dateien automatisch als gut aussehendes HTML an. Aber jeder kann selbst Tools einzusetzen, die optisch ansprechende Dokumente in vielen verschiedenen Formaten erzeugen können. Ich ziele derzeit nur auf HTML und daraus erzeugtes PDF (so werden beide mit CSS formatiert). [Man kann aber auch von Pandoc direkt PDF-, odt- oder epub-Dateien erzeugen lassen. Zu den Möglichkeiten siehe hier.]

  • Der Markdown Editor Ghostwriter hilft mir reinen Markdown-Text zu verfassen.
  • Die Konvertierungssoftware Pandoc erzeugt aus einer Markdown-Datei eine HTML-Datei.
  • Den Ausdruck der HTML-Datei in eine PDF-Datei erledigt der Chromium-Browser oder auch Google-Chrome von der Kommandozeile aus.

Pandoc alleine erzeugt eine korrekte, aber nicht so hübsche HTML-Datei. Aber man kann mit der Kommandozeilenoption -H eine zusätzliche Datei in den Header der HTML-Datei einfügen lassen. Damit ist es einfach viele CSS-Styles einzubinden. Am Ende kann man mit -F eine weitere Datei als eine Art Fußzeile einfügen lassen. Dann gibt es noch den Befehl --toc, der ein Inhaltsverzeichnis generiert, das wiederum erst nach einer Formatierung mit obigen Styles gut aussieht.

Chromium/Chrome kann über die Kommandozeile eine HTML-Datei direkt als PDF-Datei „ausdrucken“. Dabei werden Formatierungsanweisungen der HTML-Datei beachtet, z.B. page-break-before, so dass man Kapitel mit einer neuen Seite anfangen lassen kann. Man kann sogar das Aussehen der PDF-Datei komplett anders gestalten, da dabei @media print { … } beachtet wird.

Inzwischen werden mehrere Dateien inkludiert, die CSS-Zeilen regelmäßig ergänzt sowie der Aufruf von Pandoc und Chrome per Skript automatisiert. Deshalb benötige ich einen Prozess um diesen Workflow auf mehreren Rechnern identisch durchführen zu können:

  • Ich erstelle dazu ein Dockerimage, das
  • als Backup an andere Rechner (bei mir sowohl Linux- als auch Windows10-Rechner) weitergegeben und
  • dort geladen wird.
  • Ein Pythonskript in dem dockerimage überwacht z.B. das aktuelle Verzeichnis und konvertiert eine zu neue md-Datei sofort in html und pdf, so dass man sich Resultate gleich ansehen kann.

Die Vorgehensweise wird in der nächsten Zeit hier dokumentiert.

Technisches

Stand von 2021 - Aktualisierung Ende 2022 folgt…

Wer ein wenig experimentieren möchte aber auf einer funktionierenden Basis: Hier der aktuelle Stand…

Bash-Datei, die mit dem Namen der md-Datei aufgerufen wird. Dann werden sowohl eine HTML- als auch eine PDF-Datei erzeugt. Pandoc installiert?

md2html
#!/bin/bash
if [[ "$1" == "" ]]
then 
	echo "Dateiname.md als Parameter fehlt" 
	exit
fi
 
rumpf="${1%.*}"
ext="${1##*.}"
echo $rumpf . $ext
[[ "$ext" == @(md|txt|markdown) ]] || (printf "Falsche, oder keine Erweiterung!\nMuss md oder txt sein\n"; exit;)
 
pandoc -s -o "${rumpf}.html" "${1}" --toc --toc-depth=2 -H ~/Pfad/zu/doku.css -A ~/Pfad/zu/footer.txt 
 
firefox "${rumpf}.html" &
 
chromium --headless --disable-gpu  \
    --run-all-compositor-stages-before-draw --print-to-pdf-no-header --no-margins \
    --print-to-pdf=${rumpf}.pdf ${rumpf}.html

footer.txt ist ein HTML-Schnipsel - bei mir im Original mit einem base64-kodierten Bildchen.

footer.txt
<div id="footer" style="text-align:right;">
	Christian Bienmüller <img style="vertical-align:middle;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADEAAAAwCAYAAAC4wJK5AAAABmJLR0QA
        ....
        YOX/NaDH6ejFV/cJagIy6ud4/pL/9S/vYwWvr7yH4Bzfnf1V79bdqpv97/KuM/wdexdIzOCy+fQAAAABJRU5ErkJggg==" alt="Biene" />
</div>

doku.css enthält alle Formatierungen und, da sie 1:1 in den Header geschrieben wird, auch die Zeilen <style> und </style».

doku.css
<style type="text/css">
    body {
        margin: auto;
        padding-right: 1em;
        padding-left: 1em;
        max-width: 44em; 
        border-left: 1px solid black;
        border-right: 1px solid black;
        font-family: "Liberation Sans", Verdana, Arial, sans-serif;
        font-size: 100%;
        line-height: 140%;
        color: #333; 
    }
    pre {
        border: 1px dotted gray;
        background-color: #ececec;
        color: #1111111;
        padding: 0.5em;
    }
    blockquote {
        border-left: 4px solid #4d94ff;
        padding-left: 6px;
        margin: 10px 20px 10px 10px;
    }
    code {
        font-family: "Source Code Pro", "Liberation Mono", monospace;
        background-color: #ececec;
 
    }
    a { color: #005ce6}
    .footnote-ref {text-decoration: none; font-weight:bold;}
 
    h1 a, h2 a, h3 a, h4 a, h5 a { 
        text-decoration: none;
        color: #005ce6; 
    }
    h1, h2, h3, h4, h5 { font-family: "Liberation Sans", Verdana, Arial, sans-serif;
                         font-weight: bold;
                         color: #4d94ff; }
 
    h1, h2, h3 { 
            border-bottom: 1px dotted black;
    }
    h1 {
        font-size: 130%;
        counter-reset: h2counter;
    }
 
    h1:not(:first-of-type) {
        page-break-before: always;
    }
 
    h2 {
        font-size: 115%; 
    }
 
    h3 {
        font-size: 105%; }
 
    h4 {
        font-size: 95%;
        font-style: italic; }
 
    h5 {
        font-size: 90%;
        font-style: italic; }
 
    h1.title {
        font-size: 200%;
        font-weight: bold;
        padding-top: 0.2em;
        padding-bottom: 0.2em;
        text-align: left;
        border: none; }
 
    dt code {
        font-weight: bold;   }
 
    dd p {
        margin-top: 0;   }
 
    footer, #footer {
        padding-top: 1em;
        font-size: 70%;
        color: gray;
        text-align: center; }
 
    table {
        font-family: "Liberation Sans", Verdana, Arial, sans-serif;
        border-collapse: collapse;
        width: 100%;  }
 
    td, th {
        border: 1px solid #ddd;
        padding: 8px;
    }
 
    td:first-child {
        font-weight: bold; font-size:90%;}
 
    tr:nth-child(even){
        background-color: #f2f2f2;}
 
    tr:hover {background-color: #ddd;}
 
    th {
        padding-top: 12px;
        padding-bottom: 12px;
        text-align: left;
        background-color: #4d94ff;
        font-weight: bold;
        color: white;  } 
 
    .footnotes li {
        font-style: italic;
        font-size:80%;    }
    /* Formatierung des Table Of Contents */
    #TOC { 
        float: right;
        max-width: 35%; 
        font-size:80%;
        margin-left: 6px;
        padding-left: 6px;
        padding-right: 4px;
        background-color: #e6f0ff;
        border: 1px solid grey;
    }
    #TOC::before { 
        font-weight: bold;
        content: " Inhalt und Links" ;
    }
    #TOC ul { 
        margin: 0em;
        padding: 0em;
        padding-left: 1.5em; 
    }
    #TOC a,
    #TOC a:visited {
        text-decoration: none;
    }
 
/* ==========================================================================
   Print styles. Zum Drucken im Browser und für PDF-Export relevant
   ========================================================================== */
 
@media print {
    body { 
        font-size: 90%;
        max-width:100%;
        border: 0;
    }
 
    *,
    *::before,
    *::after {
        /* background: #fff !important; */
        /* color: #000 !important; */
        /* Black prints faster */
        box-shadow: none !important;
        text-shadow: none !important;
    }
    h1, h2 { color:  #404040; }
    h3, h4, h5 { color: grey; }
 
    th { background: grey;}
 
    a,
    a:visited {
        color: grey;
        text-decoration: underline;
    }
    /* Inhaltsverzeichnis */
    /* -> besteht nur aus Links, müssen aber daher nicht so formatiert sein */
    #TOC a,
    #TOC a:visited {
        color: black;
        text-decoration: none;
    }
    /* ohne Farbe hellstgrau */
    #TOC {
        background-color: #e8e8e8;
    }
 
    /* Print the URL of most links */
    a[href]::after {
        content: " (" attr(href) ")";
        font-size: 80%;
    }
    /* Don't print internal links or links that use the `javascript:` pseudo protocol */
    a[href^="#"]::after,
    a[href^="javascript:"]::after {
        content: "";
    }
 
    abbr[title]::after {
        content: " (" attr(title) ")"; 
    }
 
    pre {
        white-space: pre-wrap !important;
        border: 1px solid #999;
        page-break-inside: avoid;
    }
 
    blockquote {
        border-left: 4px solid grey;
        padding-left: 6px;
    }
 
    tr,
    img {
        page-break-inside: avoid;
    }
 
    h2, h3, h4 {
        page-break-after: avoid;
    }
} /* ENDE der Printstyles */
 
</style>