22.11.2013 Aufrufe

Aufgabe 6: Ein JPEG-Decoder

Aufgabe 6: Ein JPEG-Decoder

Aufgabe 6: Ein JPEG-Decoder

MEHR ANZEIGEN
WENIGER ANZEIGEN

Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.

YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.

¥¤<br />

¡<br />

<br />

©¨<br />

£¢<br />

<br />

§¦<br />

<strong>Aufgabe</strong> 6: <strong>Ein</strong> <strong>JPEG</strong>-<strong>Decoder</strong><br />

<strong>Ein</strong>leitung<br />

<strong>JPEG</strong> ist ein populärer Standard zur Kompression von Bildern. Neben verlustfreien Kompressionsalgorithmen<br />

werden auch verlustbehaftete benutzt. Bei diesen wird die besondere Struktur von Bildern<br />

so ausgenutzt, daß der Informationsverlust der Kompression dem menschlichen Betrachter nur wenig<br />

auffällt. <strong>JPEG</strong> is nach seinen Schöpfern benannt, der Joint Photographic Expert Group.<br />

In <strong>JPEG</strong> werden verschiedene Techniken kombiniert: Huffman-Kodierung, Quantisierung, Fourier-<br />

Transformation, Differentielle Kodierung und andere.<br />

Ziel dieser <strong>Aufgabe</strong> ist es, ein C-Programm zu schreiben, welches eine <strong>JPEG</strong>-Datei der einfachsten<br />

und häufigsten Art (nicht-differentielle Huffman-Kodierung, drei Farbebenen, keine Zusatzfunktionen)<br />

dekodiert und dekomprimiert. Als Ergebnis soll eine Datei im PPM (portable pixmap)-Format erzeugt<br />

werden.<br />

Digitalisierte Bilder: das PPM-Format<br />

<strong>Ein</strong> digitalisiertes Bild besteht aus einzelnen Bildpunkten, Pixel genannt. PPM ist eine ”naive”Form der<br />

Speicherung dieser Pixel ohne jegliche Komprimierung oder Umordnung der Daten. <strong>Ein</strong>e PPM-Datei<br />

beginnt mit einer Kennung. Das ist eine Zeile, die nur aus den 2 Zeichen ”P6” besteht. Es folgt eine<br />

Zeile, die aus 2 Zahlen besteht, der Breite w und Höhe h des Bildes in Pixel ( z.B. ”608 320”) und eine<br />

weitere Zeile, die für unsere Zwecke nur aus der Zahl ”255” besteht. An diese 3 Zeilen schließt sich ein<br />

Strom von 3 ∗ w ∗ h Bytes an. Jeweils 3 Bytes kodieren Farbe und Helligkeit eines Pixels. Dazu wird<br />

jedes Byte als vorzeichenlose ganze Zahl zwischen 0 und 255 interpretiert. Die 3 Zahlen beschreiben<br />

die Intensität des Rot-, Grün- und Blauanteils (RGB-Kodierung): (0, 0, 0) ist Schwarz, (255, 255, 255)<br />

Weiß, (230, 230, 0) ein helles Gelb etc. Die Pixeldaten stehen einfach ”in Leserichtung” (Zeile für Zeile<br />

von links nach rechts und oben nach unten) hintereinander.<br />

Huffman-Kodierung<br />

Die Huffman-Kodierung ist ein verlustfreier Kompressionsalgorithmus. <strong>Ein</strong> Alphabet soll so kodiert<br />

werden, daß die häufigere Zeichen durch kürzere Bit-Sequenzen dargestellt werden (ein Prinzip, von<br />

dem sich schon Samuel Morse bei der Erfindung seines Morsealphabets leiten ließ).<br />

Wie bei wohl allen Kompressionsalgorithmen ist das Entpacken wesentlich einfacher als das Packen.<br />

Letzteres erfordert eine umfangreiche Analyse der Input-Daten, ersteres bloß das Anwenden eines mitgelieferten<br />

Rezeptes.<br />

Das Rezept zur Huffman-Dekodierung läßt sich am einfachsten in Form einer Baumstruktur kodieren.<br />

Nehmen wir als Beispiel die Sprache ”Vokalisch”, deren Alphabet die 5 Buchstaben A,E,I,O,U umfaßt.<br />

Der häufigste Buchstabe sei E, gefolgt von O,A,I und U.<br />

0 1<br />

E<br />

A<br />

0<br />

<br />

U<br />

0 1<br />

0<br />

1<br />

1<br />

I<br />

O<br />

Der Datenstrom 101111101000 wird mit Hilfe des Huffman-Baums<br />

so dekodiert: Wir starten an der Wurzel des Baumes (wie in der<br />

Informatik üblich, steht der Baum auf dem Kopf) und nehmen die<br />

Bitfolge als Wegbeschreibung: 0 heißt den linken Weg nehmen, 1 den<br />

rechten Weg nehmen. Wenn wir eine Zweigspitze erreicht haben, steht<br />

ein Buchstabe fest und wir beginnen wieder an der Wurzel. Damit<br />

führt uns 1011 zu I, 11 zu O und 1010 zu U, 0 zu E und 0 zu E:<br />

IOUEE.<br />

Obwohl wir es mit einem Code variabler Länge zu tun haben, ist kein spezielles Trennzeichen nötig.<br />

Natürlich ist die Kompression nicht optimal. Sie könnte verbessert werden, indem man Silben aus<br />

2 Buchstaben in den Huffman-Baum aufnimmt, dann Silben aus 3 Buchstaben etc.<br />

1


Der <strong>JPEG</strong>-Algorithmus verwendet mehrere Huffman-Bäume, allerdings auf recht indirekte Art und<br />

Weise.<br />

Beschreibung des <strong>JPEG</strong>-Formats<br />

Im Folgenden wird das <strong>JPEG</strong>-Format beschrieben, wobei die Kapitel dieser Beschreibung (Farbmodell,<br />

Downsampling, Quantisierung, Fourier-Transformation, Huffman-Dekodierung, Analyse der Datei) vom<br />

Dekompressor in umgekehrter Reihenfolge angewandt werden müssen.<br />

Farbmodell<br />

<strong>JPEG</strong> verwendet nicht das RGB-Farbmodell, sondern eines, das YUV genannt wird: 3 Zahlen beschreiben<br />

Helligkeit (Y), Blauanteil (U) und Rotanteil (V) eines Pixels. Die Umrechnung in RGB ist durch<br />

die lineare Transformation ⎛<br />

⎝ R ⎞ ⎛<br />

G ⎠ = ⎝ 1 0 ⎞ ⎛<br />

8<br />

5<br />

1 − 1 3<br />

− 4 ⎠ ⎝ Y ⎞<br />

5<br />

U ⎠<br />

B 1 2 0 V<br />

möglich.<br />

Implementierungshinweis: Die YUV-Werte, die man nach Fourier-Transformation und Dequantisierung<br />

aus den <strong>JPEG</strong>-Daten erhält, sind vorzeichenbehaftet, liegen zwischen -128 und 127.<br />

Dasselbe gilt auch für die RGB-Werte, die obige Transformation liefert. Manchmal können sie auch<br />

über diesen Bereich hinausschießen. Um sie z.B. mit der Funktion putc (die ihr Argument zu einem<br />

unsigned char konvertiert) korrekt in eine PPM-Datei ausgeben zu können, empfiehlt es sich:<br />

a) 128 zu addieren,<br />

b) zu testen, ob der Wert nun zwischen 0 und 255 liegt und kleinere Werte durch 0, größere durch<br />

255 zu ersetzen.<br />

Downsampling<br />

• Zentrales Objekt der Kompressionsalgorithmen ist eine ”data unit”. Dies ist eine 8 × 8-Matrix von<br />

Y-, U- oder V-Werten. Im einfachsten Fall beschreibt sie auch einen Bildausschnitt von 8 × 8<br />

Pixeln. Durch eine (verlustbehaftete) Kompressionsmethode namens ”Downsampling” kann sie<br />

jedoch auch die Informationen für bis zu 32×32 Pixel enthalten. Dabei wird jeweils ein kleiner (z.B.<br />

2×2) Block von Pixeln durch ein ”gemitteltes”Pixel ersetzt. Üblicherweise wird das Downsampling<br />

nicht auf die Helligkeit (Y) angewendet, sondern nur auf die Farbkomponenten. Dadurch bleibt<br />

der wahrnehmbare Qualitätsverlust gering.<br />

• Für jede der 3 Farbkomponenten YUV wird das Downsampling beschrieben durch 2 Parameter<br />

(h, w) (height, width): Blöcke aus h × w Pixel wurden duch einen Pixel ersetzt. h und w können<br />

Werte zwischen 1 und 4 annehmen. Beim Entpacken muß also ein ”Upsampling” durchgeführt<br />

werden, bei dem die 8 × 8-Matrix zu einer( 8h × 8w-Matrix ) aufgebläht wird, indem man jeden<br />

<strong>Ein</strong>trag x durch eine h × w-Blockmatrix x x<br />

ersetzt. Für die Downsampling-Parameter<br />

h Y , h V , h U muß gelten kgV(h i ) = max(h i ) und kgV(w i ) = max(w i ). ∗<br />

x<br />

• Das Bild wird in kleine Rechtecke aus (8∗max(h i )×8∗max(w i )) Pixel zerlegt, die MCUs (Minimal<br />

Coding Units) genannt werden. Nehmen wir an, die Y-Information wird nicht ”downsampled”und<br />

die U- und V-Komponente werden um die Faktoren 2×2 bzw 4×4 ”downsampled”. Dann beschreibt<br />

eine MCU 32 × 32 Pixel des Bildes und sie ist kodiert durch 16 Y-data-units, 4 U-data-units und<br />

eine V-data-unit. In genau dieser Reihenfolge sind sie auch im Datenstrom gespeichert, wobei die<br />

16 Y-data-units (und 4 U-data-units) in ”Lesereihenfolge” zeilenweise von links nach rechts und<br />

oben nach unten abgespeichert sind.<br />

x<br />

∗ kgV: kleinstes gemeinsames Vielfaches. Dies bedeutet einfach, daß die elementaren Quadrate oder Rechtecke, in die das<br />

Bild für die verschiedenen Farbkomponenten zerschnitten wird, ”ineinander aufgehen” müssen.<br />

2


• Der Datenstrom, der das Gesamtbild beschreibt, besteht aus einer Folge von MCUs<br />

([16Y, 4U, 1V ], [16Y, 4U, 1V ], . . .), ebenfalls in ”Lesereihenfolge”.<br />

• Nach der Dekomprimierung hat man ein Bild, dessen Größe ein Vielfaches der MCU-Größe ist.<br />

Um es auf die Größe (H, W ) des Originals zu bringen, muß man eventuell rechts und unten ein<br />

paar Pixel wegschneiden.<br />

Fourier-Transformation und Quantisierung<br />

Der Schlüssel zur hohen Kompressionsrate von <strong>JPEG</strong> ist, daß die Bilddaten nicht direkt komprimiert,<br />

sondern vorher Fourier-transformiert werden. Die verwendete spezielle Form der Fourier-Transformation<br />

wird als ”Diskrete Cosinus-Transformation” (DCT) bezeichnet. Die DCT führt eine 8 × 8-Matrix von<br />

Farbwerten in eine 8 × 8-Matrix über, deren [0, 0]-Komponente den Mittelwert der Originaldaten beschreibt,<br />

die anderen beschreiben die Amplituden der verschiedenen Schwankungen um diesen Wert.<br />

Zur Rücktransformation sind folgende Schritte nötig:<br />

• Die <strong>JPEG</strong>-Datei enthält für jede Komponente (Y, U und V) eine Quantisierungstabelle aus 64<br />

ganzen Zahlen. Jede der 64 Zahlen du[i], i=0...63 einer data-unit ist mit der entsprechenden<br />

Zahl aus der Quantisierungstabelle zu multiplizieren. Das Ergebnis ist in Fließkommazahlen<br />

umzuwandeln.<br />

• Aus diesen 64 Zahlen wird jetzt eine 8 × 8-Matrix aufgebaut. Um eine optimale Kompression<br />

zu erreichen, sind diese Zahlen allerdings nicht zeilen- oder spaltenweise angeordnet, sondern im<br />

Zigzag. Das folgende Codestück beschreibt die notwendige Umordnung:<br />

const int zigzag[8][8] ={ { 0, 1, 5, 6,14,15,27,28},<br />

{ 2, 4, 7,13,16,26,29,42},<br />

{ 3, 8,12,17,25,30,41,43},<br />

{ 9,11,18,24,31,40,44,53},<br />

{10,19,23,32,39,45,52,54},<br />

{20,22,33,38,46,51,55,60},<br />

{21,34,37,47,50,56,59,61},<br />

{35,36,48,49,57,58,62,63}};<br />

for(i=0; i


• Der DC-Baum dient nur zum <strong>Ein</strong>lesen des ersten Wertes du[0]:<br />

• Lese Bits vom Datenstrom und laufe durch den DC-Baum, bis eine Spitze erreicht ist. Der<br />

an dieser Spitze gespeicherte Wert s gibt die Anzahl der nun einzulesenden Bits an.<br />

• Die nächsten s Bits aus dem Datenstrom sind als positive ganze Zahl n zu interpretieren.<br />

• Diese Zahl wird in eine vorzeichenbehaftete Zahl konvertiert nach der Vorschrift<br />

m = extend(n, s)<br />

{ n if n ≥ 2<br />

s−1<br />

extend(n, s) =<br />

n + 1 − 2 s otherwise<br />

• Dieser Wert m ist nur dann gleich du[0], wenn es sich um die erste data-unit des Bildes zu<br />

einer Farbkomponente handelt. Sonst ist m die Differenz zum Wert du[0] der vorhergehenden<br />

data-unit derselben Farbkomponente.<br />

• Zur Dekodierung der übrigen 63 Werte wird der AC-Baum verwendet. Die an dessen Spitzen<br />

gespeicherten Bytes (Zahlen x zwischen 0 und 255) sind als zwei 4-Bit-Zahlen (”nibbles”)<br />

(r, s) = (x/16, mod (x, 16)) zu interpretieren. Die Dekodierung erfordert folgende Schritte:<br />

1. Lese Bits aus dem Datenstrom ein, bis eine Spitze (r, s) des AC-Baumes ereicht ist.<br />

2. Wenn r = s = 0, fülle die restlichen Felder von du[] mit Nullen, die data-unit ist fertig<br />

gelesen.<br />

3. Wenn r > 0 ist, werden die nächsten r Felder in du[] mit Nullen gefüllt.<br />

4. Dann werden die die nächsten s Bits aus dem Datenstrom gelesen und das Ergebnis von<br />

extend(n, s) wird in das nächste freie Feld von du[] gespeichert.<br />

5. Wiederhole 1.-4., bis alle Felder von du[] gefüllt sind.<br />

Aufbau einer <strong>JPEG</strong>-Datei<br />

<strong>Ein</strong>e <strong>JPEG</strong>-Datei besteht aus einer Folge von Segmenten verschiedenen Typs. Segmente beginnen mit<br />

2 Startbytes, die den Segmenttyp kodieren, gefolgt von 2 Bytes, die die Länge L des Segments (ohne<br />

die beiden Startbytes) angeben und von L − 2 Datenbytes. <strong>Ein</strong>e Ausnahme sind die Segmente ”Start<br />

of Image” (SOI) am Dateianfang und ”End of Image” (EOI) am Dateiende, sie bestehen nur aus den<br />

2 Bytes FFD8 (SOI) und FFD9 (EOI). In der folgenden Übersicht steht ein ∗ für ein Halbbyte (4 Bits),<br />

auch nibble genannt.<br />

SOI Start of Image<br />

FFD8<br />

EOI End of Image<br />

FFD9<br />

COM Comment<br />

FFFE ∗ ∗ ∗∗<br />

L<br />

L-2 Bytes<br />

Kommentartext<br />

DQT Define Quantization Table<br />

FFDB ∗ ∗ ∗∗ ∗∗ 64 Bytes . . . ∗∗ 64 Bytes L = 2 + 65 ∗ n<br />

L i 1 QT 1 i n QT n<br />

SOF Start of Frame<br />

FFC0 ∗ ∗ ∗∗ ∗∗ ∗ ∗ ∗∗ ∗ ∗ ∗∗ ∗∗ 3 Bytes . . . 3 Bytes L = 2 + 6 + 3 ∗ ne<br />

L cd H W ne Ebene 1 Ebene ne<br />

Jede Ebene hat den Aufbau ∗∗ ∗ ∗ ∗∗<br />

i e w h n qt<br />

4


DHT Define Huffman Table<br />

FFC4 ∗ ∗ ∗∗ ∗ ∗ 16 Bytes data . . . ∗ ∗ 16 Bytes data<br />

L tc th ns[i] tc th ns[i]<br />

L = 2 + 1 + 16 + ∑ 15<br />

i=0 ns[i] + . . . + 1 + 16 + ∑ 15<br />

i=0 ns[i]<br />

SOS Start of Scan<br />

FFDA ∗ ∗ ∗∗ ∗∗ 2 Bytes . . . 2 Bytes ∗ ∗ ∗ ∗ ∗∗ data<br />

L nc Komponente 1 Komponente nc 3 Bytes<br />

Jede Komponente hat den Aufbau ∗∗ ∗ ∗<br />

i c td ta<br />

Es gibt noch eine Reihe weiterer Segmente. Wenn Segmente mit den Kennungen FFC1, FFC2, FFC3,<br />

FFC5, FFC6, FFC7, FFC9, FFCA, FFCB, FFCC, FFCD, FFCE oder FFCF auftauchen, soll unser<br />

Entpacker abbrechen. Sie bedeuten, daß noch andere Kompressionsalgorithmen (differentielle arithmetische<br />

Kodierung, differentielle Huffman-Kodierung u.a.) angewendet wurden.<br />

Andere Segmente der Form<br />

FF∗∗ ∗ ∗ ∗∗<br />

L-2 Bytes<br />

können ignoriert werden. Sie könenn z.B. ”thumbnails” (”daumennagelgroße” Varianten des Bildes, die<br />

ein Programm zur Vorschau o.ä. verwenden kann) enthalten.<br />

Beschreibung der Segmente<br />

DQT <strong>JPEG</strong>-Dateien können bis zu 4 Quantisierungstabellen enthalten (auch wenn die hier besprochene<br />

Variante nur 3 verwendet). Sie können durch mehrere DQT-Segmente oder gemeinsam in einem<br />

DQT-Segment gespeichert sein. Die Anzahl der Tabellen in einem DQT-Segment läßt sich aus der Längenangabe<br />

L ableiten. Jede Tabelle hat eine Nummer i n . Die Tabelle selbst besteht aus 64 Bytes, von<br />

denen jedes eine Zahl zwischen 0 und 255 repräsentiert.<br />

Implementierungshinweis:<br />

int i;<br />

i=getc(filepointer);<br />

liest ein Byte korrekt in diesem Sinne (als Zahl zwischen 0 und 255) ein, weil getc() das eingelesene<br />

Byte als unsigned char interpretiert. Ebenso kann man die durch 2 Bytes kodierten Zahlen (wie<br />

die Längenangabe L) einlesen:<br />

int i,L;<br />

i=getc(filepointer);<br />

L=256*i+getc(filepointer);<br />

SOF<br />

<strong>Ein</strong> Frame enthält globale Informationen über das Bild.<br />

• dc (1 Byte) enthält die Farbtiefe (color depth). Für unsere Zwecke sollte sie 8 sein: Jeder Farbwert<br />

wird mit 8 Bit (einem Byte) kodiert.<br />

• H und W (je 2 Byte) geben die tatsächliche Größe des Bildes (Höhe und Breite in Pixeln) an.<br />

• ne (1 Byte) gibt die Anzahl der Farbkomponenten an. Unser Dekoder soll nur mit genau 3 Farbkomponenten<br />

umgehen können. Es gibt auch schwarzweiße <strong>JPEG</strong>-Dateien mit nur einer Farbkomponente.<br />

• Es folgen jeweils 3 Bytes für jede Farbkomponente. Sie enthalten eine Nummer i e und die Downsampling-Parameter<br />

w und h dieser Farbkomponente sowie die Nummer der Quantisierungstabelle<br />

n qt , die für diese Komponente zu verwenden ist. Es ist die Tabelle zu verwenden, für die i n = n qt<br />

gilt.<br />

5


¡<br />

!<br />

"<br />

!<br />

"<br />

!<br />

"<br />

!<br />

"<br />

!<br />

"<br />

#<br />

$<br />

#<br />

$<br />

#<br />

$<br />

#<br />

$<br />

#<br />

$<br />

#<br />

$<br />

§¦<br />

©¨<br />

DHT<br />

Implementierungshinweis: Aus diesen Daten läßt sich die Größe einer MCU sowie die<br />

Anzahl der MCUs berechnen. Hierbei ist daran zu denken, daß man aufrunden muß, wenn H<br />

oder W nicht durch die Höhe oder Breite einer MCU teilbar ist. Die ”nibbles” h und w lassen<br />

sich so einlesen:<br />

int x,h,w;<br />

x=getc(filepointer);<br />

w=x/16;<br />

h=x%16;<br />

• Für jede Farbkomponente Y,U und V werden 2 Huffman-Bäume benötigt, ein DC- und ein AC-<br />

Baum. Die Bäume können in einem odere mehreren DHT-Feldern beschrieben sein. Sie sind numeriert<br />

durch die nibbles tc und th. Wenn tc ungleich 0 ist, dient der Baum als AC-Baum, wenn<br />

tc gleich 0 ist, als DC-Baum. th ist seine Nummer.<br />

• Es folgt eine 16 Bytes lange Liste ns[]. Die Bytes geben an, wieviele Huffman-Kodes der Länge<br />

1 Bit, 2 Bit, . . . 16 Bit abgespeichert sind. (Für unseren Vokal-Beispielbaum hieße das ns =<br />

[1, 1, 1, 2, 0, . . .].) Danach folgt eine Liste der an den Zweigspitzen zu speichernden Daten, nach<br />

aufsteigender Länge der Kodes sortiert. Diese Liste ist somit ∑ 15<br />

i=0<br />

ns[i] Bytes lang.<br />

• Die Daten sind Bytes, Zahlen zwischen 0 und 255. Bei den AC-Bäumen werden sie später als 2<br />

nibbles interpretiert.<br />

• Diese Daten bestimmen einen Baum eindeutig, wenn er so konstruiert wird, daß der Abstand<br />

Spitze-Wurzel von links nach rechts zunimmt.<br />

B<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

¢£¤¥<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

A D E F G<br />

<br />

%% && ''' (((<br />

<br />

&& ''' ((( %%<br />

%% && ((( '''<br />

((( ''' && %%<br />

%% && ((( )) ** '''<br />

)) ** ((( ''' && %%<br />

C<br />

** ))<br />

)) **<br />

** ))<br />

H<br />

++ ,,<br />

,, ++<br />

++ ,,<br />

,, ++<br />

.. /// 000 --<br />

++ ,,<br />

,, -- .. /// 000 ++ <br />

-- .. 000 ///<br />

000 /// .. --<br />

<strong>Ein</strong> Beispiel: Sei ns = [0, 1, 5, 1, 1] und die 8 Bytes<br />

in diesem Baum sind in der Reihenfolge BADEFG-<br />

CH gegeben. Damit sind die Huffman-Kodes B=00,<br />

A=010, D=011, E=100, F=101, G=110, C=1110,<br />

H=11110. Die letzte Spitze bleibt leer.<br />

Implementierungshinweis: Material zu Bäumen und anderen Datenstrukturen findet man<br />

z.B. in R. Sedgewick, Algorithmen in C. <strong>Ein</strong>e Möglichkeit ist, einen Knoten des Baumes als<br />

Struktur mit Zeigern auf die Unterknoten zu definieren und den Baum gemäß den DHT-Daten<br />

durch Aufrufe von createNode zu erzeugen. Dies kann z.B. auch rekursiv geschehen.<br />

struct node { unsigned char Item; struct node *l; struct node *r; };<br />

struct node * createNode(unsigned char a){<br />

struct node * x = malloc(sizeof(struct node));<br />

x->l=0;<br />

x->r=0;<br />

x->Item=a;<br />

return x;<br />

}<br />

SOS Das eigentliche Datenfeld. Bevor es losgeht mit dem Strom Huffman-kodierter und komprimierter<br />

MCUs, folgen nochmal Daten über die Farbkomponenten. Im nc-Byte steht nochmal deren Anzahl, dann<br />

folgt für jede Komponente ein 2-Byte-Feld, das aus 3 Zahlen besteht: einem Index i c und den Nummern<br />

td und ta der für diese Komponente zu verwendenden DC- und AC-Huffmanbäume. Die Daten mit dem<br />

Index i c ergänzen die Daten aus dem SOF-Segment mit dem gleichen Index i e .<br />

Es folgen noch 3 Bytes, deren Inhalt für die hier beschriebene <strong>JPEG</strong>-Variante irrelevant ist.<br />

Beim <strong>Ein</strong>lesen des folgenden Datenstroms ist eine Besonderheit zu beachten: Er endet, wenn ein neuer<br />

Segment-Markierer kommt, d.h., ein FF-Byte gefolgt von einem Byte ungleich 0. In der Regel wird das<br />

der EOI-Marker FFD9 und auch das Ende der Datei sein.<br />

Nun können solche Sequenzen natürlich auch als Teil der Bilddaten entstehen. Deshalb gilt eine<br />

Sonderregel: Wenn die Bilddaten ein FF-Byte enthalten, wird ihm ein zusätzliches 00-Byte angehängt.<br />

Dieses 00-Byte ist nicht Teil der Bilddaten und muß beim <strong>Ein</strong>lesen herausgefiltert werden.<br />

6

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!