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 Bilder erwähnt, können wir die Daten mit Hexadezimalschreibweise umschreiben. Die Schreibweise ist, wie gesagt, identisch wie bei 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.

Diskussion

Geben Sie Ihren Kommentar ein. Wiki-Syntax ist zugelassen:
U U B D K
 
grundlagen/dateien/binaere_streams.txt · Zuletzt geändert: 2013/04/22 15:08 (Externe Bearbeitung)
 
Falls nicht anders bezeichnet, ist der Inhalt dieses Wikis unter der folgenden Lizenz veröffentlicht: CC0 1.0 Universal
Recent changes RSS feed Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki