Das PCX-Format

Referat von Oliver Pola

- PCX-Header
- Algorithmus zum Speichern
- Algorithmus zum Laden

Quelle: R. Steinbrecher: "Bildverarbeitung in der Praxis", Oldenbourg, Seite 273ff

Das PCX-Format wurde entwickelt von der Firma Zsoft-Corporation, USA. Es existieren die Versionen 0, 2, 3, 4 und 5. Version 0 war nur für zwei oder vier Farben geeignet, Version 2 unterstützte 16 Farben. Die aktuelle Version 5 verarbeitet auch 256 Farben aus 16,7 Millionen oder Echtfarben (24 Bit).
Die maximale Größe der Bilder im PCX-Format beträgt 65536 x 65536 Pixel. Es wird nur das RGB-Modell unterstützt und die Lauflängen-Kodierung angewendet.

Lauflängen-Kodierung (RLC):
Bei der Lauflängen-Kodierung werden aufeinander folgende gleiche Farbwerte in der Form kodiert, daß nur einmal der Farbwert und die Anzahl der Wiederholungen gespeichert wird.
Kennzeichen für die Lauflängen-Kodierung ist das setzen der beiden höchsten Bits. Die unteren 6 Bit geben dann die Anzahl (max. 63) der Wiederholungen, das folgende Byte den Farbwert an. Die Kodierung erfolgt für maximal eine Zeile.
Das bewirkt das Problem, daß Farbwerte >191 immer Lauflängen-kodiert werden, auch wenn der Farbwert nur einmal auftritt.

Header:

`Byte Anzahl Bezeichner Wert / Bedeutung`

`0 1 Hersteller 10 = Zsoft`
`1 1 Versionsnr. 0, 2, 3, 4 oder 5`
`2 1 Kodierung 1 = RLC`
`3 1 Bits pro Pixel 1, 2, 4 oder 8`
`4 8 Bildgröße X_Min, Y_Min, X_Max, Y_Max jeweils 2 Byte`
`12 2 horiz. Aufl. in dpi`
`14 2 vert. Aufl. in dpi`
`16 48 Header-Palette LUT für 16 oder weniger Farben`
`64 1 reserviert 0`
`65 1 Farbebenen 1-4`
`66 2 Bytes / Zeile / Farbebene` zur Ermittlung des benötigten Speichers
`68 2 Interpretation 1 = Farbe oder s/w, 2 = Grauwerte`
`70 2 horiz. Bildschirmgröße`
`72 2 vert. Bildschirmgröße`
`74 54 Leer bis Byte 128`

Angaben mit 2 Byte sind Integer-Werte.

Darauf folgen die Bildinformationen mit Bezug auf die Farbpalette oder zuerst Rot-Ebene dann Grün-Ebene dann Blau-Ebene.
Anschließend folgt, wenn benötigt, die 256-Farben-Palette mit 256 Farbtripeln (R,G,B), eingeleitet von einer dezimalen 12.

Die folgenden Algorithmen gehen davon aus, daß Version 5 mit Grauwerten, also 256 Farben, verwendet wird.

Algorithmus zur Speicherung

`1 unsigned char *bild; /* Adresse des Bildspeichers (Array) */`
`2 unsigned int bildzeilen; /* Anzahl der Zeilen/Spalten des Bildes */`
`3 unsigned int bildspalten;`
`4`
`5 Save_PCX()`
`6 {`
`7 int Z_Index, S_Index; /* PCX-Größenangaben */`
`8 unsigned char PCXHeader[128];`
`9 unsigned char LUT[768]; /* Farbpalette */`
`10 unsigned char Pixel;`
`11 unsigned char Anzahl;`
`12 int PCX_fd; /* File-Descriptor */`
`13 int i, j, z, s;`
`14 long Index; /* Adresse des Pixels im Bild */`
`15`
`16 ... Datei PCX_fd zum schreiben öffnen ...`
`17`
`18 /* PCX-Header erzeugen */`
`19 S_Index = bildspalten-1;`
`20 Z_Index = bildzeilen-1;`
`21`
`22 PCXHeader[0] = 10; /* Zsoft */`
`23 PCXHeader[1] = 5; /* Version 5 */`
`24 PCXHeader[2] = 1; /* RLC */`
`25 PCXHeader[3] = 8; /* Bits pro Pixel und Ebene */`
`26 PCXHeader[4] = 0; /* Xmin Low-Byte */`
`27 PCXHeader[5] = 0; /* Xmin High-Byte */`
`28 PCXHeader[6] = 0; /* Ymin Low-Byte */`
`29 PCXHeader[7] = 0; /* Ymin High-Byte */`
`30 PCXHeader[8] = S_Index-256*(S_Index/256); /* Xmax Low-Byte */`
`31 PCXHeader[9] = S_Index/256; /* Xmax High-Byte */`
`32 PCXHeader[10] = Z_Index-256*(Z_Index/256); /* Ymax Low-Byte */`
`33 PCXHeader[11] = Z_Index/256; /* Ymax High-Byte */`
`34 PCXHeader[12] = 0; /* X-Auflösung in dpi */`
`35 PCXHeader[13] = 0;`
`36 PCXHeader[14] = 0; /* Y-Auflösung in dpi */`
`37 PCXHeader[15] = 0;`
`38`
`39 /* Farbtabelle für 16 oder weniger Farben (nicht verwendet)*/`
`40 for(i=16; i<64; i++) PCXHeader[i] = 0;`
`41`
`42 PCXHeader[64] = 0; /* reserviert */`
`43 PCXHeader[65] = 1; /* Anzahl der Ebenen */`
`44 PCXHeader[66] = S_Index+1-256*((S_Index+1)/256); /* Bytes/Zeile */`
`45 PCXHeader[67] = (S_Index+1)/256;`
`46 PCXHeader[68] = 2; /* Grauwerte */`
`47 PCXHeader[69] = 0;`
`48 PCXHeader[70] = 0; /* Auflösung des Bildschirms */`
`49 PCXHeader[71] = 0;`
`50 PCXHeader[72] = 0;`
`51 PCXHeader[73] = 0;`
`52`
`53 /* unbenutzte Bytes auf 0 Setzen */`
`54 for(i=74; i<128; i++) PCXHeader[i] = 0;`
`55`
`56 /* Farbtabelle (Graukeil) */`
`57 for(i=0; i<256; i++)`
`58 for(j=0; j<3; j++) LUT[i*3+j] = i;`
`59`
`60 write(PCX_fd, PCXHeader, 128);`
`61`
`62 /* RLC berechnen */`
`63 for(z=0; z<=Z_Index; z++)`
`64 {`
`65 Index = (long)z * (long)bildspalten;`
`66 s = 0;`
`67 while(s<=S_Index)`
`68 {`
`69 Pixel = bild[Index+s]; /* erstes Vorkommen der Farbe */`
`70 s++;`
`71 Anzahl=1;`
`72 while((s<=S_Index) && (Pixel==bild[Index+s]) && (Anzahl<63))`
`73 {`
`74 Anzahl++;`
`75 s++;`
`76 }`
`77 /* Anzahl>1 oder Farbe>=192, dann RLC durchführen */`
`78 if((Anzahl>1) || (Pixel>=192))`
`79 {`
`80 Anzahl = 0xC0 + Anzahl; /* RLC-Kennung */`
`81 write(PCX_fd, Anzahl, 1);`
`82 write(PCX_fd, Pixel, 1);`
`83 }`
`84 else`
`85 {`
`86 write(PCX_fd, Pixel, 1); /* einmaliges Pixel mit Grauwert<192 */`
`87`
`88 }`
`89 }`
`90 }`
`91 /* LUT Farbpalette schreiben */`
`92 Pixel=12; /* Kennzeichen f. Bild-Ende */`
`93 write(PCX_fd, Pixel, 1);`
`94 write(PCX_fd, LUT, 768); /* Farbpalette */`
`95 close(PCX_fd);`
`96 }`
Algorithmus zum Laden
`1 unsigned char *bild; /* Adresse des Bildspeichers (Array) */`
`2 unsigned int bildzeilen;`
`3 unsigned int bildspalten;`
`4`
`5 Load_PCX()`
`6 {`
`7 unsigned char PCXHeader[128];`
`8 unsigned char Pixel;`
`9 unsigned char Anzahl;`
`10 int PCX_fd; /* File-Descriptor */`
`11 int i, j, z, s;`
`12 long Index;`
`13`
`14 ... Datei PCX_fd zum lesen öffnen ...`
`15`
`16 /* PCX-Header einlesen und auf Version 5 testen */`
`17 read(PCX_fd, PCXHeader, 128);`
`18 if((PCXHeader[0]!=10) || (PCXHeader[1]!=5) ||`
`19 (PCXHeader[2]!=1) || (PCXHeader[3]!=8))`
`20 {`
`21 ShowError("Falsches Datenformat.");`
`22 return();`
`23 }`
`24`
`25 /* Bildmaße berechnen */`
`26 bildspalten = 256*(unsigned int)PCXHeader[9]+(unsigned int)PCXHeader[8]+1;`
`27 bildzeilen = 256*(unsigned int)PCXHeader[11]+(unsigned int)PCXHeader[10]+1;`
`28`
`29 /* RLC einlesen */`
`30 Index = 0;`
`31 z = 0;`
`32 while(z<bildzeilen)`
`33 {`
`34 s = 0;`
`35 j = 0;`
`36 while(s<bildspalten)`
`37 {`
`38 read(PCX_fd, Pixel, 1);`
`39 if(Pixel>192)`
`40 {`
`41 Anzahl = Pixel-192;`
`42 read(PCX_fd, Pixel, 1);`
`43 for(i=0; i<Anzahl; i++)`
`44 {`
`45 bild[Index++] = Pixel;`
`46 s++;`
`47 }`
`48 }`
`49 else`
`50 {`
`51 bild[Index++] = Pixel;`
`52 s++;`
`53 }`
`54 }`
`55 z++;`
`56 }`
`57 close(PCX_fd);`
`58`
`59 /* Einlesen der Farbpalette entfällt, da Grauwerte vorausgesetzt */`
`60 }`