====== Binäre Streams ====== PDF ist grundsätzlich ein Textformat. Dementsprechend braucht es Sonderregeln, um binäre Daten einzubinden. Bei Strings mit binären Daten können wir Hexstrings verwenden, aber Dateien werden grundsätzlich als Streams eingebunden. PDF bietet hier gleich mehrere Möglichkeiten, das Dilemma zu lösen. ===== direktes Einbinden ===== Zwischen den Schlüsselwörtern ''stream'' und ''endstream'' darf grundsätzlich alles stehen, auch binäre Daten. Dies ist möglich, weil die Länge der Daten im dem Stream zugehörigen Dictionary festgehalten wurde. Der Interpreter weiss dadurch, dass er für die angegebene Menge Bytes die Daten einfach einlesen soll, ohne sich um etwaige nicht druckbare Zeichen zu kümmern. Folglich können binäre Daten also direkt in die Datei gepackt werden. Der Nachteil dieser Variante ist, dass man die erstellte PDF Datei nicht einfach in einem Texteditor betrachten kann. Dies ist aber enorm hilfreich bei der Fehlersuche. Darum schauen wir uns noch zwei weitere Methoden an. ===== Hexadezimalschreibweise ===== Wie im Kapitel über [[/grundlagen/seiteninhalt/bilder#der_stream|Bilder]] erwähnt, können wir die Daten mit Hexadezimalschreibweise umschreiben. Die Schreibweise ist, wie gesagt, identisch wie bei [[/grundlagen/aufbau_und_syntax/syntax#hexstrings|Hexstrings]] ohne die öffnende Klammer. Im Dictionary muss der Eintrag ''/Filter'' auf ''/ASCIIHexDecode'' gesetzt werden, um dem Interpreter mitzuteilen, dass er die Hexschreibweise in Binärcode umwandeln soll. Diese Methode ist simpel, und produziert Code, den jeder Editor leicht darstellen kann. Dummerweise brauchen wir aber für jedes Byte eingebetteter Daten zwei Zeichen, von denen jedes im PDF wiederum ein Byte benötigt. Das heisst, die Grösse der eingebetteten Daten innerhalb des PDFs wird verdoppelt. ===== ASCII85 ===== Dies ist eine andere Methode, um Binärcode in druckbare Zeichen umzuwandeln. Sie ist wesentlich effizienter als die Hexadezimalschreibweise, aber auch deutlich komplizierter. Um diesen Algorithmus verwenden zu können muss im Dictionary des Streams ''/Filter'' auf ''/ASCII85Decode'' gesetzt werden. ==== Konzept ==== Die Binärdaten werden in Gruppen von vier Bytes aufgeteilt. Jede dieser Gruppen wird als vorzeichenlose 32 Bit Zahl in Big-Endian Anordnung interpretiert. Der so ermittelte Wert wird wiederum in fünf Zahlen mit Wertebereich 0 - 84 aufgeteilt. Zu jeder dieser fünf Zahlen wird 33 addiert, wodurch sich der Bereich auf 33 - 117 verschiebt (hexadezimal 0x21 - 0x75), was gültigen ASCII-Zeichencodes entspricht. Da wir 4 Bytes mit 5 Zeichen darstellen, welche wiederum je ein Byte in der Datei benötigen, steigt die Grösse der eingebetteten Daten innerhalb des PDFs um 25%. Das ist in der Regel leicht verkraftbar. ==== die Mathematik ==== Wir verwenden hier die einfache Division mit ganzer Zahl und Rest als Ergebnis (statt einem Dezimalbruch). Wenn wir zum Beispiel 100 ÷ 85 rechnen, so wäre das Ergebnis 1 mit Rest 15. Um die fünf Zahlen zu erhalten, dividieren wir den Wert zunächst durch 85. Wir merken uns den Rest, und dividieren das eigentliche Resultat wiederum durch 85. Das wiederholen wir noch zwei mal, so dass wir nun 4 Restwerte und ein endgültiges Ergebnis haben. Das Ergebnis der letzten Division ist die erste Zahl. Der Rest der letzten Division ist die zweite Zahl. Der Rest der dritten Division ist die dritte Zahl. Der Rest der zweiten Division ist die vierte Zahl. Der Rest der ersten Divsion schliesslich ist die fünfte Zahl. Zu jeder dieser Zahlen addieren wir 33, und erhalten so einen gültigen ASCII-Zeichencode. Beispiel: ursprüngliche Bytes: 206 10 106 20\\ 32 Bit Wert: 3'456'789'012 3'456'789'012 ÷ 85 = 40'668'106 Rest 2 40'668'106 ÷ 85 = 478'448 Rest 26 478'448 ÷ 85 = 5'628 Rest 68 5'628 ÷ 85 = 66 Rest 18 Zahlen: 66 18 68 26 2\\ Codes: 99 51 101 59 35\\ Zeichen: c3e;# ==== Padding ==== Ein Problem, welches wir noch lösen müssen, stellt sich, wenn die Anzahl Bytes der Binärdaten nicht durch vier teilbar ist. In dem Fall haben wir am Schluss eine unvollständige Gruppe. Zunächst füllen wir diese Vierergruppe rechts mit Nullen auf. Danach berechnen wir normal unsere fünf Zahlen. Vom Ende dieser Fünfergruppe entfernen wir soviele Zahlen, wie wir vorher Nullen hinzugefügt haben. Zu den verbliebenen Zahlen addieren wir wie gehabt 33, um auf ASCII-Zeichencodes zu kommen. Beispiel: ursprüngliche Bytes: 206 10\\ aufgefüllte Bytes: 206 10 0 0\\ 32 Bit Wert: 3'456'761'856 3'456'761'856 ÷ 85 = 40'677'786 Rest 46 40'677'786 ÷ 85 = 478'444 Rest 46 478'444 ÷ 85 = 5'628 Rest 64 5'628 ÷ 85 = 66 Rest 18 Zahlen: 66 18 64 46 46\\ Zahlen gekürzt: 66 18 64\\ Codes: 99 51 97\\ Zeichen: c3a ==== der "z" Sonderfall ==== Besteht eine Vierergruppe aus 4 Nullen, so erhalten wir mit unserem Algorithmus ''!!!!!''. Sofern wir die Gruppe nicht mit Nullen auffüllen mussten, können wir auch ein einzelnes ''z'' einsetzen. Damit wird der Stream nochmals etwas kleiner. ==== Abschluss ==== An die kodierten Daten hängen wir noch ''~>''. Damit bestätigen wir dem Interpreter das Ende der Daten. ==== Leerschläge und Zeilenumbrüche ==== Leerzeichen und Zeilenumbrüche werden ignoriert. Da die Datei ja in einem Texteditor betrachtbar sein soll, lohnt es sich, in regelmässigen Abständen Zeilenumbrüche einzusetzen. Damit vermeiden wir überlange Zeilen. Eine gängige Methode ist es, alle 60 verarbeiteten Bytes einen Zeilenumbruch zu setzen, wodurch die Zeilen nie länger als 75 Zeichen werden. Beispiel: 10 0 obj << /Length 293 /Filter /ASCII85Decode >> stream <+ohcEHPu*CER),Dg-(AAoDo:C3=B4ARlp%G%G\:FD,5.CghX8+CoD'/g+,,AKYu8Bk(p$@WHC2 DBNP0GT^aDD/a&s+E)F7EZfI;AKYetH?gWDDeC[F<+ohcEHPu*CER),Dg-(AAoDo:C3=B4ARlp% G%G\:FD,5.CghX8+CoD'/g+,,AKYu8Bk(p$@WHC2DBNP0GT^aDD/a&s+E)F7EZfI;AKYetH?gWD DeC[F<+ohcEHPu*CER),Dg-(AAoDo:C3=B4ARlp%G%G\:FD,5.CghX8+CoD'/g(~> endstream endobj Dekodiert man dies, so erhält man den Text "The quick brown fox jumped over the lazy dog. " fünf mal hintereinander.