ST-Ecke: WEITERBILDUNG - DEGAS komprimiert- und IFF-Format

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.

DEGAS ELITE und das IFF-Format

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.

Förmlich

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:

  1. Byte = 80, !!!
  2. 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

Noch mehr Information...

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,dO
            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



Links

Copyright-Bestimmungen: siehe Über diese Seite
Classic Computer Magazines
[ Join Now | Ring Hub | Random | << Prev | Next >> ]