PDF: Font-Fallback für Emoji und Sonderzeichen - 2070 Missing-character-Faelle behoben
This commit is contained in:
parent
9b461426fc
commit
abc7a5693f
8 changed files with 198 additions and 1 deletions
|
|
@ -29,6 +29,11 @@ bilder_04/ Quelle: Diagramme + erzeuge_*.py-
|
|||
web_04/ Quelle: site.css, site.js, icons.svg,
|
||||
plotly.min.js, katex/ - die statischen
|
||||
Bestandteile der Website
|
||||
pandoc/, pandoc-defaults-basis.yaml, pandoc-defaults-buch.yaml PDF-Konfiguration
|
||||
(pandoc/emoji_fallback.lua schaltet Zeichen,
|
||||
die Times New Roman fehlt, auf Symbola um -
|
||||
siehe PROGRESS.md, "Sonderzeichen in der
|
||||
PDF-Fassung")
|
||||
Operations_Research_mit_Python_Version_04.md generiert: Gesamtdokument
|
||||
Operations_Research_mit_Python_Version_04.pdf generiert: PDF (xelatex)
|
||||
OR_HTML_04/ generiert: Mehrseiten-Website
|
||||
|
|
|
|||
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
BIN
OR_HTML_04/Operations_Research_mit_Python_Version_04.pdf
generated
Binary file not shown.
Binary file not shown.
|
|
@ -1194,6 +1194,21 @@ def baue_pdf() -> None:
|
|||
print(f"PDF wurde nicht erzeugt - LaTeX-Protokoll in "
|
||||
f"{BUILD_BASISNAME}.log pruefen.")
|
||||
|
||||
# Bewachung des Sonderzeichen-Fallbacks: xelatex verschweigt fehlende
|
||||
# Glyphen im Druckbild (nur "Missing character" im Protokoll). Der Filter
|
||||
# pandoc/emoji_fallback.lua deckt die bekannten Zeichen ab; taucht hier
|
||||
# eine Zahl auf, kennt Times New Roman ein Zeichen, das der Filter noch
|
||||
# nicht umschaltet - Zeichenliste im Filter ergaenzen.
|
||||
protokoll = os.path.join(BASIS, BUILD_BASISNAME + ".log")
|
||||
if os.path.exists(protokoll):
|
||||
with open(protokoll, encoding="utf-8", errors="replace") as datei:
|
||||
fehlend = sum(1 for zeile in datei if "Missing character" in zeile)
|
||||
if fehlend:
|
||||
print(f" WARNUNG: {fehlend} fehlende Zeichen im LaTeX-Protokoll "
|
||||
f"(pandoc/emoji_fallback.lua erweitern)")
|
||||
else:
|
||||
print(" Kein fehlendes Zeichen - Font-Fallback deckt alles ab.")
|
||||
|
||||
for endung in (".tex", ".aux", ".log", ".out", ".toc", ".idx", ".ind", ".ilg"):
|
||||
pfad = os.path.join(BASIS, BUILD_BASISNAME + endung)
|
||||
if os.path.exists(pfad) and endung != ".log":
|
||||
|
|
|
|||
39
PROGRESS.md
39
PROGRESS.md
|
|
@ -2592,6 +2592,45 @@ eine **doppelte Nummer** — „Abbildung 21: Abb. 7.2: …". Die erste vergibt
|
|||
`nummeriere_marken()`. Das betrifft alle 48 Abbildungen und besteht seit Langem; behoben wäre
|
||||
es dadurch, dass die LaTeX-Nummerierung der Gleitumgebung unterdrückt wird.
|
||||
|
||||
### Sonderzeichen in der PDF-Fassung — ein stiller Font-Fehler behoben ✅
|
||||
|
||||
In der gesamten PDF-Fassung fehlten alle Zeichen, die Times New Roman nicht mitbringt: die
|
||||
Lernelemente-Symbole (⭐ ✏ ❓ 🎯 🚀 …), aber auch die Sub-/Superskripte (₀ ₁ ₂ ₜ ₙ ⁶ ᵀ) und die
|
||||
langen Pfeile (⟹ ⟶ ⟵ ⇒). Das alte LaTeX-Protokoll enthielt **rund 2 070**
|
||||
`Missing character`-Meldungen; die Zeichen fielen stillschweigend aus dem Druckbild.
|
||||
Zwei Ursachen, beide lange unentdeckt, weil die Website die Zeichen korrekt zeigt
|
||||
(der Browser weicht selbst auf eine Emoji-Schrift aus):
|
||||
|
||||
* xelatex hat keine automatische Font-Fallback-Kette — fehlt einem Zeichen der Glyph, wird
|
||||
es weggelassen, ohne dass der Bau fehlschlägt.
|
||||
* Die pandoc-Variable `emoji-font: "Noto Color Emoji"` wertet der LaTeX-Writer
|
||||
(pandoc 3.1.3) **nicht aus** — sie hat seit ihrer Einführung still nichts getan.
|
||||
|
||||
**Die Lösung ist zweistufig**, weil die Zeichen auf zwei Wegen in den PDF gelangen:
|
||||
|
||||
1. **`pandoc/emoji_fallback.lua`** (neu) — ein pandoc-Filter, der die betreffenden Zeichen
|
||||
im Fließtext in `{\texorpdfstring{\symfont{…}}{…}}` einschüttet. `\symfont` ist
|
||||
**Symbola** — die einzige Schrift auf dem Bausystem, die das komplette Set abdeckt
|
||||
(Noto Color Emoji funktioniert unter XeTeX nicht: die Zeichen landen im `nullfont`);
|
||||
monochrom, für den Drucksatz ohnehin passend. Der `\texorpdfstring`-Antil hält die
|
||||
PDF-Lesezeichen ruhig und erhalten. Variationsselektoren (U+FE0F) werden entfernt.
|
||||
Zwei pandoc-3.1.3-Eigenheiten unterwegs gefunden: Filterhandler funktionieren **nur als
|
||||
globale Funktionen** — ein vom Filter zurückgegebenes Table wird stillschweigend
|
||||
ignoriert; und der Einschub muss `RawInline` sein, als `Str` würde pandoc die
|
||||
Backslashes escapen.
|
||||
2. **`ucharclasses`** in `pandoc/header-includes.tex` — für den **Diagrammtext**: Das Paket
|
||||
`svg` exportiert die SVG-Texte (x₁, σᵀ, ∈ in Achsen- und Knotenbeschriftungen) als
|
||||
LaTeX-Text, dorthin reicht der AST-Filter nicht. Die Zurück-Umschaltung ist bewusst
|
||||
`\fontfamily{\familydefault}\selectfont` statt `\normalfont` — `\normalfont` würde den
|
||||
Fettdruck hinter dem Stern einer Aufgabentitel-Zeile zerstören (gemessen mit
|
||||
pdfminer: „Titel“ bleibt Bold).
|
||||
|
||||
Die tote `emoji-font`-Variable ist aus `pandoc-defaults-basis.yaml` entfernt (mit
|
||||
Begründung), und `baue_pdf()` zählt die `Missing character`-Meldungen im Protokoll:
|
||||
Der neue Lauf meldet **null fehlende Zeichen**; taucht die Warnung wieder auf, kennt Times
|
||||
New Roman ein Zeichen, das der Filter noch nicht umschaltet. Symbola ist damit eingebettet,
|
||||
der Buchumfang bleibt bei 792 Seiten; alle HTML-Seiten sind byteidentisch geblieben.
|
||||
|
||||
---
|
||||
|
||||
## 8. Commit-Historie des V04-Strangs
|
||||
|
|
|
|||
|
|
@ -39,6 +39,15 @@ metadata:
|
|||
include-in-header:
|
||||
- pandoc/header-includes.tex
|
||||
|
||||
# Sonderzeichen, die Times New Roman fehlen (Emoji, Lernelemente-Symbole,
|
||||
# Sub-/Superskripte, lange Pfeile), auf \symfont (= Symbola, definiert in
|
||||
# pandoc/header-includes.tex) umschalten. Ohne diesen Filter liess xelatex
|
||||
# alle betreffenden Zeichen in der PDF-Fassung stillschweigend weg —
|
||||
# die Website zeigte sie, das PDF nicht. Nur für den PDF-Bau; der HTML-Bau
|
||||
# benutzt diese Defaults nicht.
|
||||
filters:
|
||||
- pandoc/emoji_fallback.lua
|
||||
|
||||
# --------------------------------
|
||||
# Fonts & Layout Variables
|
||||
# --------------------------------
|
||||
|
|
@ -48,7 +57,9 @@ variables:
|
|||
monofont: "DejaVu Sans Mono"
|
||||
# sansfont: "DejaVu Sans"
|
||||
sansfont: "Arial" # Sans-Serif
|
||||
emoji-font: "Noto Color Emoji"
|
||||
# "emoji-font" hier bewusst NICHT gesetzt: Die Variable wertet der
|
||||
# LaTeX-Writer (pandoc 3.1.3) nicht aus, sie hat jahrelang still nichts
|
||||
# getan. Die Emoji-Abdeckung läuft über pandoc/emoji_fallback.lua.
|
||||
mathfont: "STIX Two Math"
|
||||
monofontoptions: "Scale=MatchLowercase"
|
||||
papersize: a4
|
||||
|
|
|
|||
91
pandoc/emoji_fallback.lua
Normal file
91
pandoc/emoji_fallback.lua
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
-- emoji_fallback.lua
|
||||
-- Pandoc-Filter für den PDF-Bau (nur `-t latex`, nur PDF, nicht für die Website).
|
||||
--
|
||||
-- Problem: Der Haupttext steht in Times New Roman — diese Schrift kennt weder
|
||||
-- Emoji noch die Darstellungssymbole der Lernelemente (⭐ ✏ ❓ 🧠 …) und auch
|
||||
-- keine hoch-/tiefgestellten Ziffern. XeLaTeX besitzt keine automatische
|
||||
-- Font-Fallback-Kette: Fehlt einem Zeichen der Glyph, wird es stillschweigend
|
||||
-- weggelassen ("Missing character" nur im Protokoll). Die pandoc-Variable
|
||||
-- "emoji-font" wird vom LaTeX-Writer (pandoc 3.1.3) nicht ausgewertet — die
|
||||
-- Zeichen fehlten daher in der gesamten PDF-Fassung, während die Website sie
|
||||
-- über den Browser-Fontstack korrekt zeigte.
|
||||
--
|
||||
-- Lösung: Dieser Filter wickelt alle betreffenden Zeichen in
|
||||
-- {\texorpdfstring{\symfont{<Zeichen>}}{<Zeichen>}}
|
||||
-- ein. \symfont ist in pandoc/header-includes.tex auf Symbola gesetzt — die
|
||||
-- einzige auf dem Bausystem vorhandene Schrift, die das komplette Set abdeckt
|
||||
-- (Noto Color Emoji funktioniert unter XeTeX nicht, die Zeichen landen im
|
||||
-- nullfont). Symbola ist monochrom — für den Drucksatz ohnehin passend.
|
||||
--
|
||||
-- Der \texorpdfstring-Anteil hält hyperref ruhig: In PDF-Lesezeichen und im
|
||||
-- Inhaltsverzeichnis steht das schlichte Zeichen statt des Fontwechsels.
|
||||
--
|
||||
-- Codeblöcke werden nicht angetastet (Code/CodeBlock sind eigene
|
||||
-- AST-Elemente): Der Mono-Font DejaVu Sans Mono deckt die dort vorkommenden
|
||||
-- Symbole (✓ ✗ ★, Sub-/Superskripte) selbst ab.
|
||||
|
||||
local function braucht_symfont(cp)
|
||||
return (cp >= 0x1F000 and cp <= 0x1FAFF) -- Emoji-Blöcke (🎯 📌 🚀 …)
|
||||
or (cp >= 0x2600 and cp <= 0x27BF) -- Misc Symbols + Dingbats (★ ⚠ ✅ ✏ ✓ ✗ ❌ ❓)
|
||||
or (cp >= 0x2B00 and cp <= 0x2BFF) -- Misc Symbols and Arrows (⭐)
|
||||
or (cp >= 0x27F5 and cp <= 0x27FF) -- Supplemental Arrows-A (⟵ ⟶ ⟹)
|
||||
or (cp >= 0x2070 and cp <= 0x209F) -- hoch-/tiefgestellte Ziffern (⁶ ₀ ₁ ₂ ₜ ₙ)
|
||||
or cp == 0x21D2 -- ⇒
|
||||
or cp == 0x1D40 -- ᵀ (Modifier Letter Capital T)
|
||||
end
|
||||
|
||||
local function ersetze(text)
|
||||
local teile = {}
|
||||
local normal = {}
|
||||
local symbole = nil -- Puffer für aufeinanderfolgende Fallback-Zeichen
|
||||
|
||||
local function flush_normal()
|
||||
if #normal > 0 then
|
||||
teile[#teile + 1] = pandoc.Str(table.concat(normal))
|
||||
normal = {}
|
||||
end
|
||||
end
|
||||
|
||||
local function flush_symbole()
|
||||
if symbole and #symbole > 0 then
|
||||
local zeichen = table.concat(symbole)
|
||||
teile[#teile + 1] = pandoc.RawInline("latex",
|
||||
"{\\texorpdfstring{\\symfont{" .. zeichen .. "}}{"
|
||||
.. zeichen .. "}}")
|
||||
symbole = nil
|
||||
end
|
||||
end
|
||||
|
||||
for _, cp in utf8.codes(text) do
|
||||
if cp == 0xFE0F then
|
||||
-- Variationsselektor (Emoji- vs. Textdarstellung): für das PDF ohne
|
||||
-- Bedeutung, Symbola enthält keinen sichtbaren Glyphen — weglassen.
|
||||
elseif braucht_symfont(cp) then
|
||||
flush_normal()
|
||||
symbole = symbole or {}
|
||||
symbole[#symbole + 1] = utf8.char(cp)
|
||||
else
|
||||
flush_symbole()
|
||||
normal[#normal + 1] = utf8.char(cp)
|
||||
end
|
||||
end
|
||||
flush_normal()
|
||||
flush_symbole()
|
||||
|
||||
return teile
|
||||
end
|
||||
|
||||
-- pandoc 3.1.3 ruft Filterhandler ausschließlich als globale Funktionen auf;
|
||||
-- ein zurückgegebenes Handler-Table würde stillschweigend ignoriert.
|
||||
function Str(el)
|
||||
-- Schneller Ausstieg: nur anfassen, wenn überhaupt Multibyte drin ist.
|
||||
if not el.text:find("[\194-\244]") then
|
||||
return nil
|
||||
end
|
||||
local ok, teile = pcall(ersetze, el.text)
|
||||
if not ok then
|
||||
-- Kaputtes UTF-8 o. ä.: Element unverändert durchreichen.
|
||||
return nil
|
||||
end
|
||||
return teile
|
||||
end
|
||||
|
|
@ -2,5 +2,41 @@
|
|||
\setmonofont{DejaVu Sans Mono}[
|
||||
Scale=MatchLowercase
|
||||
]
|
||||
|
||||
% --- Symbol-/Emoji-Fallback ------------------------------------------------
|
||||
% Times New Roman (Haupttext) kennt weder Emoji noch die Symbole der
|
||||
% Lernelemente und keine hoch-/tiefgestellten Ziffern. XeLaTeX hat keine
|
||||
% automatische Fallback-Kette — fehlende Zeichen fielen stillschweigend weg.
|
||||
% Der Filter pandoc/emoji_fallback.lua schaltet die betreffenden Zeichen
|
||||
% deshalb auf \symfont um. Symbola ist die einzige Schrift auf dem
|
||||
% Bausystem, die das komplette Set abdeckt; Noto Color Emoji funktioniert
|
||||
% unter XeTeX nicht (die Zeichen landen im nullfont). Monochrom — für den
|
||||
% Drucksatz ohnehin passend.
|
||||
\newfontfamily\symfont{Symbola}
|
||||
|
||||
% --- Automatische Umschaltung für den Diagrammtext --------------------------
|
||||
% Die SVG-Diagramme werden vom Paket "svg" mit Inkscape nach LaTeX
|
||||
% exportiert; deren Texte (Achsenbeschriftungen, Knotenlabels wie x₁, σᵀ)
|
||||
% setzt LaTeX selbst — da erreicht der pandoc-Filter nicht mehr hin. Für
|
||||
% diese Ebene übernimmt ucharclasses die Umschaltung auf \symfont je
|
||||
% Unicode-Block. Die Zurück-Umschaltung ist bewusst
|
||||
% \fontfamily{\familydefault}\selectfont und NICHT \normalfont:
|
||||
% \normalfont würde auch Fettdruck und Kursiv zurücksetzen — "Aufgabe ⭐ —
|
||||
% Titel" wäre nach dem Stern nur noch mager. Im Fließtext schaltet der
|
||||
% pandoc-Filter bereits in geschlossenen Gruppen um; ucharclasses greift
|
||||
% dort nur innerhalb dieser Gruppen und bleibt unsichtbar.
|
||||
\usepackage[quiet]{ucharclasses}
|
||||
\setTransitionsFor{SuperscriptsAndSubscripts}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{PhoneticExtensions}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{MathematicalOperators}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{Arrows}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{SupplementalArrowsA}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{Dingbats}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{MiscellaneousSymbols}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{MiscellaneousSymbolsAndArrows}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{MiscellaneousSymbolsAndPictographs}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{Emoticons}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{TransportAndMapSymbols}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\setTransitionsFor{SupplementalSymbolsAndPictographs}{\symfont}{\fontfamily{\familydefault}\selectfont}
|
||||
\usepackage{microtype}
|
||||
\usepackage{pifont}
|
||||
|
|
|
|||
Loading…
Reference in a new issue