Nachdem wir uns in der letzten Ausgabe mit dem allgemeinen Aufbau eines Bildes und den einfachen (ungepackten) Bildformaten auseinandergesetzt haben, wollen wir weiter dieses Thema erforschen und die Geheimnisse der Packformate ergrĂŒnden. ZunĂ€chst betrachten wir allgemein, wie es ĂŒberhaupt möglich ist, Daten auf ein Minimum zu reduzieren, ohne daĂ tatsĂ€chlich Information verloren geht. Im weiteren Verlauf werden wir uns mit dem ersten Bildformat beschĂ€ftigen, das die Daten gepackt also komprimiert abspeichert- dem IFF-Format. Das Interessante des IFF-Formats ist, daĂ es nicht nur fĂŒr Bilddaten, sondern auch fĂŒr diverse andere Daten wie zum Beispiel Text verwendet werden kann.
ZunĂ€chst möchte ich mich dafĂŒr entschuldigen, daĂ in der letzten Ausgabe ein paar Zeilen im C-Listing gefehlt haben. Wahrscheinlich hat man beim Setzen das Wort Packen zu wörtlich genommen. Wir liefern die Zeilen in Listing 3 hiermit nach.
Weniger ist mehr
ZunĂ€chst wird sich der brave BĂŒrger (oder auch Programmierer ) fragen, wie es ĂŒberhaupt möglich sein kann, in weniger Daten genau die gleiche Information unterzubringen wie im Originaldatensatz - geht dabei nicht unausweichlich Information verloren ? Um so verblĂŒffender ist es, wenn relativ einfach gehaltenene Bilder sich nicht nur auf die HĂ€lfte, sondern vielleicht von 32000 Bytes auf knapp 1000 Bytes ohne jeglichen Informationsverlust verkĂŒrzen lassen. Zauberei? Wirklich nicht! Schauen wir uns dieses Wunder an einem alltĂ€glichen Beispiel an: Stellen Sie sich vor, Sie wĂŒrden ins Theater gehen, eine lange Schlange Menschen am Eingang sehen und wollten einem Bekannten nach selbigen Theaterbesuch ĂŒber diese Menschenkette erzĂ€hlen. Sicherlich kĂ€men Sie nicht auf die Idee, die Menschenkette auf folgende Art zu beschreiben: Vorne stand ein Mann, dann kam noch ein Mann und noch ein Mann, dann folgte eine Frau mit Kind und noch eine Frau mit Kind und so weiter. Vielmehr faĂt man auch im normalen Sprachgebrauch mehrere gleiche Dinge durch AufzĂ€hlung zusammen. Sie werden mir recht geben, daĂ die Beschreibung â Ich sah 3 MĂ€nner und 2 Frauen mit Kind in einer Schlangeâ eleganter klingt. Obwohl die Beschreibung kĂŒrzer ist, ist der Informationsgehalt der gleiche! Was spricht nun dagegen, Ă€hnliches auch auf die Beschreibung von Bilddaten anzuwenden? (Auch wenn es wahrscheinlich keinen Ihrer Bekannten interessieren wird, wie Ihre Bilder aussehen.)
Packen wirâs an
Normalerweise stehen in einer (nicht komprimierten) Datei hintereinander alle Bytes so, wie sie nachher auch im Bildschirmspeicher zu finden sind. Dies ist selbst dann der Fall, wenn hundertmal das gleiche Byte vorhanden ist. Viel schöner wĂ€re es doch, wenn folgende Beschreibung möglich wĂ€re: âZuerst kommen 25 unzusammenhĂ€ngende Bytes, dann hundertmal das Byte X, dann zehnmal das Byte Y, dann wieder zwölf Bytes ohne Zusammenhang...â. Sie bemerken, daĂ wir keine Information beim Abspeichem der Daten verlieren, wenn wir spĂ€ter beim Laden die Datei wieder âdechiffrierenâ. Die Kunst des Komprimierens ist es nun, ein Verfahren zu entwickeln, das möglichst viele wiederkehrende Muster erkennt und verschlĂŒsseln kann. Dabei ist die einfachste Art, den Bildspeicher in den aufeinanderfolgenden Bytes nach Bytefolgen abzusuchen. Bei Bildern, in denen aber hĂ€ufig senkrechte Linien Vorkommen, hilft das nicht. Man muĂ ein solches Bild senkrecht, nicht waagrecht durchsuchen. Auf diese Weise kann man sich die tollsten Suchalgorithmen ĂŒberlegen, um ein Bild zu packen.
Bei digitalisierten Bildern sollte dieser Algorithmus besonders ausgefuchst sein, weil hier kaum gleiche aufeinanderfolgende Bytes zu finden sind. Hier geht man meistens noch eine Ebene tiefer, indem man sogar Bitmuster zu finden versucht. Langsam wird auch deutlich, warum das Packen von (speziell digitalisierten ) Bildern teilweise so lange dauert, daĂ man âeine kleine Kaffeepauseâ entlegen kann - das Suchen von (Bit-)Mustem dauert relativ lange. Bereitet man ein solches Bild spĂ€ter wieder auf, kennt man aufgrund der Kodierung das Muster und kann die Daten im Bruchteil einer Sekunde wieder zurĂŒckgewinnen.
Die Qual der Wahl
Nun gibt es inzwischen auf dem ATARI ST eine Vielzahl von Zeichen- und Malprogrammen (gerade erreichte die Redaktion das 100undxte), und fast jedes Programm hat seine eigene Speicherroutine, will sagen sein eigenes Speicherformat. Unsere kleine Reihe soll dazu beitragen, daĂ Sie wenigstens die bekanntesten Formate, die Sie mit Ihrem gekauften Programm erstellen, auch in Ihren eigenen Programmen verwenden können. Bitte haben Sie VerstĂ€ndnis, daĂ wir nur den Auspacker des entsprechenden Datenformats und die Information ĂŒber das Format veröffentlichen. Das hat zwei GrĂŒnde: Erstens ist die eigentliche Komprimierroutine meist viel komplizierter als die Entkomprimierung, und zweitens steckt im Packer viel mehr Softwaregrips, was auf deutsch heiĂt, daĂ kaum ein Programmierer bereit ist, die Zustimmung zur Veröffentlichung des Packers zu geben.
Beim IFF-Format handelt es sich um ein Format, daĂ ursprĂŒnglich von der Firma Electronic Arts entwickelt und auf dem AMIGA (ATARI-Liebhaber werden mir die ErwĂ€hnung dieses Namens verzeihen) in Deluxe Paint zum ersten Mal eingesetzt wurde. SpĂ€ter wurde es auf dem ST in Tom Hudsons DEGAS ELITE in abgewandelter Form verwendet und ist auch auf vielen anderen Rechner verbreitet. Der Vorteil dieses Packformates ist, daĂ es so allgemein gehalten ist, daĂ man damit nicht nur Bilder, sondern beliebige andere Daten gepackt speichern kann - allerdings werden wir nur das Packformat fĂŒr Bilder erklĂ€ren.
Klumpen
Betrachtet man das IFF-Format, erkennt man, daĂ es aus einer Reihe von Blöcken besteht, die in IFF-Sprache unter dem aussagekrĂ€ftigen Namen CHUNK bekannt sind - fĂŒr alle, die dem AngelsĂ€chsischen nicht so zugetan sind: CHUNK bedeutet soviel wie groĂer Brocken oder Klumpen. Wie schon zu vermuten ist, gibt es Chunks unterschiedlicher Art.
ZunĂ€chst beginnt eine IFF-Datei mit einem sogenannten FORM-Chunk, der die Art der Datei angibt, denn, oben erwĂ€hnte ich es schon, man kann nicht nur Bild - sondern auch Text- oder Musikdaten mit IFF verschlĂŒsseln. Dieser FORM-Chunk hat die sagenhafte LĂ€nge von nur 8 Bytes, in denen die KĂŒrzel 8SVX (8-Bit-Sample-Voice), SMUS (Simple Music Score), FTXT (formatierter Text) oder -was uns am meisten interessiert - ILBM (Interleaved Bit Map ) stehen können. Jedem Name des Chunks folgt die LĂ€nge desselben, wobei die ID, also der Namen selbst, nicht miteinbezogen wird. Ein Wort noch zu dem KĂŒrzel ILBM: Wie Sie wahrscheinlich aus unserer letzten Folge noch wissen, wird ein Bild aus mehreren Planes aufgebaut, die auch noch wortweise (ATARI) oder zeilenweise (IFF-Format) ineinander verschachtelt sind, was man Interleaved-Bit-Planes (oder Map) nennt. Erkennt unser Entpacker am Form-Chunk, der ein ILBM enthĂ€lt, daĂ es sich um eine Grafik-Datei handelt, âweiĂâ er, daĂ auf einen FORM-Chunk ein BMHD-CHUNK folgt.
FORM-Chunk | BMHD-Chunk | CMAP-Chunk | CRNG-Chunk | BODY-Chunk |
GesamtlÀnge - 8 Byte (L) IFF-Art-Grafik (4B) |
Chunk-LÀnge(L) Breite (W) Höhe (W) X-Position (W) Y-Position (W)
Bitplane-Anzahl (B) Maskierung (B) Komprimierung(B) Null (B) Transparenzfarbe (W) X-Aspekt (B) Y-Aspekt (B) Seitenbreite (W) Seitenhöhe (W) |
Chunk-LĂ€nge (L) Farbe 0 Rot (B) Farbe 0 GrĂŒn (B) Farbe 0 Blau (B) Farbe 1 Rot (B) Farbe 1 GrĂŒn (B) Farbe 1 Blau (B) Farbe 2 Rot (B) Farbe 2 GrĂŒn (B) Farbe 2 Blau (B) Farbe 3 Rot (B) Farbe 3 GrĂŒn (B) Farbe 3 Blau (B) |
Chunk-LĂ€nge (L) Null (W) Geschwindigkeit (W) aktiviert (W) untere Farbe (B) obere Farbe (B) |
Chunk-LĂ€nge (L) Bilddaten (B) |
Tabelle 1: Die unterschiedlichen Grafik-Chunks (B=Byte, W=Wort, L=Langwort)
Der Kopf der ganzen Sache
An AbkĂŒrzungen wurde nicht gespart: BMHD bedeutet Bit-Map-Header. Er enthĂ€lt allgemeine Informationen eines Bildes. Schaut man sich diesen Chunk an (Tabelle 1), erkennt man einige interessante Eigenschaften: ZunĂ€chst bietet die Angabe der Koordinaten sowie der Breite und Höhe die Möglichkeit, Teile oder sogar ĂbergröĂen von Bildern abzuspeichern, die spĂ€ter entsprechend verarbeitet werden. Weiter ist im BMHD-Chunk die Anzahl der Planes enthalten, bei der darauf hingewiesen werden soll, daĂ der AMIGA bis zu fĂŒnf, der ST aber nur vier Planes enthĂ€lt, so daĂ unwillkĂŒrlich bei der Darstellung Information verloren geht.
Maskenball
Ein weiterer Eintrag gibt die Art der Maskierung an. Dabei wird zwischen 0 (keiner Maskierung), 1 (in Bilddaten vorhandene Maske), 2 (Transparenz) und 3 (Lassotechnik) unterschieden. Eine Maske ist eine Bilddatenmenge, durch die man kennzeichnen kann, an welcher Stelle ein eventuell vorhandener Hintergrund durchscheinen (ein gelöschtes Bit) oder vom neuen Bild verdeckt (ein gesetztes Bit) sein soll. Bei transparenter Maskierung wird an der Stelle im Bild, wo sich eine (an anderer Stelle) definierte Transparenzfarbe befindet, der Hintergrund des schon vorhandenen Bildes durchgeblendet. Die Verarbeitung der Lassotechnik ist relativ aufwendig zu programmieren. Die Vorgehensweise: Die Daten der Lassomaske kennzeichnen eine sich irgendwann wieder schlieĂende, im Bild befindliche Kurve. Der Bildbereich im Innern dieser FlĂ€che wird als transparent verarbeitet. Weiterhin sind im BMHD die Transparenzfarbe sowie das Flag vorhanden, das angibt, ob die Datei komprimiert (1) oder ungepackt (0) vorliegt. Zwei weitere EintrĂ€ge kennzeichnen das VerhĂ€ltnis zwischen Breite und Höhe eines Bildes. Vorhanden ist auch eine Information, wie groĂ der Arbeitsbildschirm ist, wobei diese Werte auch kleiner sein können als das eigentliche Bild - uns ist allerdings bisher kein Programm bekannt, daĂ dies unterstĂŒtzt. Die genaue Reihenfolge und den Speicherplatzbedarf entnehmen Sie bitte Tabelle 1.
# CHUNK Bemerkung
FORM:
: kennzeichnet die IFF-Datei in ihrer Art und LĂ€nge, ILBM entspricht Grafikart
BMHD:
: enthÀlt allgemeine Informationen der Grafik wie zum Beispiel Auflösung, Anzahl der Planes, Komprimierung etc.
CMAP:
: enthĂ€lt die Werte fĂŒr die Farbpalette. Es können bis zu 8 Bits pro RGB-Wert Vorkommen, wobei der ATARI ST 3 Bits und der AMIGA 4 Bits unterstĂŒtzt.
CRNG:
enthĂ€lt Daten ĂŒber Farbrotation und Shading, der CRNG ist meist vierfach vorhanden.
BODY:
: eigentlicher Grafikdatenteil
Bilder sind zeilenweise und planeweise abgespeichert, meist innerhalb der Zeile komprimiert
Tabelle 2: Der Aufbau einer IFF-Grafik-Datei
DEGAS komprimiert:
Screenformat:
nach IFF-Format komprimierte Bilddaten,
ab Byte 35 .. xxx,
32 Bytes Farbpalette nicht nach IFF-Standard Bytes 3 .. 34,
32 Bytes Farbanimationsdaten, hinter den komprimierten Bilddaten
Auflösung:
LOW ( * PCI ), MED ( *.PC2 ), HIGH ( *.PC3 ),
DateilÀnge:
variabel, abhÀngig vom Bildinhalt, da Packformat
Kennung:
- Byte = 80, !!!
- Byte = Auflösung (0=LOW, 1=MED, 2=HIGH ).
Bemerkung:
IFF-Standard nur bei der Komprimierung eingehalten, die Definitionschunks des IFF sind nicht vorhanden.
AMIGA-IFF:
Screenformat:
nach IFF - Standard aufgebautes Datenfile,
Bilddaten durch âBMHDâ- und âBODYâ-chunk gekennzeichnet,
Farbpalette durch âBMHDâ- und âCMAPâ-chunk gekennzeichnet.
Farbanimationsdaten nach IFF-Format evtl, enthalten
Auflösung: frei wÀhlbar, im BMHD eingetragen
DateilÀnge: variabel, abhÀngig vom Bildinhalt
Kennung: FORM-Chunk am Dateianfang.
Dateinamen nicht festgelegt, Vorschlag (*.IFF)
Tabelle 3: Zusammenstellung der Bildformate
bietet der CMAP-Chunk, der die Farbpalette beschreibt. FĂŒr jede Farbe stehen drei Bytes zur VerfĂŒgung, die jeweils die Rot-, GrĂŒn- und Blauwerte der Farbe angeben. Wichtig hierbei ist folgendes: Der ATARI ST besitzt vier und der AMIGA bis zu fĂŒnf Planes. Möchte man Bilder ausnutzen, die fĂŒnf Planes enthalten, muĂ man aufwendige Farbumrechnungen durchfĂŒhren, um eine Farbpalette zu erstellen, die mit 16 Farben fast so gute Ergebnisse wie mit 32 liefert. Ein weiteres Problem ergibt sich dadurch, daĂ die RGB-Werte beim AMIGA 32 Stufen annehmen können, wĂ€hrend der ATARI nur 8 Stufen besitzt. Man hat die Werte des AMIGAs durch 2 zu teilen, andernfalls findet man eine völlig falsche Farbgebung vor!
Es geht rund
Bevor wir endlich zu den eigentlichen Grafikdaten kommen, fehlt noch eine zusĂ€tzliche Information, die sich mit Farbrotationen beschĂ€ftigt. Als Farbrotation bezeichnet man das Weitergeben einer Farbinformation von einem Register in das andere. Einige unter Ihnen werden vielleicht die Animation von ATARI kennen, in der ein Adler ĂŒber den Bildschirm fliegt, unter dem die Brandung bewegt zu sehen ist. Die Bewegung der Brandung ist nur durch Rotieren der einzelnen Farben erzeugt! Der Chunk, der uns Auskunft ĂŒber die Farbrolleigenschaften des Bildes gibt, hat den unaussprechlichen Namen CRNG, was ausfĂŒhrlich Color Range (Farbbereich) heiĂt. AuĂer der Möglichkeit die Farbrotation ein- und auszuschalten, kann man hier die Geschwindigkeit und die Anfangs- und Endfarbe angeben, zwischen denen die Inhalte gerollt werden sollen. Bei einer Geschwindigkeit von 2 hoch 14 also 16384, werden sechzig Rotationen pro Sekunde durchgefĂŒhrt. Daraus folgt, daĂ eine Rotation pro Sekunde einem Vert von 273 und ein Wert von 1 einer Rotation in etwa viereinhalb Minuten spricht.
Endlich eingepackt
Nach soviel Vorinformation folgen, lange erwartet, die Grafikdaten. Wie nicht anders zu vermuten, hat auch dieser Block einen Namen - BODY. Der BODY (Körper) enthĂ€lt die Daten eines Bildes in gepackter oder ungepackter Form, je nachdem, ob der Kompressionseintrag gesetzt ist oder nicht. Nun sind wir schon daran gewöhnt, daĂ die einzelnes Planes beim ATARI nicht hintereinander abgelegt, sondern ineinander als Worte verschachtelt sind. Bei IFF sind die Planes auch nicht vollstĂ€ndig hintereinander, sondern immer bildzeilen weise hintereinander gespeichert (gefolgt von einer eventuell vorhanden Maskenzeile). Dadurch hat man die Möglichkeit, Teile eines Bildes zu laden, ohne wie wild durch die Datei springen zu mĂŒssen. Innerhalb dieser Zeilen geschieht nun die Komprimierung, die (leider) nicht besonders effektiv ist. Der Packer sucht in einer Zeile nach n gleichen aufeinanderfolgende Bytes. Am Anfang eines Kodierungsteils steht immer ein sogenanntes Befehlsbyte. Liegt der Wert n zwischen 0 und 127, werden die nĂ€chsten n+1 Bytes unverĂ€ndert (praktisch ungepackt) ĂŒbernommen. Ist es ein Wert zwischen -1 und -128, wird das folgende Byte -n+1mal wiederholt in den Speicher geschrieben die Zahl Null wĂ€re sinnlos, da das zweifache Wiederholen zwei Bytes kosten wĂŒrde... Da das oberste Bit einschaltet, ob das folgende Byte, aufgrund des sich aus den unteren sieben Bits ergebenden Wertes, wiederholt werden soll, fĂŒhrt der Wert 128 (âWiederhole nullmal !â) zu keinem Ergebnis.
Unterschiede zu DEGAS ELITE compressed
Wie oben schon angedeutet, unterscheiden sich IFF-Format und Pack-Format von DEGAS-ELITE, haben aber auch etwas gemeinsam, daher werden beide Formate in einer Folge der BILDUNG abgehandelt. Leider stimmen sie nur in der Art der Komprimierung ĂŒberein, so daĂ alle Header fehlen und auch die Farbpalette nicht im IFF-Format abgespeichert ist. Werden wir speziell: Das erste Byte enthĂ€lt eine Null, die wir auch besser so lassen, da sie wie viele, auch im IFF-Format vorhandene, Nullen Platzhalter fĂŒr spĂ€tere Erweiterungen darstellt. Im zweiten Byte findet man die Auflösung kodiert, wobei 0 niedrige, 1 mittlere und 2 hohe Auflösung bedeutet. Die folgenden 32 Bytes enthalten die Farbpalette, wie schon angesprochen, nicht als IFF-Format, sondern als ganz normale Palette des ST. Hinter der Farbpalette folgen die nach IFF komprimierten Daten, deren Anzahl der Zeilen sich aus der Auflösung ergibt. Wie wir es schon von der normalen DEGAS-Datei kennen, folgen am Ende noch 32 Bytes Farbanimationsdaten.
ResĂŒmee
Wir haben nun die ersten beiden Pack-Formate kennengelernt und dabei festgestellt, daĂ das IFF-Format hervorragend dazu geeignet ist, Daten unter Rechnern auszutauschen, zumal es auch noch andere Chunks fĂŒr andere Datenarten gibt, allerdings ist der Komprimieralgorithmus relativ mĂ€Ăig. Es wird immer nur eine Zeile untersucht und auĂerdem das Bild nur byteweise und waagrecht ĂŒberprĂŒft, was bei vielen Bildern zu kaum einem Erfolg fĂŒhrt. Leider hat sich DEGAS-ELITE, obwohl es die gleiche Komprimierung wie IFF benutzt, nicht an den IFF-Standard gehalten, obgleich das Programm die Möglichkeit bietet, IFF-Bilderzu laden.
Ausblick
In der nĂ€chsten Bildung werden wir uns mit einem weiteren Format beschĂ€ftigen: dem GEM-VDI- oder auch Image-Format. Viele unserer Leser haben danach gefragt, so daĂ wir auch dieses Pack-Format in unsere Bildungsreihe hineinnehmen. Packen wirâs also das nĂ€chste Mal an...
SH
Bild 1: Anfang einer IFF-Bilddatei
Bild 2: Schema des Anfangs einer IFF-Bilddatei
* modul AUSPACK.S
*
* Assemblermodul zum Auspacken von
* verschiedenen gepackten Bildformaten.
*
*
* Originalauszug aus dem Grafikpaket IMAGIC
* von APPLICATION SYSTEMS /// HEIDELBERG.
*
* Version 1.0
*
* verfasst am 8-8-1988 von Jörg DrĂŒcker
* Copyright (c) 1988 by IMAGIC GRAFIK.
* *
* DEGAS ELITE BILDER *
* auspacken *
* *
xdef DEC_ELIT
DEC_ELIT: bsr GET_PAR * Parameter holen
cmpi.b #$80,(a0) * header byte "80' testen
bne ERR_DONE
cmp.b 1(a0),d0 * Bildauflösung testen
bne ERR_DONE
lea 34(a0),a0 * Farbinformation ĂŒberspringen
* *
* Register fĂŒr eine Vollbild *
* IFF-Dekomprimierung einrichten *
* *
INIT_LOW: suba.l a2,a2 * compressed lines
move.w #200,d6 * 200 scanlines
moveq #6,d5 * plane byte offset (ATARI scheme)
moveq #4,d4 * plane count
moveq #40,d3 * line byte count per plane
moveq #40,d7
tst.w d0 * Niedere Auflösung?
beq.s ELIT_DECOMP * Ja...
INIT_MED: moveq #2,d5 * plane byte offset (ATARI scheme)
moveq #2,d4 * plane count
moveq #80, d3 * line byte count per plane
moveq #80,d7
subq.w #1,d0 * Mittlere Auflösung?
beq.s ELIT_DECOMP * Ja...
INIT_HIGH: moveq #0,d5 * plane byte offset (ATARI scheme)
moveq #1,d4 * plane count
add.w d6,d6 * 400 scanlines
ELIT_DECOMP: bsr ERASE_PIC
bsr IFF_DECOMP * IFF-format decompression
bra ALL_DONE
* *
* AMIGA IFF BILDER *
* auspacken *
* *
xdef DEC_IFF
DEC_IFF: bsr GET_PAR * Parameter holen
bsr ERASE_PIC * Bild löschen
* *
* Register fĂŒr eine Standard *
* IFF-Dekomprimierung einrichten *
* *
* *
* **EinschrÀnkungen:** *
* Anzahl Farbplanes nur 1/2/4 *
* *
* Keine Maskentechniken *
* zugelassen *
* *
* NOTE: data Starts direct with 'BMHD' (Bitmap-Header) chunk ...
cmpi.1 #'BMHD',(a0) * Bitmap-Header chunk found?
bne ERR_DONE * no, abort
movem.w 8(a0),d1-d2 * picture width & height in pixel
move.w d2,d6 * number of scanlines
addq.w #7, d1
lsr.w #3,d1 * plane bytes per line (pix+7) div 8
moveq #0,d3
move.b 16(a0),d3 * number of planes
* NOTE: only 1/2/4 planes can be handled.
move.w d3,d2 * d2 nur zum Testen (1/2/4)
subq.w #1,d2
beq.s PLANES_OK
subq.w #1,d2
beq.s PLANES_OK
subq.w #2,d2
bne ERR_DONE * otherwise abort
PLANES_OK: move.b 17(a0),d2
* masking technique, 0 = mskNone,
* 1 = mskHasMask, 2 = mskHasTranspcolor,
* 3 = mskLasso
cmp.b #1, d2
beq ERR_DONE * cannot handle mask in data.
suba.1 a2,a2 * "compressed"
tst.b 18(a0) * compression flag, 1=compressed
bne.s COMPRESSED
move.w d1,a2 * number of bytes per line (uncomp)
COMPRESSED: move.w d3,d4 * number of planes
move.w d1,d3 * number of plane bytes per line
subq.w #1,d0 * res = low?
bmi.s RES_LOW
beq.s RES_MED
cmpi.w #1,d4 * Anzahl planes testen
bne ERR_DONE
moveq #0,d5 * plane byte offset HIGH = 0
moveq #80, d7 * screen bytes per line
cmpi.w #400,d6 * max. 400 scanlines
ble.s GET_BODY
move.w #400, d6
bra.s GET_BODY
RES MED: cmpi.w #2,d4 * Anzahl planes testen
bne ERR_DONE
moveq #2,d5 * plane byte offset MED = 2
moveq #80,d7
cmpi.w #200,d6 * max. 200 scanlines
ble.s GET_BODY
move.w #200,d6
bra.s GET_BODY
RES_LOW: cmpi.w #4,d4 * Anzahl planes testen
bne ERR_DONE
moveq #6,d5 * plane byte offset LOW = 6
moveq #40,d7
cmpi.w #200, d6 * max. 200 scanlines
ble.s GET_BODY
move.w #200,d6
GET_BODY: move.1 4(a0),d0 * chunk length
addq.1 #1,d0
bclr #0,d0 * even length
lea 8(a0,d0.1),a0 * skip chunk
cmpi.1 #'BODY',(a0) * body chunk found?
bne.s GET_BODY
addq.l #8,a0 * Start of body chunk
bsr IFF_DECOMP * IFF-format decompression
bra ALL_DONE
* *
* AMIGA IFF BILDER *
* Farbpalette umrechnen *
* *
xdef COL_IFF
COL_IFF: movea.l 4(sp),a1 * COLOR data pointer
movea.l 8(sp),a0 * IFF DATA - Start of BMHD chunk
* *
* Standard IFF Farbdaten holen *
* *
* **EinschrÀnkungen:** *
* ---------------- *
* Anzahl Farbregister == 16 *
* *
* NOTE: data Starts direct with 'BMHD' (Bitmap-Header) chunk ...
moveq #0,d0
cmpi.l #'BMHD',(a0) * Bitmap-Header chunk found?
bne.s RETURN_COL * no, abort
GET_COLR: move.1 4(a0),d0 * chunk length
addq.l #1,d0
bclr #0,d0 * even length
lea 8 (a0, d0.1),a0 * skip chunk
cmpi.l #'CMAP',(a0) * CMAP chunk found?
bne.s GET_COLR
addq.l #8,a0 * Start of color chunk
moveq #15, d6 * 16 color registers
moveq #4,d4 * #4
MAKE_COLR: moveq #0,d0 * color register
moveq #2,d1 * 3 values
MAKE_1: lsl.w d4,d0 * next nibble
move.b (a0)+,d0 * IFF RGB value ( upper nibble )
lsr.b #1,d0 * convert IFF RGB range 0..15
* to ATARI RGB range 0..7
dbra d1, MAKE_1
lsr.w d4,d0 * position d0 to: "0rgb"
move.w d0,(a1)+ * save color value
dbra d6,MAKE_COLR
moveq #1,d0 * return "OK"
RETURN_COL: movea.1 (sp)+,a0
addq.l #8,sp * cleanup stack
jmp (a0) * rts
* *
* GEM VDI BILDER *
* auspacken *
* *
xdef DEC_VDI
DEC_VDI: bsr GET_PAR * Parameter holen
bsr ERASE_PIC * erase picture
* vorlĂ€ufig nicht verfĂŒgbar, wird spĂ€ter erweitert:
bra ERR_DONE * Fehlermeldung
* *
* IMAGIC BILDER *
* auspacken *
* *
xdef DEC_IMAG
DEC_IMAG: bsr GET_PAR * Parameter holen
bsr ERASE_PIC * erase picture
* vorlĂ€ufig nicht verfĂŒgbar, wird spĂ€ter erweitert:
bra ERR_DONE * Fehlermeldung
* *
* Fehlerausgang *
* Booleanwert FALSE zurĂŒckgeben *
* *
ERR_DONE: moveq #0,d0 * "error"
bra.s RETURN
* *
* Normalausgang *
* Booleanwert TRUE zurĂŒckgeben *
* *
ALL_DONE: moveq #1,d0 * "no error"
RETURN: movem.l (sp)+,d7/a6 * restore d7 / a6
movea.1 (sp)+,a0
lea 12(sp),sp * cleanup stack
jmp (a0) * rts
* *
* Hilfsfunktion *
* Parameter vom Stack holen *
* Register korrekt setzen *
* *
GET_PAR: lea 8(sp),a4 * Zeiger auf Parameter
move.w (a4)+,d0 * RESOLUTION
move.w (a4)+,d6 * PICLEN
movea.1 (a4)+,a1 * PICTURE
movea.1 (a4)+,a0 * COMPRESSED DATA
move.1 (sp)+,a5 * Return Adresse
movem.l d7/a6,-(sp) * Register retten
jmp (a5)
* *
* Hilfsfunktion *
* Bildinhalt löschen *
* *
* a1 = picture
* d6 = picturelen (32000 or more, but always a multiple of 64 bytes !)
ERASE_PIC: movem.l d0-d7/al-a2,- (sp)
moveq #0,d0
moveq #0,d1
moveq #0,d2
moveq #0,d3
moveq #0,d4
moveq #0,d5
moveq #0,d7
move.l d0,a2 * "0" ins a2
adda.w d6,a1 * upper border
lsr.w #6,d6 * picturelen div 64
subq.w #1,d6 * ZĂ€hler -1
clrpic: movem.l d0-d5/d7/a2,-(a1) * 32 bytes
movem.l d0-d5/d7/a2,-(a1) * 32 bytes
dbra d6,clrpic
movem.l (sp)+,d0-d7/a1-a2
rts
*=========================================*
* *
* Routinen zur Dekomprimierung *
* *
*=========================================*
* *
* Standard IFF Dekomprimierung *
* a0 = compr. source
* a1 = pic destination
* a2 = uncompressed linelength in bytes /0 = compressed lines
*
* d3 = max destination line byte count per plane
* d4 = number of planes
* d5 = byte offset from plane-to-plane (ATARI scheme)
* d6 = total number of destination lines (ysize)
* d7 = number of destination plane bytes per line (80/80/40)
IFF_DECOMP: move.1 d4,a4
subq.l #1,a4 * plane count -1
move.1 d3,a3 * line byte count
bclr #0,d3 * only even byte counts
move.w d3,d0
neg.w d0
muls d4,d0 * -(byte count) x (plane count)+2
addq.1 #2,d0
movea.1 d0,a5 * next plane offset
move.w d7,d2 * destination bytes per line
mulu d4,d7 * source bytes per line (even)
sub.l d5,d7
subq.l #2,d7 * (bytes_per_line) - (byte offset)-2
movea.1 d7,a6 * next line offset
subq.w #1,d6 * "dbra" ylines counter
move.w a4,d4 * "dbra" planes counter
clr.w d3 * plane byte counter
moveq #0,d7 * destination offset (Start = 0)
MAIN_LOOP: cmp.w a3,d3 * one plane written?
bpl.s NEXT_PLANE
move.w a2,d0 * packed data?
bne.s COPY_LOOP * take line-length as byte count
* for uncompressed data
moveq #0,d0
move.b (a0)+,d0 * compression byte
bmi.s MULTIPLE * negative: multiple byte count
* positive: single bytes following
COPY_LOOP: addq.w #1,d3
cmp.w d3, d2 * check line clipping
bmi.s COPY_CLIP
move.b (a0),0(a1,d7.w) * copy <d0> bytes
COPY_CLIP: addq.1 #1,a0
* position in destination screen according to the
* ATARIs special colorplane encoding scheme:
addq.w #1,d7
btst #0,d7 * second byte written?
bne.s COPY_1
add.w d5,d7 * add plane byte offset
COPY_1: dbra d0,COPY_LOOP
bra.s MAIN_LOOP * all singles written
MULTIPLE: neg.b d0 * multiple counter
bmi.s MAIN_LOOP * Byte was $80: "no Operation byte"
move.b (a0)+,d1 * multiple byte
MULT_LOOP: addq.w #1, d3
cmp.w d3, d2
bmi.s MULT_CLIP
move.b d1,0(a1,d7.w) * write <d0> multiple bytes
MULT_CLIP:
* position in destination screen according to the
* ATARIs special colorplane encoding scheme:
addq.w # 1, d7
btst #0,d7 * second byte written?
bne.s MULT_1
add.w d5,d7 * add plane byte offset
MULT_1: dbra d0,MULT_LOOP
bra.s MAIN_LOOP * all multiples written
NEXT_PLANE: clr.w d3 * clear line byte counter
bclr #0,d7 * re-position from even position
add.w a5,d7 * re-position on next plane
dbra d4,MAIN_LOOP * plane counter
move.w a4,d4 * re-load counter
add.w a6,d7 * position on next line
dbra d6,MAIN_LOOP
END_IFF: rts * all lines done, end
*=====================================*
end
Listing 1: Benötigte Assemblerroutinen
{ Erweiterung zu BILDEINLESEN aus ST-Computer 8/9 88 ST-Ecke }
{ Diese Zeilen sind allein nicht lauffÀhig ! ! }
program BILDEINLESEN ( input, output ) ;
{
Demonstrationsprogramm zum Einlesen von
verschiedenen Bildformaten.
->
Erweiterung zu BILDEINLESEN aus ST-Computer 8/9 88 ST-Ecke
Version 1.0
verfasst am 7-6-1988 von Jörg DrĂŒcker
erweitert am 8-8-1988 neue Bildformate.
Copyright (c) 1988 by IMAGIC GRAFIK.
}
{...}
PICTURE_TYPES = ( P_DEGAS, { Degas unkomprimiert }
P_DOODLE, { Doodle / Screenformat }
P_NEO, { Neochrome Format }
P_ART, { ART Director }
P_DEGCOM, { Degas komprimiert }
P_IFF, { AMIGA IFF }
P_GEMVDI, { GEM VDI Format }
P_IMAGIC, { IMAGIC komprimiert }
P_UNDEF ); { unbekanntes Format }
{...}
{ globale Variablen }
AUFLOESUNG : integer;
{ Systemfunktionen:
}
function getrez : integer;
{ Aktuell eingestellte Bildschirmauf lösung holen }
xbios ( 4 );
{...}
{ Assemblerroutinen zur EntschlĂŒsselung der gepackten Bildformate:
}
function DEC_ELIT ( COMP, PICTURE : DATA_POINTER;
PICSIZE, RESOLUTION : integer ): boolean;
externa1;
function DEC_IFF ( COMP, PICTURE : DATA_POINTER;
PICSIZE, RESOLUTION : integer ): boolean;
external;
function DEC_VDI ( COMP, PICTURE : DATA_POINTER;
PICSIZE, RESOLUTION : integer ): boolean;
external;
function DEC_IMAG ( COMP, PICTURE : DATA_POINTER;
PICSIZE, RESOLUTION : integer ): boolean;
external;
{ Assemblerroutinen zur EntschlĂŒsselung der der Farbpalette:
}
function COL_IFF ( IFF_DATA, COLOR_DATA : DATA_POINTER): boolean;
external;
{ folgende Routine wird insgesamt ausgetauscht }
procedure HOLE_BILDDATEN ( READBUF, DEST : DATA_POINTER;
PIC_TYPE : PICTURE_TYPES;
RESOLUTION : integer );
{ Hole Bildinhalt, je nach Bildformat }
var OK : boolean;
begin
OK := true; { O.K. fĂŒr alle nicht komprimierten Formate )
case PIC_TYPE of
{...}
P_DEGCOM : OK := DEC_ELIT ( READBUF,
DEST,
PICTURELEN,
RESOLUTION );
P_IFF : OK := DEC_IFF ( ADDR_OFFSET
( READBUF, 12 )
{ FORM chunk ĂŒberspringen }
DEST,
PICTURELEN,
RESOLUTION );
P_GEMVDI : OK := DEC_VDI ( READBUF,
DEST,
PICTURELEN,
RESOLUTION ) ;
P_IMAGIC : OK := DEC_IMAG ( READBUF,
DEST,
PICTURELEN,
RESOLUTION )
end; { case }
if not OK then begin
writeln ( chr ( 27 ), 'E', chr ( 7 ) ) ;
{ Bildschirm löschen, Warnton }
writeln ( 'Fehler beim EntschlĂŒsseln des Bildformats !' ) ;
writeln;
writeln ( 'Weiter mit <RETURN>' )
end
end; { HOLE_BILDDATEN }
procedure HOLE_FARBEN ( READBUF : DATA_POINTER;
FARBEN : COLOUR_PTR;
PIC_TYPE : PICTURE_TYPES );
{ Hole Farbpalette, je nach Bildformat }
{...}
OK : boolean;
begin
{...}
OK := true; { O.K. fĂŒr alle nicht komprimierten Formate }
{...}
case PIC_TYPE of
P_DEGAS,
P_DEGCOM : TRANSFER ( ADDR_OFFSET
(READBUF,2 ),
COL.DATA,
32 ) ;
{...}
P_DOODLE,
P_GEMVDI : SYSPALET ( COL.CPTR );
{ aktuelle Palette holen }
P_IFF : OK := COL_IFF ( ADDR_OFFSET
( READBUF, 12 ) ,
{ FORM chunk ĂŒberspringen }
COL.DATA );
P_IMAGIC : TRANSFER ( ADDR_OFFSET
( READBUF,6 ),
COL.DATA,
32 )
end; { case }
if not OK then
{ im Falle eines Fehlers: Systempalette einstellen ! }
SYSPALET ( COL.CPTR ) ;
end; { HOLE_FARBEN }
{ Hauptprogramm:
}
begin
AUFLOESUNG := getrez; { Bildschirmauflösung ? }
loop
{...}
repeat
writeln;
writeln ('Bildtyp eingeben:' );
writeln (' A = DEGAS Normal' );
writeln (' B = DOODLE' );
writeln (' C = NEO Chrome' );
writeln (' D = ART Director' );
writeln (' E = DEGAS komprimiert' );
writeln (' F = AMIGA IFF' );
writeln (' G = GEM VDI' );
writeln ( ' H = IMAGIC komprimiert' ) ;
write ( '> ' );
readln ( BILDTYP ) ;
case BILDTYP of
'A','a' : PIC_TYPE :=P_DEGAS;
'B','b' : PIC_TYPE :=P_DOODLE;
'C','c' : PIC_TYPE :=P_NEO;
'D','d' : PIC_TYPE :=P_ART;
'E','e' : PIC_TYPE :=P_DEGCOM;
'F','f' : PIC_TYPE :=P_IFF;
'G','g' : PIC_TYPE :=P_GEMVDI;
'H','h' : PIC_TYPE :=P_IMAGIC;
otherwise : PIC_TYPE := P_UNDEF
{...}
HOLE_BILDDATEN ( LESEBUFFER.DATA,
BILDSCHIRM, PIC_TYPE,
AUFLOESUNG );
end.
Listing 2: Erweiterungslisting in PASCAL
case P_DOODLE:
syspalet(farben); /* aktuelle Palette holen */
break;
case P_NEO:
transfer(readbuf+4,farben,32L);
break;
case P_ART:
transfer(readbuf+32000L,farben,32L);
break;
}
}
Listing 3: Fehlende Zeilen aus Listing 3 der letzten ST-Ecke