flying-saucer-pdf Font

bene2808

Aktives Mitglied
Hallo Leute,

ich versuche, mit flying-saucer-pdf aus einer HTML Datei, die Umlaute enthält, ein PDF zu generieren. Die Umlaute werden dabei weggelassen oder falsch dargestellt, z.B. ö statt ö. Das Problem ist anscheinend relativ bekannt (habe einige Posts dazu im Internet gefunden); aber keine einzige der vorgeschlagenen Lösungen hat bei mir funktioniert (z.B. auch nicht Definition über @font-face). Deswegen habe ich hier jetzt mal mein minimales nicht funktionierendes Beispiel angehängt. Könnt ihr das bitte ausprobieren und mir sagen, ob es bei euch geht? Bzw. mir sagen, was ich falsch mache? Danke! 😁

Grüße
 

Anhänge

  • Test.zip
    632,6 KB · Aufrufe: 2

KonradN

Super-Moderator
Mitarbeiter
Dein HTML ist schlicht falsch. Umlaute sind in HTML zu kodieren:

So müsste das ö als ö in der Datei stehen.

Wobei ich jetzt sogar vermuten würde, dass der Renderer damit hätte umgehen können, wenn das Encoding der Datei korrekt wäre. ö sieht etwas danach aus, dass die Datei im utf-8 Format vorliegt und es im Windows Format gelesen wurde. Man könnte also auch ausprobieren, dem FileReader als Encoding UTF-8 mitzugeben.

Spam, ich wette der Anhang enthält auch einen Virus.
Wie kommst Du darauf? Das zip File enthält ein minimales Beispiel als Gradle Projekt. Und die Frage ist auch ganz klar ein Problem, in Java aus einem HTML File ein PDF zu erzeugen.
 

Robert Zenz

Top Contributor
Ich kopiere nochmal kurz meine laengere Antwort von einem anderen Thema.

Wie wir alle wissen werden Dateien als Bytes gespeichert. Damit stellt sich natuerlich die Frage "Welcher Byte-Wert zwischen 0 und 255 soll das Zeichen A darstellen?". Der findige (und klugscheiszerische) Entwickler Antwortet natuerlich mit "65". Soweit so gut, aber was ist mit dem Zeichen "й"? Da scheiden sich die Geister...

Also das Encoding der Datei musst du verstehen als Mapping von Byte-Wert auf Zeichen, und da sich hier immer die Geister geschieden haben, gibt es davon viele Unterschiedliche. In der Zwischenzeit hat sich die Welt weitestgehend geeinigt das UTF-8 das Encoding der Wahl ist. Es ist kompatibel mit ASCII in den Wertden von 0-128, und kann bis zu vier Byte pro Zeichen verwenden. Also "й" wird gespeichert als die Bytes "208 185", quasi "zweite Seite, dieses Zeichen". Damit kann UTF-8 fast alle Sprachen und Zeichen problemlos abbilden. Jetzt betritt Microsoft die Buehne, Microsoft verwendet seit jeher ein ISO 8859-1 Derivat, naemlich CP-1252 (auch bekannt als Windows 1252), welches zwar auch in den Bytes 0-128 kompatibel ist zu ASCII (und damit zu UTF-8), aber darueber hinaus einfach gar nichts gemein hat. Zusaetzlich kann CP-1252 nicht mal annaehernd die Menge an Zeichen abbilden wie UTF-8.

Daraus ergibt sich die tolle Situation, dass Text welcher auf Windows Maschinen geschrieben wird, und mehr als Lateinische Zeichen enthaelt, einfach Kacke zum verarbeiten ist auf allem was nicht Windows ist (auch bekannt als: Der Rest der Welt). Und genau dieses Problem hast du jetzt.

Du willst deine JSON Dateien immer als UTF-8 speichern (im Zweifelsfall einen Editor holen der das kann, zum Beispiel Notepad++), und du willst beim lesen und schreiben in Java immer explizit das Charset auf UTF-8 setzen (StandardCharSets.UTF8. Dann hast du diese Probleme nicht mehr. Und du willst auch deine IDE umstellen, so das fuer Quellcode immer UTF-8 verwendet wird, und nicht der Plattform-Standard (in deinem Fall CP-1252).
 

bene2808

Aktives Mitglied
Dein HTML ist schlicht falsch. Umlaute sind in HTML zu kodieren:
Auf die Idee, dass man die Zeichen möglicherweise auch in der html umkodieren muss, hätte ich selbst kommen können; danke schon mal! :D
In dem Text heißt es aber ja, dass die "HTML-Umlaute nicht mehr von Hand in Zeichen wie beispielsweise „ umgewandelt werden" müssen, wenn ich UTF-8 im Header erwähne und das habe ich in meinem Beispiel ja gemacht. Wo genau hakt das dann wohl?🤔
Auf jeden Fall funktioniert der Ansatz, diese etwas längeren Zeichenketten zu verwenden; werde den jetzt weiter verfolgen!

Wobei ich jetzt sogar vermuten würde, dass der Renderer damit hätte umgehen können, wenn das Encoding der Datei korrekt wäre. ö sieht etwas danach aus, dass die Datei im utf-8 Format vorliegt und es im Windows Format gelesen wurde. Man könnte also auch ausprobieren, dem FileReader als Encoding UTF-8 mitzugeben.
Also ich hatte mir den geladenen Text auch mal auf die Konsole ausgegeben und da stand korrekt ein ö. Daraus kann man schließen, dass er korrekt eingelesen wurde oder?

Naja, mir kam das Thema einfach suspekt vor, weil anstatt Code nur ein Zip-File hochgeladen wurde... ignoriert mich. :D
Ich dachte mir schon, dass hier vielleicht wegen dem zip gepöbelt wird. Dachte nur, dass ich vielleicht auch irgendwo anders im Projekt noch was mit Zeichensätzen falsch konfiguriert habe und habe deswegen alles hochgeladen. ;)

@Robert Zenz Also ich glaube, dass ich vorher schon überall UTF-8 verwendet habe. Benutze IDEA auf Windows und habe so weit ich weiß nie eine Charset Einstellung umgestellt. Wenn ich die html offen habe, steht rechts unten "UTF-8". Unter File > Settings > Editor > File Encodings stand bei Project Encoding aber tatsächlich "windows-1252". Habe das mal auf UTF-8 geändert, bin mir aber nicht sicher, ob das jetzt wirklich auf das Projekt angewendet wurde...
 

KonradN

Super-Moderator
Mitarbeiter
Also bei Deinem Code liest Du die Datei im Default Encoding ein und das ist bei Windows dieses cp-1252. Daher ist diese Stelle anzupassen:
try (final var reader = new BufferedReader(new FileReader("source/test.html")))
zu etwas wie:
try (final var reader = new BufferedReader(new FileReader("source/test.html", StandardCharsets.UTF_8)))

(Im Forum geschrieben - Tippfehler sind also möglich.)

Du kannst es aber auch gerne erst einmal auf der Kommandozeile testen. Setz einfach mal dein Standard Charset um:
java -Dfile.encoding=UTF-8 ...

Wenn es dann funktioniert, dann sollte die angebotene Lösung funktionieren.
 

bene2808

Aktives Mitglied
Also bei Deinem Code liest Du die Datei im Default Encoding ein und das ist bei Windows dieses cp-1252. Daher ist diese Stelle anzupassen:
try (final var reader = new BufferedReader(new FileReader("source/test.html")))
zu etwas wie:
try (final var reader = new BufferedReader(new FileReader("source/test.html", StandardCharsets.UTF_8)))

(Im Forum geschrieben - Tippfehler sind also möglich.)

Du kannst es aber auch gerne erst einmal auf der Kommandozeile testen. Setz einfach mal dein Standard Charset um:
java -Dfile.encoding=UTF-8 ...

Wenn es dann funktioniert, dann sollte die angebotene Lösung funktionieren.
Ok jetzt bin ich baff... Wenn ich beim Lesen UTF-8 mit angebe, klappt das Generieren des PDFs tatsächlich auch mit ö. Wenn ich den gelesenen Text auf die Konsole ausgebe, wird das ö nur mit so einem ? Symbol dargestellt. Wenn ich ohne Angabe des Charsets lese, wird das PDF falsch aber auf der Konsole landet korrekt ein ö. Was genau passiert da under the hood, das zu diesem Ergebnis führt?😅
Anyway, keine Umlaute im HTML zu verwenden, sondern diese Sonder Zeichenketten, ist aber generell der bessere Approach oder? Es hieß ja überall, wenn man auf ganz sicher gehen will, nimmt man lieber die...
 

KonradN

Super-Moderator
Mitarbeiter
Ok jetzt bin ich baff... Wenn ich beim Lesen UTF-8 mit angebe, klappt das Generieren des PDFs tatsächlich auch mit ö. Wenn ich den gelesenen Text auf die Konsole ausgebe, wird das ö nur mit so einem ? Symbol dargestellt. Wenn ich ohne Angabe des Charsets lese, wird das PDF falsch aber auf der Konsole landet korrekt ein ö. Was genau passiert da under the hood, das zu diesem Ergebnis führt?😅
Anyway, keine Umlaute im HTML zu verwenden, sondern diese Sonder Zeichenketten, ist aber generell der bessere Approach oder? Es hieß ja überall, wenn man auf ganz sicher gehen will, nimmt man lieber die...
It's a kind of magic :)

Also mir fehlt die Beschreibung, was Du genau gemacht hast, daher muss ich raten. Du hast es einfach mal mit -D.... gestartet? Dann nutzt die Applikation generell UTF-8 - auch für den PrintStream auf System.out. Damit wird das "ö" als UTF-8 an die Konsole gegeben und diese kann das Ö nicht darstellen, da die Konsole halt als Charset cp-1252 erwartet. Daher das Problem mit der Ausgabe.

Nutzt Du die Anpassung im Code, dann wird nur die Datei als UTF-8 geladen. Bei der Ausgabe würde dann aber das Default Charset des Systems (CP-1252) genutzt, so dass alles wieder richtig angezeigt wird.

Das wäre so eine mögliche Erläuterung, die ich sehen würde.
 

bene2808

Aktives Mitglied
@KonradN Ich habe in der html das ö gelassen und einmal mit StandardCharsets.UTF_8 und einmal ohne gelesen. Ich habe nicht das Standard Charset per Konsolenparameter gesetzt.
Mich würde wirklich interessieren, was da intern genau passiert, weil Zeichensätze schon immer rätselhaft für mich waren... Also: Wenn ich so eine html Datei als UTF-8 speichere, dann werden die meisten Zeichen mit einem Byte dargestellt. Mein ö aber zum Beispiel mit 2. Habe mal Zeichenzahl und Speicher der Datei verglichen und das kommt hin. Wenn ich die Datei jetzt lese ohne ein Encoding anzugeben, wird das Standard Windows Encoding verwendet. Dieses Encoding erkennt die beiden Bytes des ö nicht als zusammenhängendes Zeichen, sondern liest die als zwei Zeichen ein (tatsächlich genau die Zeichen, die im fehlerhaften PDF rauskommen). Aber was genau passiert jetzt beim Printen, dass am Ende wieder ein korrektes ö rauskommt? Wenn der gelesene String so zu interpretieren ist, dass da jetzt zwei Zeichen drin sind, wie kann dann die Konsole davon ausgehen, dass die wieder zusammengefügt werden müssen? Also ein String ist ja kein zusammenhangloses Byte Array mehr. Ein String hat doch eine Semantik und sollte eindeutig einer bestimmten Zeichenkette in der "realen Welt" zugeordnet werden können. Wenn dann trotzdem die Konsole eine Interpretation (ö) und die PDF Bibliothek eine andere (ö) verwendet, muss da doch irgendwo was falsch sein... Habe gerade einen Knoten im Hirn...🥴
 

Ähnliche Java Themen

Neue Themen


Oben