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.
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.)
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.
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.
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)
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.
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.
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
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:
Bemerkung:
IFF-Standard nur bei der Komprimierung eingehalten, die Definitionschunks des IFF sind nicht vorhanden.
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!
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.
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.
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.
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.
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
* 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