MarkdownToIHKChemnitz

A Go CLI tool that converts a single Markdown file into a print-ready PDF compliant with the IHK Chemnitz project documentation guidelines (Verordnung 2020) and DIN 5008 formatting rules.

Features

  • DIN 5008 page layout — correct margins, font, line spacing, Blocksatz
  • Two-pass rendering for a page-accurate table of contents
  • Roman/Arabic page numbering with automatic section detection
  • Multi-line table cells with uniform row height per row
  • Named tables (Tabellenverzeichnis) and captioned figures (Abbildungsverzeichnis)
  • Numbered code blocks with line-number gutter and long-line wrapping
  • Diagram rendering via Kroki — Mermaid, PlantUML, and more
  • Inline landscape diagram pages (@DiagrammQuer:)
  • Appendices in portrait and landscape — images, tables, and diagrams
  • Abbreviation list and glossary from YAML front matter
  • Bibliography sorted alphabetically from inline @Quelle: directives
  • Declaration of authenticity page (pre-written legal text)

Prerequisites

  • Go 1.22 or later
  • Internet access or a local Kroki instance for diagram rendering (see below)

Build & Run

go build -o ihk-pdf .
./ihk-pdf -i report.md -o projektarbeit.pdf

Or without building:

go run . -i report.md -o projektarbeit.pdf

CLI Flags

Flag Default Description
-i report.md Input Markdown file
-o projektarbeit.pdf Output PDF file
-kroki https://kroki.io Kroki base URL for diagram rendering

Diagram Rendering with Kroki

Mermaid and PlantUML fenced code blocks are rendered server-side via Kroki. The resulting PNG is cached locally using a SHA-256 hash of the diagram source, so unchanged diagrams are not re-fetched.

By default the public instance at https://kroki.io is used. If your network blocks it, run a local instance with Docker Compose:

docker-compose.yml

services:
  kroki:
    image: yuzutech/kroki
    environment:
      - KROKI_MERMAID_HOST=mermaid
    ports:
      - "8000:8000"
    depends_on:
      - mermaid
  mermaid:
    image: yuzutech/kroki-mermaid
    expose:
      - "8002"
docker compose up -d
go run . -i report.md -kroki http://localhost:8000 -o projektarbeit.pdf

Note: The base yuzutech/kroki image does not include a Mermaid renderer. The companion yuzutech/kroki-mermaid container is required, wired via KROKI_MERMAID_HOST=mermaid.


YAML Front Matter

Every input file begins with a YAML block delimited by ---. All fields are optional except where noted.

---
student:
  name: "Max Mustermann"                                    # required
  profession: "Fachinformatiker Fachrichtung Anwendungsentwicklung"
  company: "Musterfirma GmbH"
  supervisor: "Sabine Supervisor"

project:
  title: "Titel der Projektarbeit"                         # required
  subtitle: "Optionaler Untertitel"                        # optional
  period: "Sommer 2026"

abbreviations:                                             # optional → Abkürzungsverzeichnis
  - abbr: "API"
    meaning: "Application Programming Interface"
  - abbr: "IHK"
    meaning: "Industrie- und Handelskammer"

glossary:                                                  # optional → Glossar (after appendices)
  - term: "Goldmark"
    definition: "Ein CommonMark-konformer Markdown-Parser für Go."
---

Document Structure

The generated PDF follows the mandatory IHK Chemnitz order:

# Section Page Numbering
1 Title page none
2 Table of contents Roman (II, III, …)
3 Abbreviation list Roman (from YAML, optional)
4 Foreword / front-matter sections Roman
5 Main body chapters Arabic (1, 2, …)
6 Bibliography Arabic
7 List of tables Arabic
8 List of figures Arabic
9 Appendices Arabic
10 Glossary Arabic (from YAML, optional)
11 Declaration of authenticity none

Front-matter detection

Level-1 headings named Vorwort, Einleitung, or Abkürzungsverzeichnis stay in the Roman-numbered front matter. Every other level-1 heading triggers the switch to Arabic numbering.


DIN 5008 / IHK Formatting Rules

Property Value
Paper A4
Left margin 30 mm
Right margin (Korrekturrand) 40 mm
Top margin 20 mm
Bottom margin 25 mm
Body font Helvetica (Arial) 12 pt, black
Body line spacing 1.5× → 6.35 mm
Heading font Helvetica Bold 14 pt
Caption / footnote Helvetica 10 pt
List line spacing 1.2× → 5.0 mm
Alignment Justified (Blocksatz)
Page number position Centered at bottom

Directives

Directives are plain paragraphs starting with @. They are consumed by the parser and never appear in the PDF as raw text. Multiple directives may appear in a single paragraph, one per line.


@Quelle: — Bibliography entry

@Quelle: Autor, Titel, Verlag, Jahr

Registers a bibliography entry. All entries are collected and rendered alphabetically at the end of the document in the Literaturverzeichnis. May appear anywhere in the document, any number of times.


@Tabelle: — Named table

Place immediately before a Markdown table to assign it a name and record it in the Tabellenverzeichnis:

@Tabelle: Übersicht der Programmiersprachen

| Sprache | Paradigma | Typsystem |
|---------|-----------|-----------|
| Go      | Imperativ | Statisch  |
| Python  | Multi     | Dynamisch |

@TabelleAnhang: — Table as portrait appendix

Sends the following table to the appendix on a portrait A4 page as a numbered Anlage:

@TabelleAnhang: Vollständige Fehlerliste

| Code | Beschreibung       | Schwere  |
|------|--------------------|----------|
| E001 | Datei nicht gefunden | Kritisch |

@TabelleAnhangQuer: — Table as landscape appendix

Same as @TabelleAnhang: but placed on a landscape A4 page (297 × 210 mm, 15 mm symmetric margins). Use for wide tables that do not fit in portrait:

@TabelleAnhangQuer: Breite Vergleichsmatrix

| Kriterium | Option A | Option B | Option C | Option D |
|-----------|----------|----------|----------|----------|
| Leistung  | Gut      | Sehr gut | Befriedigend | Gut  |

@Anhang: — Image as portrait appendix

@Anhang: Netzwerkdiagramm | diagrams/network.png

Adds an image file as a numbered Anlage on a portrait appendix page. The format is Title | relative/path/to/image.


@AnhangBildQuer: — Image as landscape appendix

@AnhangBildQuer: Großes Architekturdiagramm | diagrams/arch.png

Same as @Anhang: but placed on a landscape A4 page. Useful for wide images.


@AnhangUML: — Diagram as portrait appendix

Renders the immediately following Mermaid or PlantUML code block via Kroki and places the result as a numbered Anlage on a portrait appendix page:

@AnhangUML: Datenbankschema

` ``plantuml
@startuml
entity User {
  + id : int
  + name : string
}
@enduml
` ``

@AnhangUMLQuer: — Diagram as landscape appendix

Same as @AnhangUML: but placed on a landscape A4 page with 15 mm symmetric margins. Use for complex diagrams that need more horizontal space:

@AnhangUMLQuer: Vollständige Modulübersicht

` ``mermaid
graph TD
    A --> B --> C
` ``

@DiagrammQuer: — Inline landscape diagram page

Renders the following diagram on a dedicated landscape page inline in the document (not in the appendix). A figure caption is added and the figure is recorded in the Abbildungsverzeichnis. A fresh portrait page opens automatically afterwards:

@DiagrammQuer: Systemarchitektur  Zwei-Pass-Rendering

` ``mermaid
graph LR
    MD[report.md] --> Parser --> AST --> Renderer --> PDF
` ``

Directive Summary Table

Directive Format Placement Orientation
@Quelle: @Quelle: Text Inline anywhere
@Tabelle: @Tabelle: Name Before a table
@TabelleAnhang: @TabelleAnhang: Name Before a table Portrait appendix
@TabelleAnhangQuer: @TabelleAnhangQuer: Name Before a table Landscape appendix
@Anhang: @Anhang: Title | path Standalone Portrait appendix
@AnhangBildQuer: @AnhangBildQuer: Title | path Standalone Landscape appendix
@AnhangUML: @AnhangUML: Title Before diagram block Portrait appendix
@AnhangUMLQuer: @AnhangUMLQuer: Title Before diagram block Landscape appendix
@DiagrammQuer: @DiagrammQuer: Caption Before diagram block Landscape inline page

File Structure

.
├── main.go              # Entry point, CLI flags, two-pass pipeline
├── config.go            # Config struct matching the YAML front matter
├── markdown_parser.go   # Goldmark AST walker, directive handling
├── pdf_renderer.go      # IHKRenderer struct, DIN 5008 constants, appendix registry
├── pdf_content.go       # Paragraphs, lists, tables, images, code blocks
├── pdf_toc.go           # TOC, list of tables, list of figures
├── pdf_pages.go         # Title page, declaration, bibliography, appendices, glossary
├── pdf_numbering.go     # Roman/Arabic page numbering helpers
├── diagram.go           # Kroki HTTP client, SHA-256 image cache
├── docker-compose.yml   # Local Kroki + kroki-mermaid containers
└── report.md            # Sample document demonstrating all features

Two-Pass Rendering

The tool renders the document twice:

  1. Pass 1 — full render into a scratch PDF to collect the page number of every heading, table, and figure.
  2. Pass 2 — final render using the TOC index from pass 1, producing the output PDF.

Only tocItems are transferred between passes. tableItems and figureItems are rebuilt during pass 2 to avoid duplicates in the respective lists.


Landscape Pages — Technical Notes

  • Landscape appendices and @DiagrammQuer: use fpdf.AddPageFormat("L", {Wd:297, Ht:210}) with 15 mm symmetric margins. No 40 mm Korrekturrand — examiners do not annotate diagram or data pages.
  • After any landscape page, AddPage() reverts to the default portrait orientation (A4 "P") set at construction time — no explicit orientation restore is needed for subsequent content.
  • Portrait margins (30/20/40 mm) are restored immediately after the landscape page is closed so all following content is formatted correctly.

License

MIT

S
Description
No description provided
Readme 48 MiB
Languages
Go 100%